Index: head/Mk/Uses/gecko.mk =================================================================== --- head/Mk/Uses/gecko.mk +++ head/Mk/Uses/gecko.mk @@ -50,8 +50,8 @@ .elif ${gecko_ARGS:Mthunderbird} -_GECKO_DEFAULT_VERSION= 52 -_GECKO_VERSIONS= 52 +_GECKO_DEFAULT_VERSION= 60 +_GECKO_VERSIONS= 60 _GECKO_TYPE= thunderbird .if exists(${LOCALBASE}/bin/thunderbird) @@ -60,7 +60,7 @@ .endif # Dependence lines for different Thunderbird versions -52_DEPENDS= ${LOCALBASE}/lib/thunderbird/thunderbird:mail/thunderbird +60_DEPENDS= ${LOCALBASE}/lib/thunderbird/thunderbird:mail/thunderbird .else IGNORE= Unknown type of gecko dependency you may specify either firefox, seamonkey or thunderbird Index: head/mail/thunderbird-i18n/Makefile =================================================================== --- head/mail/thunderbird-i18n/Makefile +++ head/mail/thunderbird-i18n/Makefile @@ -2,10 +2,10 @@ # $FreeBSD$ PORTNAME= thunderbird-i18n -PORTVERSION= 52.9.1 +PORTVERSION= 60.0 CATEGORIES= mail news net-im MASTER_SITES= MOZILLA/${PORTNAME:S|-i18n||}/releases/${DISTVERSION}/linux-i686/xpi \ - MOZILLA/${PORTNAME:S|-i18n||}/candidates/${DISTVERSION}-candidates/build3/linux-i686/xpi + MOZILLA/${PORTNAME:S|-i18n||}/candidates/${DISTVERSION}-candidates/build2/linux-i686/xpi PKGNAMEPREFIX= DISTFILES= ${THUNDERBIRD_I18N_:S/$/.xpi/} DIST_SUBDIR= xpi/${DISTNAME} Index: head/mail/thunderbird-i18n/Makefile.lang =================================================================== --- head/mail/thunderbird-i18n/Makefile.lang +++ head/mail/thunderbird-i18n/Makefile.lang @@ -1,10 +1,10 @@ # $FreeBSD$ -THUNDERBIRD_I18N_ALL_= ar ast be bg bn-BD br ca cs cy da de dsb el en-GB \ - en-US es-AR es-ES et eu fi fr fy-NL ga-IE gd gl he \ - hr hsb hu hy-AM id is it ja kab ko lt nb-NO nl nn-NO \ - pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE \ - ta-LK tr uk vi zh-CN zh-TW +THUNDERBIRD_I18N_ALL_= ar ast be bg br ca cs cy da de dsb el en-GB en-US \ + es-AR es-ES et eu fi fr fy-NL ga-IE gd gl he hr hsb \ + hu hy-AM id is it ja kab kk ko lt ms nb-NO nl nn-NO \ + pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE tr uk vi \ + zh-CN zh-TW .if defined(THUNDERBIRD_I18N_ALL) || defined(PACKAGE_BUILDING) || target(package) THUNDERBIRD_I18N= ${THUNDERBIRD_I18N_ALL_} @@ -114,11 +114,17 @@ .if ${PORT_OPTIONS:MLANG_KAB} THUNDERBIRD_I18N+= kab .endif +.if ${PORT_OPTIONS:MLANG_KK} +FIREFOX_I18N+= kk +.endif .if ${PORT_OPTIONS:MLANG_KO} THUNDERBIRD_I18N+= ko .endif .if ${PORT_OPTIONS:MLANG_LT} THUNDERBIRD_I18N+= lt +.endif +.if ${PORT_OPTIONS:MLANG_MS} +FIREFOX_I18N+= ms .endif .if ${PORT_OPTIONS:MLANG_NB} THUNDERBIRD_I18N+= nb-NO Index: head/mail/thunderbird-i18n/Makefile.option =================================================================== --- head/mail/thunderbird-i18n/Makefile.option +++ head/mail/thunderbird-i18n/Makefile.option @@ -36,8 +36,10 @@ LANG_IT \ LANG_JA \ LANG_KAB \ + LANG_KK \ LANG_KO \ LANG_LT \ + LANG_MS \ LANG_NB \ LANG_NL \ LANG_NN \ Index: head/mail/thunderbird-i18n/distinfo =================================================================== --- head/mail/thunderbird-i18n/distinfo +++ head/mail/thunderbird-i18n/distinfo @@ -1,119 +1,117 @@ -TIMESTAMP = 1530448777 -SHA256 (xpi/thunderbird-i18n-52.9.1/ar.xpi) = 4e126d51c735e53f4f5fb4bd09094802639b08d42c71b8513398d164946ebba0 -SIZE (xpi/thunderbird-i18n-52.9.1/ar.xpi) = 604235 -SHA256 (xpi/thunderbird-i18n-52.9.1/ast.xpi) = e74a25ef050bcaf60d086a4460e4ee0c5d24ca9e3298bf7ee510238a5767fa5e -SIZE (xpi/thunderbird-i18n-52.9.1/ast.xpi) = 541173 -SHA256 (xpi/thunderbird-i18n-52.9.1/be.xpi) = eacf02c785ad21de6a8fa41dd7d96d0971b3057e427fc8f42425cf504ead2fc7 -SIZE (xpi/thunderbird-i18n-52.9.1/be.xpi) = 570931 -SHA256 (xpi/thunderbird-i18n-52.9.1/bg.xpi) = 78094a216d300c803a9ffe1053485fc3520c5ac8a7a6880c164661d26446b772 -SIZE (xpi/thunderbird-i18n-52.9.1/bg.xpi) = 634897 -SHA256 (xpi/thunderbird-i18n-52.9.1/bn-BD.xpi) = e26b5dd3a73377568cc988f74ba103de1582b4327f7364d80ccf36bed75ce47e -SIZE (xpi/thunderbird-i18n-52.9.1/bn-BD.xpi) = 676900 -SHA256 (xpi/thunderbird-i18n-52.9.1/br.xpi) = 039135e876e59e111322cb295706c44ec6de8db21ca8a3cd1d4df7b8e97c2561 -SIZE (xpi/thunderbird-i18n-52.9.1/br.xpi) = 559380 -SHA256 (xpi/thunderbird-i18n-52.9.1/ca.xpi) = bd7a18290ee33e07a9b13b5ac56bae0e05e9e6eadf67bbc846e6fb9942ffecbe -SIZE (xpi/thunderbird-i18n-52.9.1/ca.xpi) = 569910 -SHA256 (xpi/thunderbird-i18n-52.9.1/cs.xpi) = 60bb32710a8afda584ca1c2566037f2489e190aaa15b9401eae0c3a6ea87f178 -SIZE (xpi/thunderbird-i18n-52.9.1/cs.xpi) = 579149 -SHA256 (xpi/thunderbird-i18n-52.9.1/cy.xpi) = 9c6f813b8bae310427729e6f87dd7541e9f0e5012684fcca79df839deffca49d -SIZE (xpi/thunderbird-i18n-52.9.1/cy.xpi) = 554858 -SHA256 (xpi/thunderbird-i18n-52.9.1/da.xpi) = 412186224359be3848e12769d4c7564535b2442a785a509cfa95596ebe253c1c -SIZE (xpi/thunderbird-i18n-52.9.1/da.xpi) = 543334 -SHA256 (xpi/thunderbird-i18n-52.9.1/de.xpi) = cd8d6b41e53b747e6731b6678ed78100ffeccac2d5b2548f6a817fc7178020cc -SIZE (xpi/thunderbird-i18n-52.9.1/de.xpi) = 555743 -SHA256 (xpi/thunderbird-i18n-52.9.1/dsb.xpi) = 208a209a8a930a7c21c0080a2446ce68cc2b69b92debbed9bb11263b6f8599a5 -SIZE (xpi/thunderbird-i18n-52.9.1/dsb.xpi) = 584582 -SHA256 (xpi/thunderbird-i18n-52.9.1/el.xpi) = 4547a29d281178642ab8e44c3a931256e9ab0f54c2b9e1d070c185f1bc4cd43b -SIZE (xpi/thunderbird-i18n-52.9.1/el.xpi) = 662964 -SHA256 (xpi/thunderbird-i18n-52.9.1/en-GB.xpi) = 08fe22418c2f7eb1c905ba8fad946b1a225d8a22f137fcb84eb1c54db8f9d3d7 -SIZE (xpi/thunderbird-i18n-52.9.1/en-GB.xpi) = 531233 -SHA256 (xpi/thunderbird-i18n-52.9.1/en-US.xpi) = 8fa5e585b1b12a4ba7a839b8f2f6289620e47820fd0b3e5f62b9275788181893 -SIZE (xpi/thunderbird-i18n-52.9.1/en-US.xpi) = 529123 -SHA256 (xpi/thunderbird-i18n-52.9.1/es-AR.xpi) = 02b6864746d5610ca0d4ca0cb6e66a3ec754646d35edd0f5c6865a00bd37150c -SIZE (xpi/thunderbird-i18n-52.9.1/es-AR.xpi) = 565995 -SHA256 (xpi/thunderbird-i18n-52.9.1/es-ES.xpi) = 5a40466e88e3f0c0698281554d7ad2578c9447c04165cf8a2c88ca06c173753f -SIZE (xpi/thunderbird-i18n-52.9.1/es-ES.xpi) = 445464 -SHA256 (xpi/thunderbird-i18n-52.9.1/et.xpi) = eceffb5d80f109c0ee015d6818b7e9cf07f67bb56db455ec0bd3076c5879f316 -SIZE (xpi/thunderbird-i18n-52.9.1/et.xpi) = 551661 -SHA256 (xpi/thunderbird-i18n-52.9.1/eu.xpi) = 035a45221dccb53e4c4d0a23c67cc5130ef277307d4bc122db1fb4bd9b3726f6 -SIZE (xpi/thunderbird-i18n-52.9.1/eu.xpi) = 555536 -SHA256 (xpi/thunderbird-i18n-52.9.1/fi.xpi) = a8bcef75989b924a29f2433c30d00afbf6ffc20bcdffd4eadc2c78508958d205 -SIZE (xpi/thunderbird-i18n-52.9.1/fi.xpi) = 550669 -SHA256 (xpi/thunderbird-i18n-52.9.1/fr.xpi) = 5e7d1db861d8035b8e2706ce3ca519a1a607e2fc73f4b7221e81b3cb3d233a66 -SIZE (xpi/thunderbird-i18n-52.9.1/fr.xpi) = 577560 -SHA256 (xpi/thunderbird-i18n-52.9.1/fy-NL.xpi) = 2f2d0bf3be9c38feb49013330686da2da73efe88a0607ecf7f2169d4eaf83df6 -SIZE (xpi/thunderbird-i18n-52.9.1/fy-NL.xpi) = 563632 -SHA256 (xpi/thunderbird-i18n-52.9.1/ga-IE.xpi) = 6dbff8d17549b1e01b96ce29c277c71918f2c2eff0767a96f421174aa40c60f8 -SIZE (xpi/thunderbird-i18n-52.9.1/ga-IE.xpi) = 583556 -SHA256 (xpi/thunderbird-i18n-52.9.1/gd.xpi) = d3fc9cdc6260d4d293160fb3cbd5f984ffe84cbf3d29b1b94e4f7ae5ab375c75 -SIZE (xpi/thunderbird-i18n-52.9.1/gd.xpi) = 574065 -SHA256 (xpi/thunderbird-i18n-52.9.1/gl.xpi) = fc0405811ff57de111ef67f55dd0c4d28e3c5ec82b0f3f37a51e9288f6287e41 -SIZE (xpi/thunderbird-i18n-52.9.1/gl.xpi) = 575150 -SHA256 (xpi/thunderbird-i18n-52.9.1/he.xpi) = e8f8d4aa44c9103e078e7642d8d62acde8a16c0dc8813812cc18953496d9119b -SIZE (xpi/thunderbird-i18n-52.9.1/he.xpi) = 592566 -SHA256 (xpi/thunderbird-i18n-52.9.1/hr.xpi) = 351f9c8be31e8316220efe707a08e6604fa24303b00d520c0988e426e942d542 -SIZE (xpi/thunderbird-i18n-52.9.1/hr.xpi) = 564778 -SHA256 (xpi/thunderbird-i18n-52.9.1/hsb.xpi) = 25868d4c144fc1cbe6570a81557a116ade400e8e5a9d991c4f6430b5097ad968 -SIZE (xpi/thunderbird-i18n-52.9.1/hsb.xpi) = 582241 -SHA256 (xpi/thunderbird-i18n-52.9.1/hu.xpi) = 3673d396f6f2c8532b44c2876b256b6370c299859a874e66a1a497cc7c82bf12 -SIZE (xpi/thunderbird-i18n-52.9.1/hu.xpi) = 586446 -SHA256 (xpi/thunderbird-i18n-52.9.1/hy-AM.xpi) = 79b83cc198b302e9ad899285d2e22556755f4312fbd03b48a21aefe426adc3db -SIZE (xpi/thunderbird-i18n-52.9.1/hy-AM.xpi) = 629879 -SHA256 (xpi/thunderbird-i18n-52.9.1/id.xpi) = 146b1cad707c7e675ac794e5e3b850c225d256c8b7eb209784f37acc8dabc1d1 -SIZE (xpi/thunderbird-i18n-52.9.1/id.xpi) = 546526 -SHA256 (xpi/thunderbird-i18n-52.9.1/is.xpi) = ee72e9914c047f6dde2a26cadc942362eba9cd9102075632d6c7f1efb55b4e47 -SIZE (xpi/thunderbird-i18n-52.9.1/is.xpi) = 555712 -SHA256 (xpi/thunderbird-i18n-52.9.1/it.xpi) = b09bf17cf725f0179a441103fff9d6ada44bb27129d403210ebb09e774c6a3c5 -SIZE (xpi/thunderbird-i18n-52.9.1/it.xpi) = 455407 -SHA256 (xpi/thunderbird-i18n-52.9.1/ja.xpi) = 89c67cd4782ecfee3355cc296d0bb21d15e8ffbfa635a8ec787829c332d9f7f9 -SIZE (xpi/thunderbird-i18n-52.9.1/ja.xpi) = 630052 -SHA256 (xpi/thunderbird-i18n-52.9.1/kab.xpi) = 9a65c237a28db2b0005cf1ac3a7f8560ce397686b9649b76eee846382b27c9ad -SIZE (xpi/thunderbird-i18n-52.9.1/kab.xpi) = 568691 -SHA256 (xpi/thunderbird-i18n-52.9.1/ko.xpi) = 116379d62a97355ce898f8c05a01c8d38499408347f41c0ce68c668abd07d1a6 -SIZE (xpi/thunderbird-i18n-52.9.1/ko.xpi) = 595517 -SHA256 (xpi/thunderbird-i18n-52.9.1/lt.xpi) = 8c4a14c6f670744233eb6baaf93e9296f931a0f37b52b5d26978866311c19fb7 -SIZE (xpi/thunderbird-i18n-52.9.1/lt.xpi) = 580598 -SHA256 (xpi/thunderbird-i18n-52.9.1/nb-NO.xpi) = ac281bcccb47b0547649bf2bb0d469cea9972eabbf46fdea3a389b211cd664a7 -SIZE (xpi/thunderbird-i18n-52.9.1/nb-NO.xpi) = 551103 -SHA256 (xpi/thunderbird-i18n-52.9.1/nl.xpi) = beb67cafd89969eae55e76a754df378d89e123f96b9bd3afeb6727287e8c0a3d -SIZE (xpi/thunderbird-i18n-52.9.1/nl.xpi) = 557956 -SHA256 (xpi/thunderbird-i18n-52.9.1/nn-NO.xpi) = 63f11a440531a673a23918c307e7a69a94e9e65ba29d363320736bf25866658b -SIZE (xpi/thunderbird-i18n-52.9.1/nn-NO.xpi) = 551891 -SHA256 (xpi/thunderbird-i18n-52.9.1/pa-IN.xpi) = fda332c982bb6d78d3c081648e52fe6ec40a5791bbf8bbf561d74ea2488c339b -SIZE (xpi/thunderbird-i18n-52.9.1/pa-IN.xpi) = 646568 -SHA256 (xpi/thunderbird-i18n-52.9.1/pl.xpi) = 2fcd160bacebd77843e6a85eb20e83513870062c7526aa172f270d842668afb0 -SIZE (xpi/thunderbird-i18n-52.9.1/pl.xpi) = 469901 -SHA256 (xpi/thunderbird-i18n-52.9.1/pt-BR.xpi) = 8f3e9f83dec81527a4048d3d57bc28ce8e11b097474daaccb2f60d32503f08f4 -SIZE (xpi/thunderbird-i18n-52.9.1/pt-BR.xpi) = 558223 -SHA256 (xpi/thunderbird-i18n-52.9.1/pt-PT.xpi) = 096826fdbeaaebed3886db5fa5025179b7f8abcd80599d68e02f6872ac66c465 -SIZE (xpi/thunderbird-i18n-52.9.1/pt-PT.xpi) = 565623 -SHA256 (xpi/thunderbird-i18n-52.9.1/rm.xpi) = e2923b46e2f1e1e3af4bc8f41effde5395132404a23160e4a0413fc312e20859 -SIZE (xpi/thunderbird-i18n-52.9.1/rm.xpi) = 557605 -SHA256 (xpi/thunderbird-i18n-52.9.1/ro.xpi) = 85da875bd3b785f5043b8734042302061436103df943a91671a49abfcb823ab4 -SIZE (xpi/thunderbird-i18n-52.9.1/ro.xpi) = 570529 -SHA256 (xpi/thunderbird-i18n-52.9.1/ru.xpi) = 20102503cd4a8cda03be12396d1bdfb90623bd54f35c4013fa56723352f74e22 -SIZE (xpi/thunderbird-i18n-52.9.1/ru.xpi) = 530670 -SHA256 (xpi/thunderbird-i18n-52.9.1/si.xpi) = d66402d1f8b9d16513be5c620348a3703521020e732857647c4b35aeff820d07 -SIZE (xpi/thunderbird-i18n-52.9.1/si.xpi) = 649010 -SHA256 (xpi/thunderbird-i18n-52.9.1/sk.xpi) = 5ac8d7c810be9797ade84805bf85b7aea215419671d9b77be54413e08f26c018 -SIZE (xpi/thunderbird-i18n-52.9.1/sk.xpi) = 583882 -SHA256 (xpi/thunderbird-i18n-52.9.1/sl.xpi) = 2c705087f4ac765292a6bac0099be39091a6293e52538112587065e1b1ad794e -SIZE (xpi/thunderbird-i18n-52.9.1/sl.xpi) = 562834 -SHA256 (xpi/thunderbird-i18n-52.9.1/sq.xpi) = 862ed58bb0c13633ef0de4577fc738e84d6cc50ed94aa3d617672a88acb4550e -SIZE (xpi/thunderbird-i18n-52.9.1/sq.xpi) = 570617 -SHA256 (xpi/thunderbird-i18n-52.9.1/sr.xpi) = 4b4d89bfe976681755b45371d0a4bd6f25a4877f2b694434a142d9251a369992 -SIZE (xpi/thunderbird-i18n-52.9.1/sr.xpi) = 609019 -SHA256 (xpi/thunderbird-i18n-52.9.1/sv-SE.xpi) = ede899e7554be6b60fb093c31803f5964e33f33bafde79ab95fa31231097c884 -SIZE (xpi/thunderbird-i18n-52.9.1/sv-SE.xpi) = 565777 -SHA256 (xpi/thunderbird-i18n-52.9.1/ta-LK.xpi) = dcade6aca9be34468a93277903971e248198776f03ebc2ebbe21a3002ca829d0 -SIZE (xpi/thunderbird-i18n-52.9.1/ta-LK.xpi) = 675039 -SHA256 (xpi/thunderbird-i18n-52.9.1/tr.xpi) = 91d130b3f07b38720f887a323fe49393452fc88b6830540f0cc76682209dbf38 -SIZE (xpi/thunderbird-i18n-52.9.1/tr.xpi) = 569926 -SHA256 (xpi/thunderbird-i18n-52.9.1/uk.xpi) = da6176a05dc819a5fa7376b5f62a84846e01365b78495a576a2d738edc8b8577 -SIZE (xpi/thunderbird-i18n-52.9.1/uk.xpi) = 652854 -SHA256 (xpi/thunderbird-i18n-52.9.1/vi.xpi) = e25dfd63f38748c46b7c8d9bf87497e06cfee8de4ace89b9fe13e73a68e818ec -SIZE (xpi/thunderbird-i18n-52.9.1/vi.xpi) = 637163 -SHA256 (xpi/thunderbird-i18n-52.9.1/zh-CN.xpi) = ad691e808b25f34c105b80f61b6a2cd8dbbb2230eca741c126954ae4330eac0b -SIZE (xpi/thunderbird-i18n-52.9.1/zh-CN.xpi) = 593611 -SHA256 (xpi/thunderbird-i18n-52.9.1/zh-TW.xpi) = 19e45d672c06afe44b1103b94199094374098671b29d84043fe0f4d096b7090f -SIZE (xpi/thunderbird-i18n-52.9.1/zh-TW.xpi) = 595728 +TIMESTAMP = 1531797876 +SHA256 (xpi/thunderbird-i18n-60.0/ar.xpi) = 11a5a009815ded56f5f370c6823ae6813643d367fea58b83e4d9d768abf53928 +SIZE (xpi/thunderbird-i18n-60.0/ar.xpi) = 627180 +SHA256 (xpi/thunderbird-i18n-60.0/ast.xpi) = db52ff2e8457437861bd56bc228ce201a96c707dac84cefbfa1f8bd8313ea1ea +SIZE (xpi/thunderbird-i18n-60.0/ast.xpi) = 560865 +SHA256 (xpi/thunderbird-i18n-60.0/be.xpi) = b031e89f37bac13d887190f9232110a6caa276df3a4b109af3bc141f377ee1cd +SIZE (xpi/thunderbird-i18n-60.0/be.xpi) = 659078 +SHA256 (xpi/thunderbird-i18n-60.0/bg.xpi) = 4dd3a055173d3148e25c62e8774227b56e9be4442bb810e2048904910a1e35b1 +SIZE (xpi/thunderbird-i18n-60.0/bg.xpi) = 665511 +SHA256 (xpi/thunderbird-i18n-60.0/br.xpi) = 9268af2b4ed1e6b2eddcfac28c8278ff95e94477e3838c8a8c72de6ec6f64aaf +SIZE (xpi/thunderbird-i18n-60.0/br.xpi) = 581591 +SHA256 (xpi/thunderbird-i18n-60.0/ca.xpi) = 8f51b603ba22c31b617b2f527d66a022e272f0ea49b2a8d14a20e2abfe8944ba +SIZE (xpi/thunderbird-i18n-60.0/ca.xpi) = 591970 +SHA256 (xpi/thunderbird-i18n-60.0/cs.xpi) = e6e9018fdc39e039052621d4b7c02b8eb6d01d7f09dd64be49849596f8b862fa +SIZE (xpi/thunderbird-i18n-60.0/cs.xpi) = 611200 +SHA256 (xpi/thunderbird-i18n-60.0/cy.xpi) = f46bfec05cace5f29429537c5b458de2cfcc122fc1e07f58c7256f8a76f197c9 +SIZE (xpi/thunderbird-i18n-60.0/cy.xpi) = 582231 +SHA256 (xpi/thunderbird-i18n-60.0/da.xpi) = 52b197fa5ba03a6abe53a3bb5c03be097d7c0887cf5efc4d786fe36e2bc00f17 +SIZE (xpi/thunderbird-i18n-60.0/da.xpi) = 570805 +SHA256 (xpi/thunderbird-i18n-60.0/de.xpi) = 052747d6d22f1672c1b774caa1507bc6917e1717f222f317b2e30646d804ef73 +SIZE (xpi/thunderbird-i18n-60.0/de.xpi) = 582574 +SHA256 (xpi/thunderbird-i18n-60.0/dsb.xpi) = a285f0fb22bf60a398fc95dff1506db089853096e331669725fd96dc4fb97268 +SIZE (xpi/thunderbird-i18n-60.0/dsb.xpi) = 613758 +SHA256 (xpi/thunderbird-i18n-60.0/el.xpi) = cd1a18d845903651c28c160ce6fe61015dfb61704fd15fe9b798bc4555b209ee +SIZE (xpi/thunderbird-i18n-60.0/el.xpi) = 691054 +SHA256 (xpi/thunderbird-i18n-60.0/en-GB.xpi) = 7babe1d2f58c629c82cc148fb87bda0511fd0641edbab5f100fa3d0d2b869190 +SIZE (xpi/thunderbird-i18n-60.0/en-GB.xpi) = 550353 +SHA256 (xpi/thunderbird-i18n-60.0/en-US.xpi) = 75f7f04720089eaf8b4d4128f0d0256d3dda0dca0adea31a3e30f0fab91af6fd +SIZE (xpi/thunderbird-i18n-60.0/en-US.xpi) = 546973 +SHA256 (xpi/thunderbird-i18n-60.0/es-AR.xpi) = 27ff067330acd3178f1664c7bf28967f3652058ef6b92d4972bdaf8ec3ca2dfc +SIZE (xpi/thunderbird-i18n-60.0/es-AR.xpi) = 595047 +SHA256 (xpi/thunderbird-i18n-60.0/es-ES.xpi) = e4150ea5bb481763fbaddb20937fd2c5a4c8d93045e254e0bc158c048f472f00 +SIZE (xpi/thunderbird-i18n-60.0/es-ES.xpi) = 492209 +SHA256 (xpi/thunderbird-i18n-60.0/et.xpi) = e69290484c09608544f99ceec19e8f4f3fd990340ce1923ef155e04371a1e87a +SIZE (xpi/thunderbird-i18n-60.0/et.xpi) = 570865 +SHA256 (xpi/thunderbird-i18n-60.0/eu.xpi) = a4b3f71ad8b00b2ce70b3f814b270f907d756ae0b08f7df95abc13ed59737280 +SIZE (xpi/thunderbird-i18n-60.0/eu.xpi) = 577578 +SHA256 (xpi/thunderbird-i18n-60.0/fi.xpi) = 948e6310b2942a02b3f12a0c2f4eb49053bead5ef8f1ee1f7df4103507690bde +SIZE (xpi/thunderbird-i18n-60.0/fi.xpi) = 575754 +SHA256 (xpi/thunderbird-i18n-60.0/fr.xpi) = 014483ec4815f512b3803485970602334ad5eb891a80a591dbb7d8190b672e75 +SIZE (xpi/thunderbird-i18n-60.0/fr.xpi) = 608465 +SHA256 (xpi/thunderbird-i18n-60.0/fy-NL.xpi) = dac2e1777b2b0a03749f8190a6a391cf992cba23c66258394415265531316caa +SIZE (xpi/thunderbird-i18n-60.0/fy-NL.xpi) = 590032 +SHA256 (xpi/thunderbird-i18n-60.0/ga-IE.xpi) = 7d11d42e417ede0577d0251101953d758d05bc98eabf1bbd89976f2047f68a0f +SIZE (xpi/thunderbird-i18n-60.0/ga-IE.xpi) = 603505 +SHA256 (xpi/thunderbird-i18n-60.0/gd.xpi) = c960d26a6fc01d56a94337997597d91a7a3e84c1861549f671a6fabbe7a65ee0 +SIZE (xpi/thunderbird-i18n-60.0/gd.xpi) = 599260 +SHA256 (xpi/thunderbird-i18n-60.0/gl.xpi) = 0742dfa7ccfc2c6692267a0969205a851369487f215032a65ce70e379190321e +SIZE (xpi/thunderbird-i18n-60.0/gl.xpi) = 576546 +SHA256 (xpi/thunderbird-i18n-60.0/he.xpi) = e65a5de1e4f64043c485fa77eda437fd70eeee0cb1c9614718773471380dc54f +SIZE (xpi/thunderbird-i18n-60.0/he.xpi) = 618364 +SHA256 (xpi/thunderbird-i18n-60.0/hr.xpi) = eecd63a13d982292fd9ceb95fffecc2dd5f92906b5e52cfb228c18c6973fc913 +SIZE (xpi/thunderbird-i18n-60.0/hr.xpi) = 583458 +SHA256 (xpi/thunderbird-i18n-60.0/hsb.xpi) = 4918bda163309f2fc826bcbb07117cc1aeb8723087a866c248f4cd382220cee4 +SIZE (xpi/thunderbird-i18n-60.0/hsb.xpi) = 611322 +SHA256 (xpi/thunderbird-i18n-60.0/hu.xpi) = d7f634f1c60fd7f150948af204abad8264ab6426135424547f7c991b14732f16 +SIZE (xpi/thunderbird-i18n-60.0/hu.xpi) = 615344 +SHA256 (xpi/thunderbird-i18n-60.0/hy-AM.xpi) = c56d11c6daf8cf90c172a61de470d6e44a27472fde68c9861c80d6942a788426 +SIZE (xpi/thunderbird-i18n-60.0/hy-AM.xpi) = 649712 +SHA256 (xpi/thunderbird-i18n-60.0/id.xpi) = f7596c4f7f4621186f0dc7a71d257c42d1c4693f5ab2277bc659910890269dba +SIZE (xpi/thunderbird-i18n-60.0/id.xpi) = 568858 +SHA256 (xpi/thunderbird-i18n-60.0/is.xpi) = e0708976b463aa0b84a85eef8e438ecd55591109a32892dda05c938c4722b8a3 +SIZE (xpi/thunderbird-i18n-60.0/is.xpi) = 579046 +SHA256 (xpi/thunderbird-i18n-60.0/it.xpi) = f3010291be6eddff1294bd7e4d44078b3ccc8e016edee1f80d24dd5587613009 +SIZE (xpi/thunderbird-i18n-60.0/it.xpi) = 477499 +SHA256 (xpi/thunderbird-i18n-60.0/ja.xpi) = af99f62dacd07f49e57f2ff4df8c82c18081f1003717c319e194576558eee2af +SIZE (xpi/thunderbird-i18n-60.0/ja.xpi) = 653343 +SHA256 (xpi/thunderbird-i18n-60.0/kab.xpi) = c72b1e3c56b498477cc337ffefb63cc8182f30c5eb4da2f2baca8c72e2f313b7 +SIZE (xpi/thunderbird-i18n-60.0/kab.xpi) = 595237 +SHA256 (xpi/thunderbird-i18n-60.0/kk.xpi) = a46d3b2afe4c3f20c2fe5eb289174e1779db11810f713550e6fe785ea85ff669 +SIZE (xpi/thunderbird-i18n-60.0/kk.xpi) = 670449 +SHA256 (xpi/thunderbird-i18n-60.0/ko.xpi) = 4f7ae7b83812da014304c4daabbbb2c72975ccec37739a547c2a153eaa4203b5 +SIZE (xpi/thunderbird-i18n-60.0/ko.xpi) = 619729 +SHA256 (xpi/thunderbird-i18n-60.0/lt.xpi) = 32522fff0fd62ddf052ca5ab05527572cdca9a42acfb05e94ed2cb2b9cb2b3f7 +SIZE (xpi/thunderbird-i18n-60.0/lt.xpi) = 605439 +SHA256 (xpi/thunderbird-i18n-60.0/ms.xpi) = c5fd7f9c88108c2223d07da4384d2160775751707ce00d2fdcc6c8cbc8851aed +SIZE (xpi/thunderbird-i18n-60.0/ms.xpi) = 574305 +SHA256 (xpi/thunderbird-i18n-60.0/nb-NO.xpi) = 82cf564e2716bce55c2bf0886b0fcc7e1fed9aa25e4083d8eea7cc1b4325b224 +SIZE (xpi/thunderbird-i18n-60.0/nb-NO.xpi) = 578231 +SHA256 (xpi/thunderbird-i18n-60.0/nl.xpi) = a2964f7ef47133c48d982f97c45dc733ee71aa2bc71d906262ff9487332b906f +SIZE (xpi/thunderbird-i18n-60.0/nl.xpi) = 583912 +SHA256 (xpi/thunderbird-i18n-60.0/nn-NO.xpi) = 192fbcca2d605c3bb3b11a0b17f0e31751a4943ee090ddb9594bcce25a0c3850 +SIZE (xpi/thunderbird-i18n-60.0/nn-NO.xpi) = 577653 +SHA256 (xpi/thunderbird-i18n-60.0/pl.xpi) = e2bb972724d121e533e7691a3a642a8e7aab1642f64249db6a08e5130e9b4f70 +SIZE (xpi/thunderbird-i18n-60.0/pl.xpi) = 480722 +SHA256 (xpi/thunderbird-i18n-60.0/pt-BR.xpi) = 584da94848d776c59f5afa8f35531dd12be0d50afa280d3164929a5dd64054b6 +SIZE (xpi/thunderbird-i18n-60.0/pt-BR.xpi) = 585017 +SHA256 (xpi/thunderbird-i18n-60.0/pt-PT.xpi) = f100de434488b774162e2d03819367e8641de73550d5d36a1f973d4c1fe17897 +SIZE (xpi/thunderbird-i18n-60.0/pt-PT.xpi) = 593184 +SHA256 (xpi/thunderbird-i18n-60.0/rm.xpi) = 4f2b462e2797a253f9e2a8375f8a0806ca6db1e3b3af6df60f963999dcf2a5b2 +SIZE (xpi/thunderbird-i18n-60.0/rm.xpi) = 578382 +SHA256 (xpi/thunderbird-i18n-60.0/ro.xpi) = 516023538a69843ab2968215ffcc8311be8629272e28b529d43f3cc74fe33d3e +SIZE (xpi/thunderbird-i18n-60.0/ro.xpi) = 584307 +SHA256 (xpi/thunderbird-i18n-60.0/ru.xpi) = 5b6c983390dce06895b1d559d289fd93f7341010d6379bd084cf936328fe22b1 +SIZE (xpi/thunderbird-i18n-60.0/ru.xpi) = 694704 +SHA256 (xpi/thunderbird-i18n-60.0/si.xpi) = 7020b781581863538431b6a4816167304ee56f570669f3dffcf440d41656882a +SIZE (xpi/thunderbird-i18n-60.0/si.xpi) = 643790 +SHA256 (xpi/thunderbird-i18n-60.0/sk.xpi) = 2fc32f1c12ac40694809ab3d73fc7335a766c41997fe32ca665cea60077d2a8d +SIZE (xpi/thunderbird-i18n-60.0/sk.xpi) = 612215 +SHA256 (xpi/thunderbird-i18n-60.0/sl.xpi) = 6a511da89df22266b780edefb7c3919967d3c3a2bc826a626315b8a29a8bc3d1 +SIZE (xpi/thunderbird-i18n-60.0/sl.xpi) = 589946 +SHA256 (xpi/thunderbird-i18n-60.0/sq.xpi) = e2c402a9fb6d7962b99d2e895483c92926223ae39da8e925be54b7a4c8741522 +SIZE (xpi/thunderbird-i18n-60.0/sq.xpi) = 593095 +SHA256 (xpi/thunderbird-i18n-60.0/sr.xpi) = b8a6c95950ab75c802b5e83a72c7d669a51ac99169e26c376116e83bdd03b4d0 +SIZE (xpi/thunderbird-i18n-60.0/sr.xpi) = 637720 +SHA256 (xpi/thunderbird-i18n-60.0/sv-SE.xpi) = 0c72b2f40dd151efb9d30b53b8e3d1bfa0931785ff02e0e7ee4ec4498d07e56e +SIZE (xpi/thunderbird-i18n-60.0/sv-SE.xpi) = 594077 +SHA256 (xpi/thunderbird-i18n-60.0/tr.xpi) = 4800a3201bfdfb64ed6ca09c853f2f62bbc202af0fd8faaf601b78a3501bf915 +SIZE (xpi/thunderbird-i18n-60.0/tr.xpi) = 598009 +SHA256 (xpi/thunderbird-i18n-60.0/uk.xpi) = 7725b913e5d34353b9ceda07dc0d5a8a3c3f90fd92fbf1ea6023bf461e2249fc +SIZE (xpi/thunderbird-i18n-60.0/uk.xpi) = 684153 +SHA256 (xpi/thunderbird-i18n-60.0/vi.xpi) = 9996a26429fd1f89173b4c057a316d316a9ec4acf16c2d18665dd35df0d461af +SIZE (xpi/thunderbird-i18n-60.0/vi.xpi) = 638420 +SHA256 (xpi/thunderbird-i18n-60.0/zh-CN.xpi) = 7e1a05b54ff9c998f1c6d32c32f799d47756908a5aca04b7cc151cfe6aab7302 +SIZE (xpi/thunderbird-i18n-60.0/zh-CN.xpi) = 622465 +SHA256 (xpi/thunderbird-i18n-60.0/zh-TW.xpi) = 40a6d68a67cbb6dfcf232ea0f20b8fc8ca4d1c6349329f4a8bd5999a5b48933a +SIZE (xpi/thunderbird-i18n-60.0/zh-TW.xpi) = 626188 Index: head/mail/thunderbird/Makefile =================================================================== --- head/mail/thunderbird/Makefile +++ head/mail/thunderbird/Makefile @@ -2,24 +2,25 @@ # $FreeBSD$ PORTNAME= thunderbird -DISTVERSION= 52.9.1 +DISTVERSION= 60.0 CATEGORIES= mail news net-im ipv6 MASTER_SITES= MOZILLA/${PORTNAME}/releases/${DISTVERSION}/source \ - MOZILLA/${PORTNAME}/candidates/${DISTVERSION}-candidates/build3/source + MOZILLA/${PORTNAME}/candidates/${DISTVERSION}-candidates/build2/source DISTFILES= ${DISTNAME}.source${EXTRACT_SUFX} MAINTAINER= gecko@FreeBSD.org COMMENT= Mozilla Thunderbird is standalone mail and news that stands above -BUILD_DEPENDS= nspr>=4.13.1:devel/nspr \ - nss>=3.28.6:security/nss \ - libevent>=2.0.21_2:devel/libevent \ - harfbuzz>=1.4.1:print/harfbuzz \ - graphite2>=1.3.8:graphics/graphite2 \ - png>=1.6.25:graphics/png \ - libvorbis>=1.3.5,3:audio/libvorbis \ +BUILD_DEPENDS= nspr>=4.19:devel/nspr \ + nss>=3.36.1:security/nss \ + icu>=59.1,1:devel/icu \ + libevent>=2.1.8:devel/libevent \ + harfbuzz>=1.7.6:print/harfbuzz \ + graphite2>=1.3.11:graphics/graphite2 \ + png>=1.6.34:graphics/png \ + libvorbis>=1.3.6,3:audio/libvorbis \ libvpx>=1.5.0:multimedia/libvpx \ - sqlite3>=3.17.0:databases/sqlite3 \ + sqlite3>=3.22.0:databases/sqlite3 \ ${PYTHON_PKGNAMEPREFIX}sqlite3>0:databases/py-sqlite3@${PY_FLAVOR} \ v4l_compat>0:multimedia/v4l_compat \ autoconf-2.13:devel/autoconf213 \ @@ -27,16 +28,14 @@ zip:archivers/zip # soundtouch>=1.9.0:audio/soundtouch \ -LIB_DEPENDS= libv4l2.so:multimedia/libv4l - SSP_UNSAFE= yes USE_GECKO= gecko -USE_MOZILLA= -soundtouch +USE_MOZILLA= -cairo -soundtouch USE_GL= gl USES= tar:xz -MOZ_OPTIONS= --enable-application=mail --enable-official-branding +MOZ_OPTIONS= --enable-application=comm/mail --enable-official-branding MOZ_MK_OPTIONS= MOZ_THUNDERBIRD=1 MAIL_PKG_SHARED=1 MOZ_EXPORT= MOZ_THUNDERBIRD=1 MAIL_PKG_SHARED=1 MOZ_PKGCONFIG_FILES= @@ -47,20 +46,13 @@ SYSTEM_PREFS= ${FAKEDIR}/lib/${PORTNAME}/defaults/pref/${PORTNAME}.js MOZ_PIS_SCRIPTS=moz_pis_S50cleanhome -OPTIONS_DEFINE= LIGHTNING RUST -OPTIONS_SINGLE= TOOLKIT -OPTIONS_SINGLE_TOOLKIT= GTK2 GTK3 -OPTIONS_DEFAULT=BUNDLED_CAIRO CANBERRA GTK3 LIGHTNING +OPTIONS_DEFINE= LIGHTNING +OPTIONS_DEFAULT=CANBERRA LIGHTNING +OPTIONS_EXCLUDE=BUNDLED_CAIRO .include "${.CURDIR}/../../www/firefox/Makefile.options" - -# Inconsistent fallback order (libcubeb vs. audio_device) -SNDIO_PREVENTS= ${OPTIONS_MULTI_AUDIO:NSNDIO} - .include -MOZSRC:= ${WRKSRC}/mozilla - .if ${PORT_OPTIONS:MLIGHTNING} MOZ_OPTIONS+= --enable-calendar .else @@ -73,7 +65,7 @@ post-patch: @${REINPLACE_CMD} -e 's|%%LOCALBASE%%|${LOCALBASE}|g' \ - ${WRKSRC}/mail/app/nsMailApp.cpp + ${WRKSRC}/comm/mail/app/nsMailApp.cpp pre-configure: (cd ${WRKSRC} && ${LOCALBASE}/bin/autoconf-2.13) Index: head/mail/thunderbird/distinfo =================================================================== --- head/mail/thunderbird/distinfo +++ head/mail/thunderbird/distinfo @@ -1,3 +1,3 @@ -TIMESTAMP = 1531166133 -SHA256 (thunderbird-52.9.1.source.tar.xz) = 286fa71504e7184f3a41bcbdebf591bebe8e04dccbad1c93a47c6e72a7125c4d -SIZE (thunderbird-52.9.1.source.tar.xz) = 230475264 +TIMESTAMP = 1531797876 +SHA256 (thunderbird-60.0.source.tar.xz) = b3b939e2195eff4c4fcbd00fc4e539ecd0759b99284ec98935b2f5815ae68c31 +SIZE (thunderbird-60.0.source.tar.xz) = 284235524 Index: head/mail/thunderbird/files/moz_pis_S50cleanhome =================================================================== --- head/mail/thunderbird/files/moz_pis_S50cleanhome +++ head/mail/thunderbird/files/moz_pis_S50cleanhome @@ -0,0 +1,31 @@ +#!/bin/sh +# + +# S50cleanhome +# a script to clean up users' Mozilla home directories to make upgrading +# less painful. + +# We run in our own subshell + +# First, verify protocol +[ "$1" != "start" ] && exit 1 +[ -z "${MOZ_PIS_API}" -o ${MOZ_PIS_API} -ne 2 ] && exit 1 +[ -z "${MOZ_PIS_MOZBINDIR}" -o ! -d "${MOZ_PIS_MOZBINDIR}" ] && exit 1 +[ -z "${HOME}" -o ! -d "${HOME}" ] && exit 1 +[ -z "${MOZ_PIS_USER_DIR}" -o ! -d "${HOME}/${MOZ_PIS_USER_DIR}" ] && exit 1 + +# Try to cleanup ${HOME}/${MOZ_PIS_USER_DIR} + +if [ -f "${HOME}/${MOZ_PIS_USER_DIR}/profiles.ini" ]; then + sed -e '/Path=/! d' -e "s,Path=,${HOME}/${MOZ_PIS_USER_DIR}/," \ + "${HOME}/${MOZ_PIS_USER_DIR}/profiles.ini" \ + | while read dir + do + [ ! -d "${dir}" ] && continue + # Debian does this for new builds + # rm -f "${dir}/XUL.mfasl" + # force a rebuild of compreg.dat and xpti.dat for new installations + [ "${dir}/compreg.dat" -ot "${MOZ_PIS_MOZBINDIR}/components.ini" ] && + rm -f "${dir}/compatibility.ini" "${dir}/XUL.mfasl" + done +fi Index: head/mail/thunderbird/files/patch-addon-search =================================================================== --- head/mail/thunderbird/files/patch-addon-search +++ head/mail/thunderbird/files/patch-addon-search @@ -0,0 +1,59 @@ +https://github.com/mozilla/addons/issues/708 +https://github.com/mozilla/addons-frontend/issues/4610 + +diff --git mail/app/profile/all-thunderbird.js mail/app/profile/all-thunderbird.js +index 75c2c5e435e35..4d8c09c02759b 100644 +--- comm/mail/app/profile/all-thunderbird.js ++++ comm/mail/app/profile/all-thunderbird.js +@@ -166,10 +166,10 @@ pref("extensions.getAddons.maxResults", 15); + pref("extensions.getAddons.get.url", "https://live.thunderbird.net/services.addons/api/v3/addons/search/?guid=%IDS%&lang=%LOCALE%"); + pref("extensions.getAddons.compatOverides.url", "https://live.thunderbird.net/services.addons/api/v3/addons/compat-override/?guid=%IDS%&lang=%LOCALE%"); + pref("extensions.getAddons.link.url", "https://addons.thunderbird.net/%LOCALE%/%APP%/"); +-pref("extensions.getAddons.recommended.url", "https://services.addons.thunderbird.net/%LOCALE%/%APP%/api/%API_VERSION%/list/recommended/all/%MAX_RESULTS%/%OS%/%VERSION%?src=thunderbird"); ++pref("extensions.getAddons.recommended.url", "https://services.addons.thunderbird.net/%LOCALE%/%APP%/api/%API_VERSION%/list/recommended/all/%MAX_RESULTS%/Linux/%VERSION%?src=thunderbird"); + pref("extensions.getAddons.search.browseURL", "https://addons.thunderbird.net/%LOCALE%/%APP%/search/?q=%TERMS%"); +-pref("extensions.getAddons.search.url", "https://services.addons.thunderbird.net/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%?src=thunderbird"); +-pref("extensions.webservice.discoverURL", "https://services.addons.thunderbird.net/%LOCALE%/%APP%/discovery/pane/%VERSION%/%OS%"); ++pref("extensions.getAddons.search.url", "https://services.addons.thunderbird.net/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/Linux/%VERSION%/%COMPATIBILITY_MODE%?src=thunderbird"); ++pref("extensions.webservice.discoverURL", "https://services.addons.thunderbird.net/%LOCALE%/%APP%/discovery/pane/%VERSION%/Linux"); + pref("extensions.getAddons.themes.browseURL", "https://addons.thunderbird.net/%LOCALE%/thunderbird/themes/?src=thunderbird"); + pref("extensions.getAddons.siteRegExp", "^https://.*addons\\.thunderbird\\.net"); + +@@ -190,9 +190,9 @@ pref("security.cert_pinning.enforcement_level", 1); + // .. etc .. + // + pref("extensions.update.enabled", true); +-pref("extensions.update.url", "https://versioncheck.addons.thunderbird.net/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); ++pref("extensions.update.url", "https://versioncheck.addons.thunderbird.net/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=Linux&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); + +-pref("extensions.update.background.url", "https://versioncheck-bg.addons.thunderbird.net/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); ++pref("extensions.update.background.url", "https://versioncheck-bg.addons.thunderbird.net/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=Linux&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); + + pref("extensions.update.interval", 86400); // Check for updates to Extensions and + // Themes every day +diff --git toolkit/mozapps/extensions/internal/AddonRepository.jsm toolkit/mozapps/extensions/internal/AddonRepository.jsm +index f70fd8d7e3bd8..81e8cd7764fdf 100644 +--- toolkit/mozapps/extensions/internal/AddonRepository.jsm ++++ toolkit/mozapps/extensions/internal/AddonRepository.jsm +@@ -588,7 +588,7 @@ var AddonRepository = { + addon.version = String(aEntry.current_version.version); + if (Array.isArray(aEntry.current_version.files)) { + for (let file of aEntry.current_version.files) { +- if (file.platform == "all" || file.platform == Services.appinfo.OS.toLowerCase()) { ++ if (file.platform == "all" || file.platform == "linux" || file.platform == Services.appinfo.OS.toLowerCase()) { + if (file.url) { + addon.sourceURI = NetUtil.newURI(file.url); + } +diff --git toolkit/mozapps/extensions/internal/XPIProvider.jsm toolkit/mozapps/extensions/internal/XPIProvider.jsm +index f70fd8d7e3bd8..81e8cd7764fdf 100644 +--- toolkit/mozapps/extensions/internal/XPIProvider.jsm ++++ toolkit/mozapps/extensions/internal/XPIProvider.jsm +@@ -4974,7 +4974,7 @@ AddonInternal.prototype = { + // Something is causing errors in here + try { + for (let platform of this.targetPlatforms) { +- if (platform.os == Services.appinfo.OS) { ++ if (platform.os == "Linux" || platform.os == Services.appinfo.OS) { + if (platform.abi) { + needsABI = true; + if (platform.abi === abi) Index: head/mail/thunderbird/files/patch-bug1021761 =================================================================== --- head/mail/thunderbird/files/patch-bug1021761 +++ head/mail/thunderbird/files/patch-bug1021761 @@ -0,0 +1,1269 @@ +commit f9bcf9c81c4a +Author: Evgeniy Vodolazskiy +Date: Tue Sep 9 14:38:00 2014 -0700 + + Bug 1021761 - Make ALSA optional on Linux, allowing fallback to another backend. r=kinetik r=glandium +--- + media/libcubeb/gtest/moz.build | 1 - + media/libcubeb/src/cubeb_alsa.c | 228 +++++++++++++++++++++++++++++----------- + toolkit/library/moz.build | 3 - + 3 files changed, 168 insertions(+), 64 deletions(-) + +diff --git media/libcubeb/gtest/moz.build media/libcubeb/gtest/moz.build +index 558130188c2e..0cf157d41903 100644 +--- media/libcubeb/gtest/moz.build ++++ media/libcubeb/gtest/moz.build +@@ -72,7 +72,6 @@ elif CONFIG['OS_TARGET'] == 'OpenBSD': + 'sndio', + ] + else: +- OS_LIBS += CONFIG['MOZ_ALSA_LIBS'] + OS_LIBS += CONFIG['MOZ_PULSEAUDIO_LIBS'] + + if CONFIG['CC_TYPE'] in ('clang', 'gcc'): +diff --git media/libcubeb/src/cubeb_alsa.c media/libcubeb/src/cubeb_alsa.c +index bfd4d8f199d4..213c1eaa3d07 100644 +--- media/libcubeb/src/cubeb_alsa.c ++++ media/libcubeb/src/cubeb_alsa.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -25,6 +26,52 @@ + + #define ALSA_PA_PLUGIN "ALSA <-> PulseAudio PCM I/O Plugin" + ++#ifdef DISABLE_LIBASOUND_DLOPEN ++#define WRAP(x) x ++#else ++#define WRAP(x) cubeb_##x ++#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x ++MAKE_TYPEDEF(snd_config); ++MAKE_TYPEDEF(snd_config_add); ++MAKE_TYPEDEF(snd_config_copy); ++MAKE_TYPEDEF(snd_config_delete); ++MAKE_TYPEDEF(snd_config_get_id); ++MAKE_TYPEDEF(snd_config_get_string); ++MAKE_TYPEDEF(snd_config_imake_integer); ++MAKE_TYPEDEF(snd_config_search); ++MAKE_TYPEDEF(snd_config_search_definition); ++MAKE_TYPEDEF(snd_lib_error_set_handler); ++MAKE_TYPEDEF(snd_pcm_avail_update); ++MAKE_TYPEDEF(snd_pcm_close); ++MAKE_TYPEDEF(snd_pcm_delay); ++MAKE_TYPEDEF(snd_pcm_drain); ++MAKE_TYPEDEF(snd_pcm_frames_to_bytes); ++MAKE_TYPEDEF(snd_pcm_get_params); ++/* snd_pcm_hw_params_alloca is actually a macro */ ++/* MAKE_TYPEDEF(snd_pcm_hw_params_alloca); */ ++MAKE_TYPEDEF(snd_pcm_hw_params_sizeof); ++#define snd_pcm_hw_params_sizeof cubeb_snd_pcm_hw_params_sizeof ++MAKE_TYPEDEF(snd_pcm_hw_params_any); ++MAKE_TYPEDEF(snd_pcm_hw_params_get_channels_max); ++MAKE_TYPEDEF(snd_pcm_hw_params_get_rate); ++MAKE_TYPEDEF(snd_pcm_hw_params_set_rate_near); ++MAKE_TYPEDEF(snd_pcm_nonblock); ++MAKE_TYPEDEF(snd_pcm_open); ++MAKE_TYPEDEF(snd_pcm_open_lconf); ++MAKE_TYPEDEF(snd_pcm_pause); ++MAKE_TYPEDEF(snd_pcm_poll_descriptors); ++MAKE_TYPEDEF(snd_pcm_poll_descriptors_count); ++MAKE_TYPEDEF(snd_pcm_poll_descriptors_revents); ++MAKE_TYPEDEF(snd_pcm_readi); ++MAKE_TYPEDEF(snd_pcm_recover); ++MAKE_TYPEDEF(snd_pcm_set_params); ++MAKE_TYPEDEF(snd_pcm_start); ++MAKE_TYPEDEF(snd_pcm_state); ++MAKE_TYPEDEF(snd_pcm_writei); ++ ++#undef MAKE_TYPEDEF ++#endif ++ + /* ALSA is not thread-safe. snd_pcm_t instances are individually protected + by the owning cubeb_stream's mutex. snd_pcm_t creation and destruction + is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1), +@@ -65,6 +112,8 @@ struct cubeb { + workaround is not required. */ + snd_config_t * local_config; + int is_pa; ++ ++ void * libasound; + }; + + enum stream_state { +@@ -245,8 +294,8 @@ set_timeout(struct timeval * timeout, unsigned int ms) + static void + stream_buffer_decrement(cubeb_stream * stm, long count) + { +- char * bufremains = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, count); +- memmove(stm->buffer, bufremains, snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes - count)); ++ char * bufremains = stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, count); ++ memmove(stm->buffer, bufremains, WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->bufframes - count)); + stm->bufframes -= count; + } + +@@ -278,9 +327,9 @@ alsa_process_stream(cubeb_stream * stm) + /* Call _poll_descriptors_revents() even if we don't use it + to let underlying plugins clear null events. Otherwise poll() + may wake up again and again, producing unnecessary CPU usage. */ +- snd_pcm_poll_descriptors_revents(stm->pcm, stm->fds, stm->nfds, &revents); ++ WRAP(snd_pcm_poll_descriptors_revents)(stm->pcm, stm->fds, stm->nfds, &revents); + +- avail = snd_pcm_avail_update(stm->pcm); ++ avail = WRAP(snd_pcm_avail_update)(stm->pcm); + + /* Got null event? Bail and wait for another wakeup. */ + if (avail == 0) { +@@ -303,7 +352,7 @@ alsa_process_stream(cubeb_stream * stm) + // TODO: should it be marked as DRAINING? + } + +- got = snd_pcm_readi(stm->pcm, stm->buffer+stm->bufframes, avail); ++ got = WRAP(snd_pcm_readi)(stm->pcm, stm->buffer+stm->bufframes, avail); + + if (got < 0) { + avail = got; // the error handler below will recover us +@@ -347,7 +396,7 @@ alsa_process_stream(cubeb_stream * stm) + (!stm->other_stream || stm->other_stream->bufframes > 0)) { + long got = avail - stm->bufframes; + void * other_buffer = stm->other_stream ? stm->other_stream->buffer : NULL; +- char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes); ++ char * buftail = stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->bufframes); + + /* Correct read size to the other stream available frames */ + if (stm->other_stream && got > (snd_pcm_sframes_t) stm->other_stream->bufframes) { +@@ -374,8 +423,8 @@ alsa_process_stream(cubeb_stream * stm) + long drain_frames = avail - stm->bufframes; + double drain_time = (double) drain_frames / stm->params.rate; + +- char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes); +- memset(buftail, 0, snd_pcm_frames_to_bytes(stm->pcm, drain_frames)); ++ char * buftail = stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->bufframes); ++ memset(buftail, 0, WRAP(snd_pcm_frames_to_bytes)(stm->pcm, drain_frames)); + stm->bufframes = avail; + + /* Mark as draining, unless we're waiting for capture */ +@@ -402,7 +451,7 @@ alsa_process_stream(cubeb_stream * stm) + } + } + +- wrote = snd_pcm_writei(stm->pcm, stm->buffer, avail); ++ wrote = WRAP(snd_pcm_writei)(stm->pcm, stm->buffer, avail); + if (wrote < 0) { + avail = wrote; // the error handler below will recover us + } else { +@@ -415,13 +464,13 @@ alsa_process_stream(cubeb_stream * stm) + + /* Got some error? Let's try to recover the stream. */ + if (avail < 0) { +- avail = snd_pcm_recover(stm->pcm, avail, 0); ++ avail = WRAP(snd_pcm_recover)(stm->pcm, avail, 0); + + /* Capture pcm must be started after initial setup/recover */ + if (avail >= 0 && + stm->stream_type == SND_PCM_STREAM_CAPTURE && +- snd_pcm_state(stm->pcm) == SND_PCM_STATE_PREPARED) { +- avail = snd_pcm_start(stm->pcm); ++ WRAP(snd_pcm_state)(stm->pcm) == SND_PCM_STATE_PREPARED) { ++ avail = WRAP(snd_pcm_start)(stm->pcm); + } + } + +@@ -537,26 +586,26 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm) + + slave_def = NULL; + +- r = snd_config_search(root_pcm, "slave", &slave_pcm); ++ r = WRAP(snd_config_search)(root_pcm, "slave", &slave_pcm); + if (r < 0) { + return NULL; + } + +- r = snd_config_get_string(slave_pcm, &string); ++ r = WRAP(snd_config_get_string)(slave_pcm, &string); + if (r >= 0) { +- r = snd_config_search_definition(lconf, "pcm_slave", string, &slave_def); ++ r = WRAP(snd_config_search_definition)(lconf, "pcm_slave", string, &slave_def); + if (r < 0) { + return NULL; + } + } + + do { +- r = snd_config_search(slave_def ? slave_def : slave_pcm, "pcm", &pcm); ++ r = WRAP(snd_config_search)(slave_def ? slave_def : slave_pcm, "pcm", &pcm); + if (r < 0) { + break; + } + +- r = snd_config_get_string(slave_def ? slave_def : slave_pcm, &string); ++ r = WRAP(snd_config_get_string)(slave_def ? slave_def : slave_pcm, &string); + if (r < 0) { + break; + } +@@ -565,7 +614,7 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm) + if (r < 0 || r > (int) sizeof(node_name)) { + break; + } +- r = snd_config_search(lconf, node_name, &pcm); ++ r = WRAP(snd_config_search)(lconf, node_name, &pcm); + if (r < 0) { + break; + } +@@ -574,7 +623,7 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm) + } while (0); + + if (slave_def) { +- snd_config_delete(slave_def); ++ WRAP(snd_config_delete)(slave_def); + } + + return NULL; +@@ -597,22 +646,22 @@ init_local_config_with_workaround(char const * pcm_name) + + lconf = NULL; + +- if (snd_config == NULL) { ++ if (*WRAP(snd_config) == NULL) { + return NULL; + } + +- r = snd_config_copy(&lconf, snd_config); ++ r = WRAP(snd_config_copy)(&lconf, *WRAP(snd_config)); + if (r < 0) { + return NULL; + } + + do { +- r = snd_config_search_definition(lconf, "pcm", pcm_name, &pcm_node); ++ r = WRAP(snd_config_search_definition)(lconf, "pcm", pcm_name, &pcm_node); + if (r < 0) { + break; + } + +- r = snd_config_get_id(pcm_node, &string); ++ r = WRAP(snd_config_get_id)(pcm_node, &string); + if (r < 0) { + break; + } +@@ -621,7 +670,7 @@ init_local_config_with_workaround(char const * pcm_name) + if (r < 0 || r > (int) sizeof(node_name)) { + break; + } +- r = snd_config_search(lconf, node_name, &pcm_node); ++ r = WRAP(snd_config_search)(lconf, node_name, &pcm_node); + if (r < 0) { + break; + } +@@ -632,12 +681,12 @@ init_local_config_with_workaround(char const * pcm_name) + } + + /* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */ +- r = snd_config_search(pcm_node, "type", &node); ++ r = WRAP(snd_config_search)(pcm_node, "type", &node); + if (r < 0) { + break; + } + +- r = snd_config_get_string(node, &string); ++ r = WRAP(snd_config_get_string)(node, &string); + if (r < 0) { + break; + } +@@ -648,18 +697,18 @@ init_local_config_with_workaround(char const * pcm_name) + + /* Don't clobber an explicit existing handle_underrun value, set it only + if it doesn't already exist. */ +- r = snd_config_search(pcm_node, "handle_underrun", &node); ++ r = WRAP(snd_config_search)(pcm_node, "handle_underrun", &node); + if (r != -ENOENT) { + break; + } + + /* Disable pcm_pulse's asynchronous underrun handling. */ +- r = snd_config_imake_integer(&node, "handle_underrun", 0); ++ r = WRAP(snd_config_imake_integer)(&node, "handle_underrun", 0); + if (r < 0) { + break; + } + +- r = snd_config_add(pcm_node, node); ++ r = WRAP(snd_config_add)(pcm_node, node); + if (r < 0) { + break; + } +@@ -667,7 +716,7 @@ init_local_config_with_workaround(char const * pcm_name) + return lconf; + } while (0); + +- snd_config_delete(lconf); ++ WRAP(snd_config_delete)(lconf); + + return NULL; + } +@@ -679,9 +728,9 @@ alsa_locked_pcm_open(snd_pcm_t ** pcm, char const * pcm_name, snd_pcm_stream_t s + + pthread_mutex_lock(&cubeb_alsa_mutex); + if (local_config) { +- r = snd_pcm_open_lconf(pcm, pcm_name, stream, SND_PCM_NONBLOCK, local_config); ++ r = WRAP(snd_pcm_open_lconf)(pcm, pcm_name, stream, SND_PCM_NONBLOCK, local_config); + } else { +- r = snd_pcm_open(pcm, pcm_name, stream, SND_PCM_NONBLOCK); ++ r = WRAP(snd_pcm_open)(pcm, pcm_name, stream, SND_PCM_NONBLOCK); + } + pthread_mutex_unlock(&cubeb_alsa_mutex); + +@@ -694,7 +743,7 @@ alsa_locked_pcm_close(snd_pcm_t * pcm) + int r; + + pthread_mutex_lock(&cubeb_alsa_mutex); +- r = snd_pcm_close(pcm); ++ r = WRAP(snd_pcm_close)(pcm); + pthread_mutex_unlock(&cubeb_alsa_mutex); + + return r; +@@ -757,12 +806,65 @@ alsa_init(cubeb ** context, char const * context_name) + pthread_attr_t attr; + snd_pcm_t * dummy; + ++ void * libasound = NULL; ++ ++#ifndef DISABLE_LIBASOUND_DLOPEN ++ libasound = dlopen("libasound.so", RTLD_LAZY); ++ if (!libasound) { ++ return CUBEB_ERROR; ++ } ++ ++#define LOAD(x) do { \ ++ cubeb_##x = dlsym(libasound, #x); \ ++ if (!cubeb_##x) { \ ++ dlclose(libasound); \ ++ return CUBEB_ERROR; \ ++ } \ ++ } while(0) ++ ++ LOAD(snd_config); ++ LOAD(snd_config_add); ++ LOAD(snd_config_copy); ++ LOAD(snd_config_delete); ++ LOAD(snd_config_get_id); ++ LOAD(snd_config_get_string); ++ LOAD(snd_config_imake_integer); ++ LOAD(snd_config_search); ++ LOAD(snd_config_search_definition); ++ LOAD(snd_lib_error_set_handler); ++ LOAD(snd_pcm_avail_update); ++ LOAD(snd_pcm_close); ++ LOAD(snd_pcm_delay); ++ LOAD(snd_pcm_drain); ++ LOAD(snd_pcm_frames_to_bytes); ++ LOAD(snd_pcm_get_params); ++ /* snd_pcm_hw_params_alloca is actually a macro */ ++ /* LOAD(snd_pcm_hw_params_alloca); */ ++ LOAD(snd_pcm_hw_params_sizeof); ++ LOAD(snd_pcm_hw_params_any); ++ LOAD(snd_pcm_hw_params_get_channels_max); ++ LOAD(snd_pcm_hw_params_get_rate); ++ LOAD(snd_pcm_hw_params_set_rate_near); ++ LOAD(snd_pcm_nonblock); ++ LOAD(snd_pcm_open); ++ LOAD(snd_pcm_open_lconf); ++ LOAD(snd_pcm_pause); ++ LOAD(snd_pcm_poll_descriptors); ++ LOAD(snd_pcm_poll_descriptors_count); ++ LOAD(snd_pcm_poll_descriptors_revents); ++ LOAD(snd_pcm_recover); ++ LOAD(snd_pcm_set_params); ++ LOAD(snd_pcm_state); ++ LOAD(snd_pcm_writei); ++ ++#undef LOAD ++#endif + assert(context); + *context = NULL; + + pthread_mutex_lock(&cubeb_alsa_mutex); + if (!cubeb_alsa_error_handler_set) { +- snd_lib_error_set_handler(silent_error_handler); ++ WRAP(snd_lib_error_set_handler)(silent_error_handler); + cubeb_alsa_error_handler_set = 1; + } + pthread_mutex_unlock(&cubeb_alsa_mutex); +@@ -770,6 +872,8 @@ alsa_init(cubeb ** context, char const * context_name) + ctx = calloc(1, sizeof(*ctx)); + assert(ctx); + ++ ctx->libasound = libasound; ++ + ctx->ops = &alsa_ops; + + r = pthread_mutex_init(&ctx->mutex, NULL); +@@ -819,7 +923,7 @@ alsa_init(cubeb ** context, char const * context_name) + config fails with EINVAL, the PA PCM is too old for this workaround. */ + if (r == -EINVAL) { + pthread_mutex_lock(&cubeb_alsa_mutex); +- snd_config_delete(ctx->local_config); ++ WRAP(snd_config_delete)(ctx->local_config); + pthread_mutex_unlock(&cubeb_alsa_mutex); + ctx->local_config = NULL; + } else if (r >= 0) { +@@ -859,9 +963,13 @@ alsa_destroy(cubeb * ctx) + pthread_mutex_destroy(&ctx->mutex); + free(ctx->fds); + ++ if (ctx->libasound) { ++ dlclose(ctx->libasound); ++ } ++ + if (ctx->local_config) { + pthread_mutex_lock(&cubeb_alsa_mutex); +- snd_config_delete(ctx->local_config); ++ WRAP(snd_config_delete)(ctx->local_config); + pthread_mutex_unlock(&cubeb_alsa_mutex); + } + +@@ -948,7 +1056,7 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream + return CUBEB_ERROR; + } + +- r = snd_pcm_nonblock(stm->pcm, 1); ++ r = WRAP(snd_pcm_nonblock)(stm->pcm, 1); + assert(r == 0); + + latency_us = latency_frames * 1e6 / stm->params.rate; +@@ -961,7 +1069,7 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream + latency_us = latency_us < min_latency ? min_latency: latency_us; + } + +- r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, ++ r = WRAP(snd_pcm_set_params)(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, + stm->params.channels, stm->params.rate, 1, + latency_us); + if (r < 0) { +@@ -969,20 +1077,20 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream + return CUBEB_ERROR_INVALID_FORMAT; + } + +- r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &period_size); ++ r = WRAP(snd_pcm_get_params)(stm->pcm, &stm->buffer_size, &period_size); + assert(r == 0); + + /* Double internal buffer size to have enough space when waiting for the other side of duplex connection */ + stm->buffer_size *= 2; +- stm->buffer = calloc(1, snd_pcm_frames_to_bytes(stm->pcm, stm->buffer_size)); ++ stm->buffer = calloc(1, WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->buffer_size)); + assert(stm->buffer); + +- stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm); ++ stm->nfds = WRAP(snd_pcm_poll_descriptors_count)(stm->pcm); + assert(stm->nfds > 0); + + stm->saved_fds = calloc(stm->nfds, sizeof(struct pollfd)); + assert(stm->saved_fds); +- r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds); ++ r = WRAP(snd_pcm_poll_descriptors)(stm->pcm, stm->saved_fds, stm->nfds); + assert((nfds_t) r == stm->nfds); + + if (alsa_register_stream(ctx, stm) != 0) { +@@ -1054,7 +1162,7 @@ alsa_stream_destroy(cubeb_stream * stm) + pthread_mutex_lock(&stm->mutex); + if (stm->pcm) { + if (stm->state == DRAINING) { +- snd_pcm_drain(stm->pcm); ++ WRAP(snd_pcm_drain)(stm->pcm); + } + alsa_locked_pcm_close(stm->pcm); + stm->pcm = NULL; +@@ -1100,12 +1208,12 @@ alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) + + assert(stm); + +- r = snd_pcm_hw_params_any(stm->pcm, hw_params); ++ r = WRAP(snd_pcm_hw_params_any)(stm->pcm, hw_params); + if (r < 0) { + return CUBEB_ERROR; + } + +- r = snd_pcm_hw_params_get_channels_max(hw_params, max_channels); ++ r = WRAP(snd_pcm_hw_params_get_channels_max)(hw_params, max_channels); + if (r < 0) { + return CUBEB_ERROR; + } +@@ -1126,34 +1234,34 @@ alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) { + + /* get a pcm, disabling resampling, so we get a rate the + * hardware/dmix/pulse/etc. supports. */ +- r = snd_pcm_open(&pcm, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK, SND_PCM_NO_AUTO_RESAMPLE); ++ r = WRAP(snd_pcm_open)(&pcm, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK, SND_PCM_NO_AUTO_RESAMPLE); + if (r < 0) { + return CUBEB_ERROR; + } + +- r = snd_pcm_hw_params_any(pcm, hw_params); ++ r = WRAP(snd_pcm_hw_params_any)(pcm, hw_params); + if (r < 0) { +- snd_pcm_close(pcm); ++ WRAP(snd_pcm_close)(pcm); + return CUBEB_ERROR; + } + +- r = snd_pcm_hw_params_get_rate(hw_params, rate, &dir); ++ r = WRAP(snd_pcm_hw_params_get_rate)(hw_params, rate, &dir); + if (r >= 0) { + /* There is a default rate: use it. */ +- snd_pcm_close(pcm); ++ WRAP(snd_pcm_close)(pcm); + return CUBEB_OK; + } + + /* Use a common rate, alsa may adjust it based on hw/etc. capabilities. */ + *rate = 44100; + +- r = snd_pcm_hw_params_set_rate_near(pcm, hw_params, rate, NULL); ++ r = WRAP(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, NULL); + if (r < 0) { +- snd_pcm_close(pcm); ++ WRAP(snd_pcm_close)(pcm); + return CUBEB_ERROR; + } + +- snd_pcm_close(pcm); ++ WRAP(snd_pcm_close)(pcm); + + return CUBEB_OK; + } +@@ -1186,10 +1294,10 @@ alsa_stream_start(cubeb_stream * stm) + pthread_mutex_lock(&stm->mutex); + /* Capture pcm must be started after initial setup/recover */ + if (stm->stream_type == SND_PCM_STREAM_CAPTURE && +- snd_pcm_state(stm->pcm) == SND_PCM_STATE_PREPARED) { +- snd_pcm_start(stm->pcm); ++ WRAP(snd_pcm_state)(stm->pcm) == SND_PCM_STATE_PREPARED) { ++ WRAP(snd_pcm_start)(stm->pcm); + } +- snd_pcm_pause(stm->pcm, 0); ++ WRAP(snd_pcm_pause)(stm->pcm, 0); + gettimeofday(&stm->last_activity, NULL); + pthread_mutex_unlock(&stm->mutex); + +@@ -1229,7 +1337,7 @@ alsa_stream_stop(cubeb_stream * stm) + pthread_mutex_unlock(&ctx->mutex); + + pthread_mutex_lock(&stm->mutex); +- snd_pcm_pause(stm->pcm, 1); ++ WRAP(snd_pcm_pause)(stm->pcm, 1); + pthread_mutex_unlock(&stm->mutex); + + return CUBEB_OK; +@@ -1245,8 +1353,8 @@ alsa_stream_get_position(cubeb_stream * stm, uint64_t * position) + pthread_mutex_lock(&stm->mutex); + + delay = -1; +- if (snd_pcm_state(stm->pcm) != SND_PCM_STATE_RUNNING || +- snd_pcm_delay(stm->pcm, &delay) != 0) { ++ if (WRAP(snd_pcm_state)(stm->pcm) != SND_PCM_STATE_RUNNING || ++ WRAP(snd_pcm_delay)(stm->pcm, &delay) != 0) { + *position = stm->last_position; + pthread_mutex_unlock(&stm->mutex); + return CUBEB_OK; +@@ -1271,7 +1379,7 @@ alsa_stream_get_latency(cubeb_stream * stm, uint32_t * latency) + snd_pcm_sframes_t delay; + /* This function returns the delay in frames until a frame written using + snd_pcm_writei is sent to the DAC. The DAC delay should be < 1ms anyways. */ +- if (snd_pcm_delay(stm->pcm, &delay)) { ++ if (WRAP(snd_pcm_delay)(stm->pcm, &delay)) { + return CUBEB_ERROR; + } + +diff --git toolkit/library/moz.build toolkit/library/moz.build +index b0df6b98b91f..e06592daa265 100644 +--- toolkit/library/moz.build ++++ toolkit/library/moz.build +@@ -247,9 +247,6 @@ if CONFIG['MOZ_SYSTEM_LIBVPX']: + if not CONFIG['MOZ_TREE_PIXMAN']: + OS_LIBS += CONFIG['MOZ_PIXMAN_LIBS'] + +-if CONFIG['MOZ_ALSA']: +- OS_LIBS += CONFIG['MOZ_ALSA_LIBS'] +- + if CONFIG['HAVE_CLOCK_MONOTONIC']: + OS_LIBS += CONFIG['REALTIME_LIBS'] + + +commit 161bcd671217 +Author: Evgeniy Vodolazskiy +Date: Wed Sep 3 10:47:00 2014 -0700 + + Bug 1021761 - Add OSS backend to libcubeb, default but last on Linux. r=kinetik r=glandium +--- + build/moz.configure/old.configure | 1 + + dom/media/CubebUtils.cpp | 3 +- + media/libcubeb/AUTHORS | 1 + + media/libcubeb/src/cubeb.c | 10 + + media/libcubeb/src/cubeb_oss.c | 453 ++++++++++++++++++++++++++++++++++++++ + media/libcubeb/src/moz.build | 7 + + media/libcubeb/update.sh | 1 + + old-configure.in | 62 ++++++ + toolkit/library/moz.build | 3 + + 9 files changed, 540 insertions(+), 1 deletion(-) + +diff --git build/moz.configure/old.configure build/moz.configure/old.configure +index 17d0c5bf3420..3e6dbc16ca14 100644 +--- build/moz.configure/old.configure ++++ build/moz.configure/old.configure +@@ -262,6 +262,7 @@ def old_configure_options(*options): + '--with-nspr-prefix', + '--with-nss-exec-prefix', + '--with-nss-prefix', ++ '--with-oss', + '--with-pthreads', + '--with-qemu-exe', + '--with-sixgill', +diff --git dom/media/CubebUtils.cpp dom/media/CubebUtils.cpp +index 88063ed3a4d6..8613f86dbd16 100644 +--- dom/media/CubebUtils.cpp ++++ dom/media/CubebUtils.cpp +@@ -149,7 +149,8 @@ const char* AUDIOSTREAM_BACKEND_ID_STR[] = { + "sndio", + "opensl", + "audiotrack", +- "kai" ++ "kai", ++ "oss", + }; + /* Index for failures to create an audio stream the first time. */ + const int CUBEB_BACKEND_INIT_FAILURE_FIRST = +diff --git media/libcubeb/AUTHORS media/libcubeb/AUTHORS +index f0f9595227f2..e7e7048190ab 100644 +--- media/libcubeb/AUTHORS ++++ media/libcubeb/AUTHORS +@@ -4,6 +4,7 @@ Michael Wu + Paul Adenot + David Richards + Sebastien Alaiwan ++Evgeniy Vodolazskiy + KO Myung-Hun + Haakon Sporsheim + Alex Chronopoulos +diff --git media/libcubeb/src/cubeb.c media/libcubeb/src/cubeb.c +index bb35e0ce349f..e523d94108a3 100644 +--- media/libcubeb/src/cubeb.c ++++ media/libcubeb/src/cubeb.c +@@ -60,6 +60,9 @@ int audiotrack_init(cubeb ** context, char const * context_name); + #if defined(USE_KAI) + int kai_init(cubeb ** context, char const * context_name); + #endif ++#if defined(USE_OSS) ++int oss_init(cubeb ** context, char const * context_name); ++#endif + + static int + validate_stream_params(cubeb_stream_params * input_stream_params, +@@ -159,6 +162,10 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam + } else if (!strcmp(backend_name, "kai")) { + #if defined(USE_KAI) + init_oneshot = kai_init; ++#endif ++ } else if (!strcmp(backend_name, "oss")) { ++#if defined(USE_OSS) ++ init_oneshot = oss_init; + #endif + } else { + /* Already set */ +@@ -203,6 +210,9 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam + #endif + #if defined(USE_KAI) + kai_init, ++#endif ++#if defined(USE_OSS) ++ oss_init, + #endif + }; + int i; +diff --git media/libcubeb/src/cubeb_oss.c media/libcubeb/src/cubeb_oss.c +new file mode 100644 +index 000000000000..7d96168b9ea6 +--- /dev/null ++++ media/libcubeb/src/cubeb_oss.c +@@ -0,0 +1,454 @@ ++/* ++ * Copyright © 2014 Mozilla Foundation ++ * ++ * This program is made available under an ISC-style license. See the ++ * accompanying file LICENSE for details. ++ */ ++#if defined(HAVE_SYS_SOUNDCARD_H) ++#include ++#else ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cubeb/cubeb.h" ++#include "cubeb-internal.h" ++ ++#ifndef CUBEB_OSS_DEFAULT_OUTPUT ++#define CUBEB_OSS_DEFAULT_OUTPUT "/dev/dsp" ++#endif ++ ++#define OSS_BUFFER_SIZE 1024 ++ ++struct cubeb { ++ struct cubeb_ops const * ops; ++}; ++ ++struct cubeb_stream { ++ /* Note: Must match cubeb_stream layout in cubeb.c. */ ++ cubeb * context; ++ void * user_ptr; ++ /**/ ++ ++ cubeb_data_callback data_callback; ++ cubeb_state_callback state_callback; ++ float volume; ++ float panning; ++ ++ pthread_mutex_t state_mutex; ++ pthread_cond_t state_cond; ++ ++ int running; ++ int stopped; ++ int floating; ++ ++ /* These two vars are needed to support old versions of OSS */ ++ unsigned int position_bytes; ++ unsigned int last_position_bytes; ++ ++ uint64_t written_frags; /* The number of fragments written to /dev/dsp */ ++ uint64_t missed_frags; /* fragments output with stopped stream */ ++ ++ cubeb_stream_params params; ++ int fd; ++ pthread_t th; ++}; ++ ++static struct cubeb_ops const oss_ops; ++ ++int oss_init(cubeb ** context, char const * context_name) ++{ ++ cubeb* ctx = (cubeb*)malloc(sizeof(cubeb)); ++ ctx->ops = &oss_ops; ++ *context = ctx; ++ return CUBEB_OK; ++} ++ ++static void oss_destroy(cubeb *ctx) ++{ ++ free(ctx); ++} ++ ++static char const * oss_get_backend_id(cubeb * context) ++{ ++ static char oss_name[] = "oss"; ++ return oss_name; ++} ++ ++static int oss_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) ++{ ++ *max_channels = 2; /* Let's support only stereo for now */ ++ return CUBEB_OK; ++} ++ ++static int oss_get_min_latency(cubeb * context, cubeb_stream_params params, ++ uint32_t * latency_frames) ++{ ++ (void)context; ++ /* 40ms is a big enough number to work ok */ ++ *latency_frames = 40 * params.rate / 1000; ++ return CUBEB_OK; ++} ++ ++static int oss_get_preferred_sample_rate(cubeb *context, uint32_t * rate) ++{ ++ /* 48000 seems a prefered choice for most audio devices ++ * and a good choice for OSS */ ++ *rate = 48000; ++ return CUBEB_OK; ++} ++ ++static void run_state_callback(cubeb_stream *stream, cubeb_state state) ++{ ++ if (stream->state_callback) { ++ stream->state_callback(stream, stream->user_ptr, state); ++ } ++} ++ ++static long run_data_callback(cubeb_stream *stream, void *buffer, long nframes) ++{ ++ long got = 0; ++ pthread_mutex_lock(&stream->state_mutex); ++ if (stream->data_callback && stream->running && !stream->stopped) { ++ pthread_mutex_unlock(&stream->state_mutex); ++ got = stream->data_callback(stream, stream->user_ptr, NULL, buffer, nframes); ++ } else { ++ pthread_mutex_unlock(&stream->state_mutex); ++ } ++ return got; ++} ++ ++static void apply_volume_int(int16_t* buffer, unsigned int n, ++ float volume, float panning) ++{ ++ float left = volume; ++ float right = volume; ++ unsigned int i; ++ int pan[2]; ++ if (panning<0) { ++ right *= (1+panning); ++ } else { ++ left *= (1-panning); ++ } ++ pan[0] = 128.0*left; ++ pan[1] = 128.0*right; ++ for(i=0; irunning) { ++ pthread_mutex_lock(&stream->state_mutex); ++ if (stream->stopped) { ++ pthread_mutex_unlock(&stream->state_mutex); ++ run_state_callback(stream, CUBEB_STATE_STOPPED); ++ pthread_mutex_lock(&stream->state_mutex); ++ while (stream->stopped) { ++ pthread_cond_wait(&stream->state_cond, &stream->state_mutex); ++ } ++ pthread_mutex_unlock(&stream->state_mutex); ++ run_state_callback(stream, CUBEB_STATE_STARTED); ++ continue; ++ } ++ pthread_mutex_unlock(&stream->state_mutex); ++ if (stream->floating) { ++ got = run_data_callback(stream, f_buffer, ++ OSS_BUFFER_SIZE/stream->params.channels); ++ apply_volume_float(f_buffer, got*stream->params.channels, ++ stream->volume, stream->panning); ++ for (i=0; i<((unsigned long)got)*stream->params.channels; i++) { ++ /* Clipping is prefered to overflow */ ++ if(f_buffer[i]>=1.0){ ++ f_buffer[i]=1.0; ++ } ++ if(f_buffer[i]<=-1.0){ ++ f_buffer[i]=-1.0; ++ } ++ /* One might think that multipling by 32767.0 is logical but results in clipping */ ++ buffer[i] = f_buffer[i]*32767.0; ++ } ++ } else { ++ got = run_data_callback(stream, buffer, ++ OSS_BUFFER_SIZE/stream->params.channels); ++ apply_volume_int(buffer, got*stream->params.channels, ++ stream->volume, stream->panning); ++ } ++ if (got<0) { ++ run_state_callback(stream, CUBEB_STATE_ERROR); ++ break; ++ } ++ if (!got) { ++ run_state_callback(stream, CUBEB_STATE_DRAINED); ++ } ++ if (got) { ++ size_t i = 0; ++ size_t s = got*stream->params.channels*sizeof(int16_t); ++ while (i < s) { ++ ssize_t n = write(stream->fd, ((char*)buffer) + i, s - i); ++ if (n<=0) { ++ run_state_callback(stream, CUBEB_STATE_ERROR); ++ break; ++ } ++ i+=n; ++ } ++ stream->written_frags+=got; ++ } ++ } ++ return NULL; ++} ++ ++static void oss_try_set_latency(cubeb_stream* stream, unsigned int latency) ++{ ++ unsigned int latency_bytes, n_frag; ++ int frag; ++ /* fragment size of 1024 is a good choice with good chances to be accepted */ ++ unsigned int frag_log=10; /* 2^frag_log = fragment size */ ++ latency_bytes = ++ latency*stream->params.rate*stream->params.channels*sizeof(uint16_t)/1000; ++ n_frag = latency_bytes>>frag_log; ++ frag = (n_frag<<16) | frag_log; ++ /* Even if this fails we wish to continue, not checking for errors */ ++ ioctl(stream->fd, SNDCTL_DSP_SETFRAGMENT, &frag); ++} ++ ++static int oss_stream_init(cubeb * context, cubeb_stream ** stm, ++ char const * stream_name, ++ cubeb_devid input_device, ++ cubeb_stream_params * input_stream_params, ++ cubeb_devid output_device, ++ cubeb_stream_params * output_stream_params, ++ unsigned int latency, ++ cubeb_data_callback data_callback, ++ cubeb_state_callback state_callback, void * user_ptr) ++{ ++ cubeb_stream* stream = (cubeb_stream*)malloc(sizeof(cubeb_stream)); ++ stream->context = context; ++ stream->data_callback = data_callback; ++ stream->state_callback = state_callback; ++ stream->user_ptr = user_ptr; ++ ++ assert(!input_stream_params && "not supported."); ++ if (input_device || output_device) { ++ /* Device selection not yet implemented. */ ++ return CUBEB_ERROR_DEVICE_UNAVAILABLE; ++ } ++ ++ if ((input_stream_params && input_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) || ++ (output_stream_params && output_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK)) { ++ return CUBEB_ERROR_NOT_SUPPORTED; ++ } ++ ++ if ((stream->fd = open(CUBEB_OSS_DEFAULT_OUTPUT, O_WRONLY)) == -1) { ++ free(stream); ++ return CUBEB_ERROR; ++ } ++#define SET(what, to) do { unsigned int i = to; \ ++ int j = ioctl(stream->fd, what, &i); \ ++ if (j == -1 || i != to) { \ ++ close(stream->fd); \ ++ free(stream); \ ++ return CUBEB_ERROR_INVALID_FORMAT; } } while (0) ++ ++ stream->params = *output_stream_params; ++ stream->volume = 1.0; ++ stream->panning = 0.0; ++ ++ oss_try_set_latency(stream, latency); ++ ++ stream->floating = 0; ++ SET(SNDCTL_DSP_CHANNELS, stream->params.channels); ++ SET(SNDCTL_DSP_SPEED, stream->params.rate); ++ switch (stream->params.format) { ++ case CUBEB_SAMPLE_S16LE: ++ SET(SNDCTL_DSP_SETFMT, AFMT_S16_LE); ++ break; ++ case CUBEB_SAMPLE_S16BE: ++ SET(SNDCTL_DSP_SETFMT, AFMT_S16_BE); ++ break; ++ case CUBEB_SAMPLE_FLOAT32LE: ++ SET(SNDCTL_DSP_SETFMT, AFMT_S16_NE); ++ stream->floating = 1; ++ break; ++ default: ++ close(stream->fd); ++ free(stream); ++ return CUBEB_ERROR; ++ } ++ ++ ++ pthread_mutex_init(&stream->state_mutex, NULL); ++ pthread_cond_init(&stream->state_cond, NULL); ++ ++ stream->running = 1; ++ stream->stopped = 1; ++ stream->position_bytes = 0; ++ stream->last_position_bytes = 0; ++ stream->written_frags = 0; ++ stream->missed_frags = 0; ++ ++ pthread_create(&stream->th, NULL, writer, (void*)stream); ++ ++ *stm = stream; ++ ++ return CUBEB_OK; ++} ++ ++static void oss_stream_destroy(cubeb_stream * stream) ++{ ++ pthread_mutex_lock(&stream->state_mutex); ++ ++ stream->running = 0; ++ stream->stopped = 0; ++ pthread_cond_signal(&stream->state_cond); ++ ++ pthread_mutex_unlock(&stream->state_mutex); ++ ++ pthread_join(stream->th, NULL); ++ ++ pthread_mutex_destroy(&stream->state_mutex); ++ pthread_cond_destroy(&stream->state_cond); ++ close(stream->fd); ++ free(stream); ++} ++ ++static int oss_stream_get_latency(cubeb_stream * stream, uint32_t * latency) ++{ ++ if (ioctl(stream->fd, SNDCTL_DSP_GETODELAY, latency)==-1) { ++ return CUBEB_ERROR; ++ } ++ /* Convert latency from bytes to frames */ ++ *latency /= stream->params.channels*sizeof(int16_t); ++ return CUBEB_OK; ++} ++ ++ ++static int oss_stream_current_optr(cubeb_stream * stream, uint64_t * position) ++{ ++ count_info ci; ++ /* Unfortunately, this ioctl is only available in OSS 4.x */ ++#ifdef SNDCTL_DSP_CURRENT_OPTR ++ oss_count_t count; ++ if (ioctl(stream->fd, SNDCTL_DSP_CURRENT_OPTR, &count) != -1) { ++ *position = count.samples;// + count.fifo_samples; ++ return CUBEB_OK; ++ } ++#endif ++ /* Fall back to this ioctl in case the previous one fails */ ++ if (ioctl(stream->fd, SNDCTL_DSP_GETOPTR, &ci) == -1) { ++ return CUBEB_ERROR; ++ } ++ /* ci.bytes is only 32 bit and will start to wrap after arithmetic overflow */ ++ stream->position_bytes += ci.bytes - stream->last_position_bytes; ++ stream->last_position_bytes = ci.bytes; ++ *position = stream->position_bytes/stream->params.channels/sizeof(int16_t); ++ return CUBEB_OK; ++} ++ ++static int oss_stream_get_position(cubeb_stream * stream, uint64_t * position) ++{ ++ if ( oss_stream_current_optr(stream, position) == CUBEB_OK ){ ++ *position -= stream->missed_frags; ++ return CUBEB_OK; ++ } ++ /* If no correct method to get position works we resort to this */ ++ *position = stream->written_frags; ++ return CUBEB_OK; ++} ++ ++ ++static int oss_stream_start(cubeb_stream * stream) ++{ ++ pthread_mutex_lock(&stream->state_mutex); ++ if (stream->stopped) { ++ uint64_t ptr; ++ oss_stream_current_optr(stream, &ptr); ++ stream->missed_frags = ptr - stream->written_frags; ++ stream->stopped = 0; ++ pthread_cond_signal(&stream->state_cond); ++ } ++ pthread_mutex_unlock(&stream->state_mutex); ++ return CUBEB_OK; ++} ++ ++static int oss_stream_stop(cubeb_stream * stream) ++{ ++ pthread_mutex_lock(&stream->state_mutex); ++ stream->stopped = 1; ++ pthread_mutex_unlock(&stream->state_mutex); ++ return CUBEB_OK; ++} ++ ++int oss_stream_set_panning(cubeb_stream * stream, float panning) ++{ ++ if (stream->params.channels == 2) { ++ stream->panning=panning; ++ } ++ return CUBEB_OK; ++} ++ ++int oss_stream_set_volume(cubeb_stream * stream, float volume) ++{ ++ stream->volume=volume; ++ return CUBEB_OK; ++} ++ ++static struct cubeb_ops const oss_ops = { ++ .init = oss_init, ++ .get_backend_id = oss_get_backend_id, ++ .get_max_channel_count = oss_get_max_channel_count, ++ .get_min_latency = oss_get_min_latency, ++ .get_preferred_sample_rate = oss_get_preferred_sample_rate, ++ .get_preferred_channel_layout = NULL, ++ .enumerate_devices = NULL, ++ .device_collection_destroy = NULL, ++ .destroy = oss_destroy, ++ .stream_init = oss_stream_init, ++ .stream_destroy = oss_stream_destroy, ++ .stream_start = oss_stream_start, ++ .stream_stop = oss_stream_stop, ++ .stream_reset_default_device = NULL, ++ .stream_get_position = oss_stream_get_position, ++ .stream_get_latency = oss_stream_get_latency, ++ .stream_set_volume = oss_stream_set_volume, ++ .stream_set_panning = oss_stream_set_panning, ++ .stream_get_current_device = NULL, ++ .stream_device_destroy = NULL, ++ .stream_register_device_changed_callback = NULL, ++ .register_device_collection_changed = NULL ++}; +diff --git media/libcubeb/src/moz.build media/libcubeb/src/moz.build +index e1fea30ca417..a5b1100f1014 100644 +--- media/libcubeb/src/moz.build ++++ media/libcubeb/src/moz.build +@@ -23,6 +23,12 @@ if CONFIG['MOZ_ALSA']: + ] + DEFINES['USE_ALSA'] = True + ++if CONFIG['MOZ_OSS']: ++ SOURCES += [ ++ 'cubeb_oss.c', ++ ] ++ DEFINES['USE_OSS'] = True ++ + if CONFIG['MOZ_PULSEAUDIO'] or CONFIG['MOZ_JACK']: + SOURCES += [ + 'cubeb_resampler.cpp', +@@ -88,6 +94,7 @@ if CONFIG['OS_TARGET'] == 'Android': + FINAL_LIBRARY = 'gkmedias' + + CFLAGS += CONFIG['MOZ_ALSA_CFLAGS'] ++CFLAGS += CONFIG['MOZ_OSS_CFLAGS'] + CFLAGS += CONFIG['MOZ_PULSEAUDIO_CFLAGS'] + + # We allow warnings for third-party code that can be updated from upstream. +diff --git media/libcubeb/update.sh media/libcubeb/update.sh +index 0bb6345c9fa9..78a102dc47cb 100755 +--- media/libcubeb/update.sh ++++ media/libcubeb/update.sh +@@ -20,6 +20,7 @@ cp $1/src/cubeb_log.h src + cp $1/src/cubeb_mixer.cpp src + cp $1/src/cubeb_mixer.h src + cp $1/src/cubeb_opensl.c src ++cp $1/src/cubeb_oss.c src + cp $1/src/cubeb-jni.cpp src + cp $1/src/cubeb-jni.h src + cp $1/src/android/cubeb-output-latency.h src/android +diff --git old-configure.in old-configure.in +index 28e1a9e48d61..edacedcf6e5d 100644 +--- old-configure.in ++++ old-configure.in +@@ -2598,6 +2598,67 @@ MOZ_WEBM_ENCODER=1 + AC_DEFINE(MOZ_WEBM_ENCODER) + AC_SUBST(MOZ_WEBM_ENCODER) + ++dnl ================================== ++dnl = Check OSS availability ++dnl ================================== ++ ++dnl If using Linux, Solaris or BSDs, ensure that OSS is available ++case "$OS_TARGET" in ++Linux|SunOS|DragonFly|FreeBSD|NetBSD|GNU/kFreeBSD) ++ MOZ_OSS=1 ++ ;; ++esac ++ ++MOZ_ARG_WITH_STRING(oss, ++[ --with-oss[=PFX] Enable OpenSoundSystem support [installed at prefix PFX]], ++ OSSPREFIX=$withval) ++ ++if test -n "$OSSPREFIX"; then ++ if test "$OSSPREFIX" != "no"; then ++ MOZ_OSS=1 ++ else ++ MOZ_OSS= ++ fi ++fi ++ ++_SAVE_CFLAGS=$CFLAGS ++_SAVE_LIBS=$LIBS ++if test -n "$MOZ_OSS"; then ++ dnl Prefer 4Front implementation ++ AC_MSG_CHECKING([MOZ_OSS_CFLAGS]) ++ if test "$OSSPREFIX" != "yes"; then ++ oss_conf=${OSSPREFIX%/usr}/etc/oss.conf ++ if test -f "$oss_conf"; then ++ . "$oss_conf" ++ else ++ OSSLIBDIR=$OSSPREFIX/lib/oss ++ fi ++ if test -d "$OSSLIBDIR"; then ++ MOZ_OSS_CFLAGS="$MOZ_OSS_CFLAGS -I$OSSLIBDIR/include" ++ fi ++ fi ++ AC_MSG_RESULT([$MOZ_OSS_CFLAGS]) ++ ++ CFLAGS="$CFLAGS $MOZ_OSS_CFLAGS" ++ MOZ_CHECK_HEADERS(sys/soundcard.h soundcard.h) ++ ++ if test "$ac_cv_header_sys_soundcard_h" != "yes" -a \ ++ "$ac_cv_header_soundcard_h" != "yes"; then ++ AC_MSG_ERROR([Need OSS for Ogg, Wave or WebM decoding on $OS_TARGET. Disable with --without-oss.]) ++ fi ++ ++ dnl Assume NetBSD implementation over SunAudio ++ AC_CHECK_LIB(ossaudio, _oss_ioctl, ++ [AC_DEFINE_UNQUOTED(CUBEB_OSS_DEFAULT_OUTPUT, "/dev/sound") ++ MOZ_OSS_LIBS="$MOZ_OSS_LIBS -lossaudio"]) ++fi ++CFLAGS=$_SAVE_CFLAGS ++LIBS=$_SAVE_LIBS ++ ++AC_SUBST(MOZ_OSS) ++AC_SUBST_LIST(MOZ_OSS_CFLAGS) ++AC_SUBST_LIST(MOZ_OSS_LIBS) ++ + dnl ================================== + dnl = Check alsa availability on Linux + dnl ================================== +diff --git toolkit/library/moz.build toolkit/library/moz.build +index e06592daa265..ce016b96c2bc 100644 +--- toolkit/library/moz.build ++++ toolkit/library/moz.build +@@ -247,6 +247,9 @@ if CONFIG['MOZ_SYSTEM_LIBVPX']: + if not CONFIG['MOZ_TREE_PIXMAN']: + OS_LIBS += CONFIG['MOZ_PIXMAN_LIBS'] + ++if CONFIG['MOZ_OSS']: ++ OS_LIBS += CONFIG['MOZ_OSS_LIBS'] ++ + if CONFIG['HAVE_CLOCK_MONOTONIC']: + OS_LIBS += CONFIG['REALTIME_LIBS'] + Index: head/mail/thunderbird/files/patch-bug1144632 =================================================================== --- head/mail/thunderbird/files/patch-bug1144632 +++ head/mail/thunderbird/files/patch-bug1144632 @@ -0,0 +1,100 @@ +commit 7e0038706036 +Author: Lee Salzman +Date: Thu May 24 14:50:31 2018 -0400 + + Bug 1144632 - fix big-endian Skia builds. r=rhunt + + MozReview-Commit-ID: JQivGBE45qy +--- + gfx/skia/skia/include/core/SkColorPriv.h | 15 ++++----------- + gfx/skia/skia/include/core/SkImageInfo.h | 2 +- + gfx/skia/skia/include/gpu/GrTypes.h | 5 +---- + gfx/skia/skia/src/core/SkColorData.h | 15 ++++----------- + 4 files changed, 10 insertions(+), 27 deletions(-) + +diff --git gfx/skia/skia/include/core/SkColorPriv.h gfx/skia/skia/include/core/SkColorPriv.h +index 0cd02e8034062..8a7f1501ba434 100644 +--- gfx/skia/skia/include/core/SkColorPriv.h ++++ gfx/skia/skia/include/core/SkColorPriv.h +@@ -55,17 +55,10 @@ static inline U8CPU SkUnitScalarClampToByte(SkScalar x) { + * Here we enforce this constraint. + */ + +-#ifdef SK_CPU_BENDIAN +- #define SK_RGBA_R32_SHIFT 24 +- #define SK_RGBA_G32_SHIFT 16 +- #define SK_RGBA_B32_SHIFT 8 +- #define SK_RGBA_A32_SHIFT 0 +-#else +- #define SK_RGBA_R32_SHIFT 0 +- #define SK_RGBA_G32_SHIFT 8 +- #define SK_RGBA_B32_SHIFT 16 +- #define SK_RGBA_A32_SHIFT 24 +-#endif ++#define SK_RGBA_R32_SHIFT 0 ++#define SK_RGBA_G32_SHIFT 8 ++#define SK_RGBA_B32_SHIFT 16 ++#define SK_RGBA_A32_SHIFT 24 + + #define SkGetPackedA32(packed) ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24) + #define SkGetPackedR32(packed) ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24) +diff --git gfx/skia/skia/include/core/SkImageInfo.h gfx/skia/skia/include/core/SkImageInfo.h +index ece47f5c418a8..5b36ba1e4518a 100644 +--- gfx/skia/skia/include/core/SkImageInfo.h ++++ gfx/skia/skia/include/core/SkImageInfo.h +@@ -84,7 +84,7 @@ enum SkColorType { + #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) + kN32_SkColorType = kRGBA_8888_SkColorType, + #else +- #error "SK_*32_SHIFT values must correspond to BGRA or RGBA byte order" ++ kN32_SkColorType = kBGRA_8888_SkColorType, + #endif + }; + +diff --git gfx/skia/skia/include/gpu/GrTypes.h gfx/skia/skia/include/gpu/GrTypes.h +index c88d9ee63b38f..fdca5f29e527b 100644 +--- gfx/skia/skia/include/gpu/GrTypes.h ++++ gfx/skia/skia/include/gpu/GrTypes.h +@@ -344,15 +344,12 @@ enum GrPixelConfig { + static const int kGrPixelConfigCnt = kLast_GrPixelConfig + 1; + + // Aliases for pixel configs that match skia's byte order. +-#ifndef SK_CPU_LENDIAN +- #error "Skia gpu currently assumes little endian" +-#endif + #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) + static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig; + #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) + static const GrPixelConfig kSkia8888_GrPixelConfig = kRGBA_8888_GrPixelConfig; + #else +- #error "SK_*32_SHIFT values must correspond to GL_BGRA or GL_RGBA format." ++ static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig; + #endif + + /** +diff --git gfx/skia/skia/src/core/SkColorData.h gfx/skia/skia/src/core/SkColorData.h +index 3fc0113105a5b..43ae01eeaee3e 100644 +--- gfx/skia/skia/src/core/SkColorData.h ++++ gfx/skia/skia/src/core/SkColorData.h +@@ -32,17 +32,10 @@ + * Here we enforce this constraint. + */ + +-#ifdef SK_CPU_BENDIAN +- #define SK_BGRA_B32_SHIFT 24 +- #define SK_BGRA_G32_SHIFT 16 +- #define SK_BGRA_R32_SHIFT 8 +- #define SK_BGRA_A32_SHIFT 0 +-#else +- #define SK_BGRA_B32_SHIFT 0 +- #define SK_BGRA_G32_SHIFT 8 +- #define SK_BGRA_R32_SHIFT 16 +- #define SK_BGRA_A32_SHIFT 24 +-#endif ++#define SK_BGRA_B32_SHIFT 0 ++#define SK_BGRA_G32_SHIFT 8 ++#define SK_BGRA_R32_SHIFT 16 ++#define SK_BGRA_A32_SHIFT 24 + + #if defined(SK_PMCOLOR_IS_RGBA) && defined(SK_PMCOLOR_IS_BGRA) + #error "can't define PMCOLOR to be RGBA and BGRA" Index: head/mail/thunderbird/files/patch-bug1288587 =================================================================== --- head/mail/thunderbird/files/patch-bug1288587 +++ head/mail/thunderbird/files/patch-bug1288587 @@ -0,0 +1,67 @@ +diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure +index 855214a..1e91d51 100644 +--- build/moz.configure/init.configure ++++ build/moz.configure/init.configure +@@ -165,16 +165,17 @@ option(env='PYTHON', nargs=1, help='Python interpreter') + # ============================================================== + @depends('PYTHON', check_build_environment, mozconfig, '--help') + @imports('os') + @imports('sys') + @imports('subprocess') + @imports(_from='mozbuild.configure.util', _import='LineIO') + @imports(_from='mozbuild.virtualenv', _import='VirtualenvManager') + @imports(_from='mozbuild.virtualenv', _import='verify_python_version') ++@imports(_from='__builtin__', _import='KeyError') + @imports('distutils.sysconfig') + def virtualenv_python(env_python, build_env, mozconfig, help): + if help: + return + + python = env_python[0] if env_python else None + + # Ideally we'd rely on the mozconfig injection from mozconfig_options, +@@ -184,16 +185,22 @@ def virtualenv_python(env_python, build_env, mozconfig, help): + if 'PYTHON' in mozconfig['env']['added']: + python = mozconfig['env']['added']['PYTHON'] + elif 'PYTHON' in mozconfig['env']['modified']: + python = mozconfig['env']['modified']['PYTHON'][1] + elif 'PYTHON' in mozconfig['vars']['added']: + python = mozconfig['vars']['added']['PYTHON'] + elif 'PYTHON' in mozconfig['vars']['modified']: + python = mozconfig['vars']['modified']['PYTHON'][1] ++ for i in ('env', 'vars'): ++ for j in ('added', 'modified'): ++ try: ++ del mozconfig[i][j]['PYTHON'] ++ except KeyError: ++ pass + + with LineIO(lambda l: log.error(l)) as out: + verify_python_version(out) + topsrcdir, topobjdir = build_env.topsrcdir, build_env.topobjdir + if topobjdir.endswith('/js/src'): + topobjdir = topobjdir[:-7] + + with LineIO(lambda l: log.info(l)) as out: +@@ -219,17 +226,20 @@ def virtualenv_python(env_python, build_env, mozconfig, help): + log.info('Creating Python environment') + manager.build(python) + + python = normsep(manager.python_path) + + if python != normsep(sys.executable): + log.info('Reexecuting in the virtualenv') + if env_python: +- del os.environ['PYTHON'] ++ try: ++ del os.environ['PYTHON'] ++ except KeyError: ++ pass + # One would prefer to use os.execl, but that's completely borked on + # Windows. + sys.exit(subprocess.call([python] + sys.argv)) + + # We are now in the virtualenv + if not distutils.sysconfig.get_python_lib(): + die('Could not determine python site packages directory') + Index: head/mail/thunderbird/files/patch-bug1375074 =================================================================== --- head/mail/thunderbird/files/patch-bug1375074 +++ head/mail/thunderbird/files/patch-bug1375074 @@ -0,0 +1,82 @@ +commit fc25eb4380d0 +Author: Lars T Hansen +Date: Wed Feb 28 13:57:52 2018 +0100 + + Bug 1375074 - Save and restore non-volatile x28 on ARM64 for generated unboxed object constructor. r=sstangl + + --HG-- + extra : rebase_source : 4a2824b23cf7453d07c962123f780c0ff2fd5292 + extra : source : dec6ab6522a4eb4b3c2defc5078b38ed904f3383 +--- + js/src/jit-test/tests/bug1375074.js | 18 ++++++++++++++++++ + js/src/vm/UnboxedObject.cpp | 25 ++++++++++++++++++++++++- + 2 files changed, 42 insertions(+), 1 deletion(-) + +diff --git js/src/jit-test/tests/bug1375074.js js/src/jit-test/tests/bug1375074.js +new file mode 100644 +index 0000000000000..8bf01d96903fc +--- /dev/null ++++ js/src/jit-test/tests/bug1375074.js +@@ -0,0 +1,18 @@ ++// This forces the VM to start creating unboxed objects and thus stresses a ++// particular path into generated code for a specialized unboxed object ++// constructor. ++ ++var K = 2000; // 2000 should be plenty ++var s = "["; ++var i; ++for ( i=0; i < K-1; i++ ) ++ s = s + `{"i":${i}},`; ++s += `{"i":${i}}]`; ++var v = JSON.parse(s); ++ ++assertEq(v.length == K, true); ++ ++for ( i=0; i < K; i++) { ++ assertEq(v[i] instanceof Object, true); ++ assertEq(v[i].i, i); ++} +diff --git js/src/vm/UnboxedObject.cpp js/src/vm/UnboxedObject.cpp +index c8c178965c488..5badf328ede4f 100644 +--- js/src/vm/UnboxedObject.cpp ++++ js/src/vm/UnboxedObject.cpp +@@ -95,7 +95,15 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) + #endif + + #ifdef JS_CODEGEN_ARM64 +- // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing. ++ // ARM64 communicates stack address via sp, but uses a pseudo-sp (PSP) for ++ // addressing. The register we use for PSP may however also be used by ++ // calling code, and it is nonvolatile, so save it. Do this as a special ++ // case first because the generic save/restore code needs the PSP to be ++ // initialized already. ++ MOZ_ASSERT(PseudoStackPointer64.Is(masm.GetStackPointer64())); ++ masm.Str(PseudoStackPointer64, vixl::MemOperand(sp, -16, vixl::PreIndex)); ++ ++ // Initialize the PSP from the SP. + masm.initStackPtr(); + #endif + +@@ -233,7 +241,22 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) + masm.pop(ScratchDoubleReg); + masm.PopRegsInMask(savedNonVolatileRegisters); + ++#ifdef JS_CODEGEN_ARM64 ++ // Now restore the value that was in the PSP register on entry, and return. ++ ++ // Obtain the correct SP from the PSP. ++ masm.Mov(sp, PseudoStackPointer64); ++ ++ // Restore the saved value of the PSP register, this value is whatever the ++ // caller had saved in it, not any actual SP value, and it must not be ++ // overwritten subsequently. ++ masm.Ldr(PseudoStackPointer64, vixl::MemOperand(sp, 16, vixl::PostIndex)); ++ ++ // Perform a plain Ret(), as abiret() will move SP <- PSP and that is wrong. ++ masm.Ret(vixl::lr); ++#else + masm.abiret(); ++#endif + + masm.bind(&failureStoreOther); + Index: head/mail/thunderbird/files/patch-bug1411481 =================================================================== --- head/mail/thunderbird/files/patch-bug1411481 +++ head/mail/thunderbird/files/patch-bug1411481 @@ -0,0 +1,85 @@ +commit 57a55d1c2d33 +Author: sotaro +Date: Wed Mar 21 08:59:38 2018 +0900 + + Bug 1411481- Enable SkiaGL canvas usage on Mac r=jrmuizel +--- + dom/canvas/CanvasRenderingContext2D.cpp | 3 ++- + gfx/thebes/gfxPlatform.cpp | 3 ++- + gfx/thebes/gfxPlatform.h | 2 +- + gfx/thebes/gfxWindowsPlatform.cpp | 7 +++++++ + gfx/thebes/gfxWindowsPlatform.h | 2 ++ + 5 files changed, 14 insertions(+), 3 deletions(-) + +diff --git dom/canvas/CanvasRenderingContext2D.cpp dom/canvas/CanvasRenderingContext2D.cpp +index ef3f868bdbf7..8666564b4d0c 100644 +--- dom/canvas/CanvasRenderingContext2D.cpp ++++ dom/canvas/CanvasRenderingContext2D.cpp +@@ -1438,7 +1438,8 @@ CanvasRenderingContext2D::AllowOpenGLCanvas() const + // HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE + // as well, so it wouldn't help much. + +- return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) && ++ return (mCompositorBackend == LayersBackend::LAYERS_OPENGL || ++ mCompositorBackend == LayersBackend::LAYERS_WR) && + gfxPlatform::GetPlatform()->AllowOpenGLCanvas(); + } + +diff --git gfx/thebes/gfxPlatform.cpp gfx/thebes/gfxPlatform.cpp +index b9beea68d8c5..82635f9ab3ce 100644 +--- gfx/thebes/gfxPlatform.cpp ++++ gfx/thebes/gfxPlatform.cpp +@@ -1386,7 +1386,8 @@ bool gfxPlatform::AllowOpenGLCanvas() + // so we let content process always assume correct compositor backend. + // The callers have to do the right thing. + bool correctBackend = !XRE_IsParentProcess() || +- ((mCompositorBackend == LayersBackend::LAYERS_OPENGL) && ++ ((mCompositorBackend == LayersBackend::LAYERS_OPENGL || ++ mCompositorBackend == LayersBackend::LAYERS_WR) && + (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA)); + + if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) { +diff --git gfx/thebes/gfxPlatform.h gfx/thebes/gfxPlatform.h +index c988eb1168a8..3bbf2b763f26 100644 +--- gfx/thebes/gfxPlatform.h ++++ gfx/thebes/gfxPlatform.h +@@ -286,7 +286,7 @@ public: + /// asking for it, we will examine the commands in the first few seconds + /// of the canvas usage, and potentially change to accelerated or + /// non-accelerated canvas. +- bool AllowOpenGLCanvas(); ++ virtual bool AllowOpenGLCanvas(); + virtual void InitializeSkiaCacheLimits(); + + static bool AsyncPanZoomEnabled(); +diff --git gfx/thebes/gfxWindowsPlatform.cpp gfx/thebes/gfxWindowsPlatform.cpp +index 9ba6f40c6cc0..4d65791d075f 100644 +--- gfx/thebes/gfxWindowsPlatform.cpp ++++ gfx/thebes/gfxWindowsPlatform.cpp +@@ -509,6 +509,13 @@ gfxWindowsPlatform::UpdateRenderMode() + } + } + ++bool ++gfxWindowsPlatform::AllowOpenGLCanvas() ++{ ++ // OpenGL canvas is not supported on windows ++ return false; ++} ++ + mozilla::gfx::BackendType + gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers) + { +diff --git gfx/thebes/gfxWindowsPlatform.h gfx/thebes/gfxWindowsPlatform.h +index 47048de8f5f5..47ec0e9e5547 100644 +--- gfx/thebes/gfxWindowsPlatform.h ++++ gfx/thebes/gfxWindowsPlatform.h +@@ -174,6 +174,8 @@ public: + void SchedulePaintIfDeviceReset() override; + void CheckForContentOnlyDeviceReset(); + ++ bool AllowOpenGLCanvas() override; ++ + mozilla::gfx::BackendType GetContentBackendFor(mozilla::layers::LayersBackend aLayers) override; + + mozilla::gfx::BackendType GetPreferredCanvasBackend() override; Index: head/mail/thunderbird/files/patch-bug1438678 =================================================================== --- head/mail/thunderbird/files/patch-bug1438678 +++ head/mail/thunderbird/files/patch-bug1438678 @@ -0,0 +1,1000 @@ +commit 68124009fc5a +Author: Nicholas Nethercote +Date: Fri Feb 16 17:54:16 2018 +1100 + + Bug 1438678 - Pass early prefs via shared memory instead of the command line. r=bobowen,jld,glandium. + + This patch replaces the large -intPrefs/-boolPrefs/-stringPrefs flags with + a short-lived, anonymous, shared memory segment that is used to pass the early + prefs. + + Removing the bloat from the command line is nice, but more important is the + fact that this will let us pass more prefs at content process start-up, which + will allow us to remove the early/late prefs split (bug 1436911). + + Although this mechanism is only used for prefs, it's conceivable that it could + be used for other data that must be received very early by children, and for + which the command line isn't ideal. + + Notable details: + + - Much of the patch deals with the various platform-specific ways of passing + handles/fds to children. + + - Linux and Mac: we use a fixed fd (8) in combination with the new + GeckoChildProcessHost::AddFdToRemap() function (which ensures the child + won't close the fd). + + - Android: like Linux and Mac, but the handles get passed via "parcels" and + we use the new SetPrefsFd() function instead of the fixed fd. + + - Windows: there is no need to duplicate the handle because Windows handles + are system-wide. But we do use the new + GeckoChildProcessHost::AddHandleToShare() function to add it to the list of + inheritable handles. We also ensure that list is processed on all paths + (MOZ_SANDBOX with sandbox, MOZ_SANDBOX without sandbox, non-MOZ_SANDBOX) so + that the handles are marked as inheritable. The handle is passed via the + -prefsHandle flag. + + The -prefsLen flag is used on all platforms to indicate the size of the + shared memory segment. + + - The patch also moves the serialization/deserialization of the prefs in/out of + the shared memory into libpref, which is a better spot for it. (This means + Preferences::MustSendToContentProcesses() can be removed.) + + MozReview-Commit-ID: 8fREEBiYFvc + + --HG-- + extra : rebase_source : 7e4c8ebdbcd7d74d6bd2ab3c9e75a6a17dbd8dfe +--- + dom/ipc/ContentParent.cpp | 91 +++++++------- + dom/ipc/ContentProcess.cpp | 121 ++++++++++--------- + dom/ipc/ContentProcess.h | 5 + + ipc/chromium/src/base/process_util_win.cc | 4 + + ipc/glue/GeckoChildProcessHost.cpp | 36 +++--- + ipc/glue/GeckoChildProcessHost.h | 10 ++ + .../org/mozilla/gecko/process/IChildProcess.aidl | 3 +- + .../main/java/org/mozilla/gecko/GeckoThread.java | 13 +- + .../org/mozilla/gecko/mozglue/GeckoLoader.java | 2 +- + .../mozilla/gecko/process/GeckoProcessManager.java | 19 +-- + .../gecko/process/GeckoServiceChildProcess.java | 4 +- + modules/libpref/Preferences.cpp | 134 +++++++++++++++++++-- + modules/libpref/Preferences.h | 17 +-- + mozglue/android/APKOpen.cpp | 4 +- + toolkit/xre/Bootstrap.cpp | 4 +- + toolkit/xre/Bootstrap.h | 2 +- + toolkit/xre/nsEmbedFunctions.cpp | 3 +- + widget/android/GeneratedJNIWrappers.cpp | 4 +- + widget/android/GeneratedJNIWrappers.h | 5 +- + xpcom/build/nsXULAppAPI.h | 2 +- + 20 files changed, 318 insertions(+), 165 deletions(-) + +diff --git dom/ipc/ContentParent.cpp dom/ipc/ContentParent.cpp +index e27f3eedc1b1..60be7005354b 100644 +--- dom/ipc/ContentParent.cpp ++++ dom/ipc/ContentParent.cpp +@@ -7,6 +7,7 @@ + #include "mozilla/DebugOnly.h" + + #include "base/basictypes.h" ++#include "base/shared_memory.h" + + #include "ContentParent.h" + #include "TabParent.h" +@@ -1998,61 +1999,56 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR + extraArgs.push_back(idStr); + extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser"); + +- nsAutoCStringN<1024> boolPrefs; +- nsAutoCStringN<1024> intPrefs; +- nsAutoCStringN<1024> stringPrefs; ++ // Prefs information is passed via anonymous shared memory to avoid bloating ++ // the command line. + +- size_t prefsLen; +- ContentPrefs::GetEarlyPrefs(&prefsLen); ++ // Serialize the early prefs. ++ nsAutoCStringN<1024> prefs; ++ Preferences::SerializeEarlyPreferences(prefs); + +- for (unsigned int i = 0; i < prefsLen; i++) { +- const char* prefName = ContentPrefs::GetEarlyPref(i); +- MOZ_ASSERT(i == 0 || strcmp(prefName, ContentPrefs::GetEarlyPref(i - 1)) > 0, +- "Content process preferences should be sorted alphabetically."); +- +- if (!Preferences::MustSendToContentProcesses(prefName)) { +- continue; +- } +- +- switch (Preferences::GetType(prefName)) { +- case nsIPrefBranch::PREF_INT: +- intPrefs.Append(nsPrintfCString("%u:%d|", i, Preferences::GetInt(prefName))); +- break; +- case nsIPrefBranch::PREF_BOOL: +- boolPrefs.Append(nsPrintfCString("%u:%d|", i, Preferences::GetBool(prefName))); +- break; +- case nsIPrefBranch::PREF_STRING: { +- nsAutoCString value; +- Preferences::GetCString(prefName, value); +- stringPrefs.Append(nsPrintfCString("%u:%d;%s|", i, value.Length(), value.get())); +- } +- break; +- case nsIPrefBranch::PREF_INVALID: +- break; +- default: +- printf("preference type: %x\n", Preferences::GetType(prefName)); +- MOZ_CRASH(); +- } ++ // Set up the shared memory. ++ base::SharedMemory shm; ++ if (!shm.Create("", /* read_only */ false, /* open_existing */ false, ++ prefs.Length())) { ++ NS_ERROR("failed to create shared memory in the parent"); ++ MarkAsDead(); ++ return false; ++ } ++ if (!shm.Map(prefs.Length())) { ++ NS_ERROR("failed to map shared memory in the parent"); ++ MarkAsDead(); ++ return false; + } + +- nsCString schedulerPrefs = Scheduler::GetPrefs(); ++ // Copy the serialized prefs into the shared memory. ++ memcpy(static_cast(shm.memory()), prefs.get(), prefs.Length()); + +- // Only do these ones if they're non-empty. +- if (!intPrefs.IsEmpty()) { +- extraArgs.push_back("-intPrefs"); +- extraArgs.push_back(intPrefs.get()); +- } +- if (!boolPrefs.IsEmpty()) { +- extraArgs.push_back("-boolPrefs"); +- extraArgs.push_back(boolPrefs.get()); +- } +- if (!stringPrefs.IsEmpty()) { +- extraArgs.push_back("-stringPrefs"); +- extraArgs.push_back(stringPrefs.get()); +- } ++#if defined(XP_WIN) ++ // Record the handle as to-be-shared, and pass it via a command flag. This ++ // works because Windows handles are system-wide. ++ HANDLE prefsHandle = shm.handle(); ++ mSubprocess->AddHandleToShare(prefsHandle); ++ extraArgs.push_back("-prefsHandle"); ++ extraArgs.push_back( ++ nsPrintfCString("%zu", reinterpret_cast(prefsHandle)).get()); ++#else ++ // In contrast, Unix fds are per-process. So remap the fd to a fixed one that ++ // will be used in the child. ++ // XXX: bug 1440207 is about improving how fixed fds are used. ++ // ++ // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel, ++ // and the fixed fd isn't used. However, we still need to mark it for ++ // remapping so it doesn't get closed in the child. ++ mSubprocess->AddFdToRemap(shm.handle().fd, kPrefsFileDescriptor); ++#endif ++ ++ // Pass the length via a command flag. ++ extraArgs.push_back("-prefsLen"); ++ extraArgs.push_back(nsPrintfCString("%zu", uintptr_t(prefs.Length())).get()); + + // Scheduler prefs need to be handled differently because the scheduler needs + // to start up in the content process before the normal preferences service. ++ nsCString schedulerPrefs = Scheduler::GetPrefs(); + extraArgs.push_back("-schedulerPrefs"); + extraArgs.push_back(schedulerPrefs.get()); + +@@ -2061,6 +2057,7 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR + } + + if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) { ++ NS_ERROR("failed to launch child in the parent"); + MarkAsDead(); + return false; + } +diff --git dom/ipc/ContentProcess.cpp dom/ipc/ContentProcess.cpp +index e3c1f16910c6..2441c8cb9224 100644 +--- dom/ipc/ContentProcess.cpp ++++ dom/ipc/ContentProcess.cpp +@@ -8,6 +8,8 @@ + + #include "ContentProcess.h" + #include "ContentPrefs.h" ++#include "base/shared_memory.h" ++#include "mozilla/Preferences.h" + #include "mozilla/Scheduler.h" + + #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX) +@@ -15,7 +17,6 @@ + #endif + + #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX) +-#include "mozilla/Preferences.h" + #include "mozilla/SandboxSettings.h" + #include "nsAppDirectoryServiceDefs.h" + #include "nsDirectoryService.h" +@@ -81,6 +82,16 @@ SetUpSandboxEnvironment() + } + #endif + ++#ifdef ANDROID ++static int gPrefsFd = -1; ++ ++void ++SetPrefsFd(int aFd) ++{ ++ gPrefsFd = aFd; ++} ++#endif ++ + bool + ContentProcess::Init(int aArgc, char* aArgv[]) + { +@@ -88,9 +99,10 @@ ContentProcess::Init(int aArgc, char* aArgv[]) + bool foundAppdir = false; + bool foundChildID = false; + bool foundIsForBrowser = false; +- bool foundIntPrefs = false; +- bool foundBoolPrefs = false; +- bool foundStringPrefs = false; ++#ifdef XP_WIN ++ bool foundPrefsHandle = false; ++#endif ++ bool foundPrefsLen = false; + bool foundSchedulerPrefs = false; + + uint64_t childID; +@@ -103,7 +115,8 @@ ContentProcess::Init(int aArgc, char* aArgv[]) + #endif + + char* schedulerPrefs = nullptr; +- InfallibleTArray prefsArray; ++ base::SharedMemoryHandle prefsHandle = base::SharedMemory::NULLHandle(); ++ size_t prefsLen = 0; + for (int idx = aArgc; idx > 0; idx--) { + if (!aArgv[idx]) { + continue; +@@ -134,54 +147,24 @@ ContentProcess::Init(int aArgc, char* aArgv[]) + } + isForBrowser = strcmp(aArgv[idx], "-notForBrowser"); + foundIsForBrowser = true; +- } else if (!strcmp(aArgv[idx], "-intPrefs")) { +- char* str = aArgv[idx + 1]; +- while (*str) { +- int32_t index = strtol(str, &str, 10); +- MOZ_ASSERT(str[0] == ':'); +- str++; +- MaybePrefValue value(PrefValue(static_cast(strtol(str, &str, 10)))); +- MOZ_ASSERT(str[0] == '|'); +- str++; +- // XXX: we assume these values as default values, which may not be +- // true. We also assume they are unlocked. Fortunately, these prefs +- // get reset properly by the first IPC message. +- Pref pref(nsCString(ContentPrefs::GetEarlyPref(index)), +- /* isLocked */ false, value, MaybePrefValue()); +- prefsArray.AppendElement(pref); +- } +- foundIntPrefs = true; +- } else if (!strcmp(aArgv[idx], "-boolPrefs")) { ++#ifdef XP_WIN ++ } else if (!strcmp(aArgv[idx], "-prefsHandle")) { + char* str = aArgv[idx + 1]; +- while (*str) { +- int32_t index = strtol(str, &str, 10); +- MOZ_ASSERT(str[0] == ':'); +- str++; +- MaybePrefValue value(PrefValue(!!strtol(str, &str, 10))); +- MOZ_ASSERT(str[0] == '|'); +- str++; +- Pref pref(nsCString(ContentPrefs::GetEarlyPref(index)), +- /* isLocked */ false, value, MaybePrefValue()); +- prefsArray.AppendElement(pref); +- } +- foundBoolPrefs = true; +- } else if (!strcmp(aArgv[idx], "-stringPrefs")) { ++ MOZ_ASSERT(str[0] != '\0'); ++ // ContentParent uses %zu to print a word-sized unsigned integer. So even ++ // though strtoull() returns a long long int, it will fit in a uintptr_t. ++ prefsHandle = reinterpret_cast(strtoull(str, &str, 10)); ++ MOZ_ASSERT(str[0] == '\0'); ++ foundPrefsHandle = true; ++#endif ++ } else if (!strcmp(aArgv[idx], "-prefsLen")) { + char* str = aArgv[idx + 1]; +- while (*str) { +- int32_t index = strtol(str, &str, 10); +- MOZ_ASSERT(str[0] == ':'); +- str++; +- int32_t length = strtol(str, &str, 10); +- MOZ_ASSERT(str[0] == ';'); +- str++; +- MaybePrefValue value(PrefValue(nsCString(str, length))); +- Pref pref(nsCString(ContentPrefs::GetEarlyPref(index)), +- /* isLocked */ false, value, MaybePrefValue()); +- prefsArray.AppendElement(pref); +- str += length + 1; +- MOZ_ASSERT(*(str - 1) == '|'); +- } +- foundStringPrefs = true; ++ MOZ_ASSERT(str[0] != '\0'); ++ // ContentParent uses %zu to print a word-sized unsigned integer. So even ++ // though strtoull() returns a long long int, it will fit in a uintptr_t. ++ prefsLen = strtoull(str, &str, 10); ++ MOZ_ASSERT(str[0] == '\0'); ++ foundPrefsLen = true; + } else if (!strcmp(aArgv[idx], "-schedulerPrefs")) { + schedulerPrefs = aArgv[idx + 1]; + foundSchedulerPrefs = true; +@@ -209,21 +192,43 @@ ContentProcess::Init(int aArgc, char* aArgv[]) + bool allFound = foundAppdir + && foundChildID + && foundIsForBrowser +- && foundIntPrefs +- && foundBoolPrefs +- && foundStringPrefs +- && foundSchedulerPrefs; +- ++ && foundPrefsLen ++ && foundSchedulerPrefs ++#ifdef XP_WIN ++ && foundPrefsHandle ++#endif + #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX) +- allFound &= foundProfile; ++ && foundProfile + #endif ++ && true; + + if (allFound) { + break; + } + } + +- Preferences::SetEarlyPreferences(&prefsArray); ++#ifdef ANDROID ++ // Android is different; get the FD via gPrefsFd instead of a fixed fd. ++ MOZ_RELEASE_ASSERT(gPrefsFd != -1); ++ prefsHandle = base::FileDescriptor(gPrefsFd, /* auto_close */ true); ++#elif XP_UNIX ++ prefsHandle = base::FileDescriptor(kPrefsFileDescriptor, ++ /* auto_close */ true); ++#endif ++ ++ // Set up early prefs from the shared memory. ++ base::SharedMemory shm; ++ if (!shm.SetHandle(prefsHandle, /* read_only */ true)) { ++ NS_ERROR("failed to open shared memory in the child"); ++ return false; ++ } ++ if (!shm.Map(prefsLen)) { ++ NS_ERROR("failed to map shared memory in the child"); ++ return false; ++ } ++ Preferences::DeserializeEarlyPreferences(static_cast(shm.memory()), ++ prefsLen); ++ + Scheduler::SetPrefs(schedulerPrefs); + mContent.Init(IOThreadChild::message_loop(), + ParentPid(), +diff --git dom/ipc/ContentProcess.h dom/ipc/ContentProcess.h +index a3854c761e10..6582c94da496 100644 +--- dom/ipc/ContentProcess.h ++++ dom/ipc/ContentProcess.h +@@ -49,6 +49,11 @@ private: + DISALLOW_EVIL_CONSTRUCTORS(ContentProcess); + }; + ++#ifdef ANDROID ++// Android doesn't use -prefsHandle, it gets that FD another way. ++void SetPrefsFd(int aFd); ++#endif ++ + } // namespace dom + } // namespace mozilla + +diff --git ipc/chromium/src/base/process_util_win.cc ipc/chromium/src/base/process_util_win.cc +index 3ed54cd744ac..46667985cd71 100644 +--- ipc/chromium/src/base/process_util_win.cc ++++ ipc/chromium/src/base/process_util_win.cc +@@ -354,6 +354,10 @@ bool LaunchApp(const std::wstring& cmdline, + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL; + std::vector handlesToInherit; + for (HANDLE h : options.handles_to_inherit) { ++ if (SetHandleInformation(h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) == 0) { ++ MOZ_DIAGNOSTIC_ASSERT(false, "SetHandleInformation failed"); ++ return false; ++ } + handlesToInherit.push_back(h); + } + +diff --git ipc/glue/GeckoChildProcessHost.cpp ipc/glue/GeckoChildProcessHost.cpp +index d18ed9edd4ca..3be1c51d10bb 100644 +--- ipc/glue/GeckoChildProcessHost.cpp ++++ ipc/glue/GeckoChildProcessHost.cpp +@@ -1030,9 +1030,6 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt + + if (!CrashReporter::IsDummy()) { + PROsfd h = PR_FileDesc2NativeHandle(crashAnnotationWritePipe); +-# if defined(MOZ_SANDBOX) +- mSandboxBroker.AddHandleToShare(reinterpret_cast(h)); +-# endif // defined(MOZ_SANDBOX) + mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast(h)); + std::string hStr = std::to_string(h); + cmdLine.AppendLooseValue(UTF8ToWide(hStr)); +@@ -1043,6 +1040,11 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt + + # if defined(MOZ_SANDBOX) + if (shouldSandboxCurrentProcess) { ++ // Mark the handles to inherit as inheritable. ++ for (HANDLE h : mLaunchOptions->handles_to_inherit) { ++ mSandboxBroker.AddHandleToShare(h); ++ } ++ + if (mSandboxBroker.LaunchApp(cmdLine.program().c_str(), + cmdLine.command_line_string().c_str(), + mLaunchOptions->env_map, +@@ -1180,7 +1182,7 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type, + const base::file_handle_mapping_vector& fds_to_remap, + ProcessHandle* process_handle) + { +- MOZ_ASSERT((fds_to_remap.size() > 0) && (fds_to_remap.size() <= 3)); ++ MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 4)); + JNIEnv* const env = mozilla::jni::GetEnvForThread(); + MOZ_ASSERT(env); + +@@ -1189,21 +1191,25 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type, + for (int ix = 0; ix < argvSize; ix++) { + jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env)); + } +- base::file_handle_mapping_vector::const_iterator it = fds_to_remap.begin(); +- int32_t ipcFd = it->first; +- it++; +- // If the Crash Reporter is disabled, there will not be a second file descriptor. ++ ++ // XXX: this processing depends entirely on the internals of ++ // ContentParent::LaunchSubprocess() ++ // GeckoChildProcessHost::PerformAsyncLaunchInternal(), and the order in ++ // which they append to fds_to_remap. There must be a better way to do it. ++ // See bug 1440207. ++ int32_t prefsFd = fds_to_remap[0].first; ++ int32_t ipcFd = fds_to_remap[1].first; + int32_t crashFd = -1; + int32_t crashAnnotationFd = -1; +- if (it != fds_to_remap.end() && !CrashReporter::IsDummy()) { +- crashFd = it->first; +- it++; ++ if (fds_to_remap.size() == 3) { ++ crashAnnotationFd = fds_to_remap[2].first; + } +- if (it != fds_to_remap.end()) { +- crashAnnotationFd = it->first; +- it++; ++ if (fds_to_remap.size() == 4) { ++ crashFd = fds_to_remap[2].first; ++ crashAnnotationFd = fds_to_remap[3].first; + } +- int32_t handle = java::GeckoProcessManager::Start(type, jargs, ipcFd, crashFd, crashAnnotationFd); ++ ++ int32_t handle = java::GeckoProcessManager::Start(type, jargs, prefsFd, ipcFd, crashFd, crashAnnotationFd); + + if (process_handle) { + *process_handle = handle; +diff --git ipc/glue/GeckoChildProcessHost.h ipc/glue/GeckoChildProcessHost.h +index 631c42066bc7..0345e221abcc 100644 +--- ipc/glue/GeckoChildProcessHost.h ++++ ipc/glue/GeckoChildProcessHost.h +@@ -103,6 +103,16 @@ public: + } + #endif + ++#ifdef XP_WIN ++ void AddHandleToShare(HANDLE aHandle) { ++ mLaunchOptions->handles_to_inherit.push_back(aHandle); ++ } ++#else ++ void AddFdToRemap(int aSrcFd, int aDstFd) { ++ mLaunchOptions->fds_to_remap.push_back(std::make_pair(aSrcFd, aDstFd)); ++ } ++#endif ++ + /** + * Must run on the IO thread. Cause the OS process to exit and + * ensure its OS resources are cleaned up. +diff --git mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl +index ba26ae1ba06b..a2535f44c72b 100644 +--- mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl ++++ mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl +@@ -12,6 +12,7 @@ import android.os.ParcelFileDescriptor; + interface IChildProcess { + int getPid(); + boolean start(in IProcessManager procMan, in String[] args, in Bundle extras, +- in ParcelFileDescriptor ipcPfd, in ParcelFileDescriptor crashReporterPfd, ++ in ParcelFileDescriptor prefsPfd, in ParcelFileDescriptor ipcPfd, ++ in ParcelFileDescriptor crashReporterPfd, + in ParcelFileDescriptor crashAnnotationPfd); + } +diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java +index dfabfd05daf0..8311920afeec 100644 +--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java ++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java +@@ -128,6 +128,7 @@ public class GeckoThread extends Thread { + public static final int FLAG_PRELOAD_CHILD = 2; // Preload child during main thread start. + + private static final String EXTRA_ARGS = "args"; ++ private static final String EXTRA_PREFS_FD = "prefsFd"; + private static final String EXTRA_IPC_FD = "ipcFd"; + private static final String EXTRA_CRASH_FD = "crashFd"; + private static final String EXTRA_CRASH_ANNOTATION_FD = "crashAnnotationFd"; +@@ -149,7 +150,8 @@ public class GeckoThread extends Thread { + + private synchronized boolean init(final GeckoProfile profile, final String[] args, + final Bundle extras, final int flags, +- final int ipcFd, final int crashFd, ++ final int prefsFd, final int ipcFd, ++ final int crashFd, + final int crashAnnotationFd) { + ThreadUtils.assertOnUiThread(); + uiThreadId = android.os.Process.myTid(); +@@ -163,6 +165,7 @@ public class GeckoThread extends Thread { + mFlags = flags; + + mExtras = (extras != null) ? new Bundle(extras) : new Bundle(3); ++ mExtras.putInt(EXTRA_PREFS_FD, prefsFd); + mExtras.putInt(EXTRA_IPC_FD, ipcFd); + mExtras.putInt(EXTRA_CRASH_FD, crashFd); + mExtras.putInt(EXTRA_CRASH_ANNOTATION_FD, crashAnnotationFd); +@@ -174,15 +177,16 @@ public class GeckoThread extends Thread { + + public static boolean initMainProcess(final GeckoProfile profile, final String[] args, + final Bundle extras, final int flags) { +- return INSTANCE.init(profile, args, extras, flags, ++ return INSTANCE.init(profile, args, extras, flags, /* fd */ -1, + /* fd */ -1, /* fd */ -1, /* fd */ -1); + } + + public static boolean initChildProcess(final String[] args, final Bundle extras, +- final int ipcFd, final int crashFd, ++ final int prefsFd, final int ipcFd, ++ final int crashFd, + final int crashAnnotationFd) { + return INSTANCE.init(/* profile */ null, args, extras, /* flags */ 0, +- ipcFd, crashFd, crashAnnotationFd); ++ prefsFd, ipcFd, crashFd, crashAnnotationFd); + } + + private static boolean canUseProfile(final Context context, final GeckoProfile profile, +@@ -442,6 +446,7 @@ public class GeckoThread extends Thread { + + // And go. + GeckoLoader.nativeRun(args, ++ mExtras.getInt(EXTRA_PREFS_FD, -1), + mExtras.getInt(EXTRA_IPC_FD, -1), + mExtras.getInt(EXTRA_CRASH_FD, -1), + mExtras.getInt(EXTRA_CRASH_ANNOTATION_FD, -1)); +diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java +index b1830fd86945..ac128b651e7b 100644 +--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java ++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java +@@ -463,7 +463,7 @@ public final class GeckoLoader { + public static native boolean verifyCRCs(String apkName); + + // These methods are implemented in mozglue/android/APKOpen.cpp +- public static native void nativeRun(String[] args, int ipcFd, int crashFd, int crashAnnotationFd); ++ public static native void nativeRun(String[] args, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd); + private static native void loadGeckoLibsNative(String apkName); + private static native void loadSQLiteLibsNative(String apkName); + private static native void loadNSSLibsNative(String apkName); +diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java +index b762e1c9a3eb..dba329ba8f92 100644 +--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java ++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java +@@ -169,14 +169,14 @@ public final class GeckoProcessManager extends IProcessManager.Stub { + + @WrapForJNI + private static int start(final String type, final String[] args, +- final int ipcFd, final int crashFd, +- final int crashAnnotationFd) { +- return INSTANCE.start(type, args, ipcFd, crashFd, crashAnnotationFd, /* retry */ false); ++ final int prefsFd, final int ipcFd, ++ final int crashFd, final int crashAnnotationFd) { ++ return INSTANCE.start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ false); + } + +- private int start(final String type, final String[] args, final int ipcFd, +- final int crashFd, final int crashAnnotationFd, +- final boolean retry) { ++ private int start(final String type, final String[] args, final int prefsFd, ++ final int ipcFd, final int crashFd, ++ final int crashAnnotationFd, final boolean retry) { + final ChildConnection connection = getConnection(type); + final IChildProcess child = connection.bind(); + if (child == null) { +@@ -184,10 +184,12 @@ public final class GeckoProcessManager extends IProcessManager.Stub { + } + + final Bundle extras = GeckoThread.getActiveExtras(); ++ final ParcelFileDescriptor prefsPfd; + final ParcelFileDescriptor ipcPfd; + final ParcelFileDescriptor crashPfd; + final ParcelFileDescriptor crashAnnotationPfd; + try { ++ prefsPfd = ParcelFileDescriptor.fromFd(prefsFd); + ipcPfd = ParcelFileDescriptor.fromFd(ipcFd); + crashPfd = (crashFd >= 0) ? ParcelFileDescriptor.fromFd(crashFd) : null; + crashAnnotationPfd = (crashAnnotationFd >= 0) ? ParcelFileDescriptor.fromFd(crashAnnotationFd) : null; +@@ -198,7 +200,8 @@ public final class GeckoProcessManager extends IProcessManager.Stub { + + boolean started = false; + try { +- started = child.start(this, args, extras, ipcPfd, crashPfd, crashAnnotationPfd); ++ started = child.start(this, args, extras, prefsPfd, ipcPfd, crashPfd, ++ crashAnnotationPfd); + } catch (final RemoteException e) { + } + +@@ -209,7 +212,7 @@ public final class GeckoProcessManager extends IProcessManager.Stub { + } + Log.w(LOGTAG, "Attempting to kill running child " + type); + connection.unbind(); +- return start(type, args, ipcFd, crashFd, crashAnnotationFd, /* retry */ true); ++ return start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ true); + } + + try { +diff --git mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java +index f1f6ce109fda..6dc19813fc10 100644 +--- mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java ++++ mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java +@@ -63,6 +63,7 @@ public class GeckoServiceChildProcess extends Service { + public boolean start(final IProcessManager procMan, + final String[] args, + final Bundle extras, ++ final ParcelFileDescriptor prefsPfd, + final ParcelFileDescriptor ipcPfd, + final ParcelFileDescriptor crashReporterPfd, + final ParcelFileDescriptor crashAnnotationPfd) { +@@ -74,6 +75,7 @@ public class GeckoServiceChildProcess extends Service { + sProcessManager = procMan; + } + ++ final int prefsFd = prefsPfd.detachFd(); + final int ipcFd = ipcPfd.detachFd(); + final int crashReporterFd = crashReporterPfd != null ? + crashReporterPfd.detachFd() : -1; +@@ -83,7 +85,7 @@ public class GeckoServiceChildProcess extends Service { + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { +- if (GeckoThread.initChildProcess(args, extras, ipcFd, crashReporterFd, ++ if (GeckoThread.initChildProcess(args, extras, prefsFd, ipcFd, crashReporterFd, + crashAnnotationFd)) { + GeckoThread.launch(); + } +diff --git modules/libpref/Preferences.cpp modules/libpref/Preferences.cpp +index 330ed4a09b54..b884591c9271 100644 +--- modules/libpref/Preferences.cpp ++++ modules/libpref/Preferences.cpp +@@ -2920,7 +2920,7 @@ public: + + } // namespace + +-// A list of prefs sent early from the parent, via the command line. ++// A list of prefs sent early from the parent, via shared memory. + static InfallibleTArray* gEarlyDomPrefs; + + /* static */ already_AddRefed +@@ -3081,11 +3081,130 @@ NS_IMPL_ISUPPORTS(Preferences, + nsISupportsWeakReference) + + /* static */ void +-Preferences::SetEarlyPreferences(const nsTArray* aDomPrefs) ++Preferences::SerializeEarlyPreferences(nsCString& aStr) ++{ ++ MOZ_RELEASE_ASSERT(InitStaticMembers()); ++ ++ nsAutoCStringN<256> boolPrefs, intPrefs, stringPrefs; ++ size_t numEarlyPrefs; ++ dom::ContentPrefs::GetEarlyPrefs(&numEarlyPrefs); ++ ++ for (unsigned int i = 0; i < numEarlyPrefs; i++) { ++ const char* prefName = dom::ContentPrefs::GetEarlyPref(i); ++ MOZ_ASSERT_IF(i > 0, ++ strcmp(prefName, dom::ContentPrefs::GetEarlyPref(i - 1)) > 0); ++ ++ Pref* pref = pref_HashTableLookup(prefName); ++ if (!pref || !pref->MustSendToContentProcesses()) { ++ continue; ++ } ++ ++ switch (pref->Type()) { ++ case PrefType::Bool: ++ boolPrefs.Append( ++ nsPrintfCString("%u:%d|", i, Preferences::GetBool(prefName))); ++ break; ++ case PrefType::Int: ++ intPrefs.Append( ++ nsPrintfCString("%u:%d|", i, Preferences::GetInt(prefName))); ++ break; ++ case PrefType::String: { ++ nsAutoCString value; ++ Preferences::GetCString(prefName, value); ++ stringPrefs.Append( ++ nsPrintfCString("%u:%d;%s|", i, value.Length(), value.get())); ++ } break; ++ case PrefType::None: ++ break; ++ default: ++ printf_stderr("preference type: %d\n", int(pref->Type())); ++ MOZ_CRASH(); ++ } ++ } ++ ++ aStr.Truncate(); ++ aStr.Append(boolPrefs); ++ aStr.Append('\n'); ++ aStr.Append(intPrefs); ++ aStr.Append('\n'); ++ aStr.Append(stringPrefs); ++ aStr.Append('\n'); ++ aStr.Append('\0'); ++} ++ ++/* static */ void ++Preferences::DeserializeEarlyPreferences(char* aStr, size_t aStrLen) + { + MOZ_ASSERT(!XRE_IsParentProcess()); + +- gEarlyDomPrefs = new InfallibleTArray(mozilla::Move(*aDomPrefs)); ++ MOZ_ASSERT(!gEarlyDomPrefs); ++ gEarlyDomPrefs = new InfallibleTArray(); ++ ++ char* p = aStr; ++ ++ // XXX: we assume these pref values are default values, which may not be ++ // true. We also assume they are unlocked. Fortunately, these prefs get reset ++ // properly by the first IPC message. ++ ++ // Get the bool prefs. ++ while (*p != '\n') { ++ int32_t index = strtol(p, &p, 10); ++ MOZ_ASSERT(p[0] == ':'); ++ p++; ++ int v = strtol(p, &p, 10); ++ MOZ_ASSERT(v == 0 || v == 1); ++ dom::MaybePrefValue value(dom::PrefValue(!!v)); ++ MOZ_ASSERT(p[0] == '|'); ++ p++; ++ dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)), ++ /* isLocked */ false, ++ value, ++ dom::MaybePrefValue()); ++ gEarlyDomPrefs->AppendElement(pref); ++ } ++ p++; ++ ++ // Get the int prefs. ++ while (*p != '\n') { ++ int32_t index = strtol(p, &p, 10); ++ MOZ_ASSERT(p[0] == ':'); ++ p++; ++ dom::MaybePrefValue value( ++ dom::PrefValue(static_cast(strtol(p, &p, 10)))); ++ MOZ_ASSERT(p[0] == '|'); ++ p++; ++ dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)), ++ /* isLocked */ false, ++ value, ++ dom::MaybePrefValue()); ++ gEarlyDomPrefs->AppendElement(pref); ++ } ++ p++; ++ ++ // Get the string prefs. ++ while (*p != '\n') { ++ int32_t index = strtol(p, &p, 10); ++ MOZ_ASSERT(p[0] == ':'); ++ p++; ++ int32_t length = strtol(p, &p, 10); ++ MOZ_ASSERT(p[0] == ';'); ++ p++; ++ dom::MaybePrefValue value(dom::PrefValue(nsCString(p, length))); ++ dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)), ++ /* isLocked */ false, ++ value, ++ dom::MaybePrefValue()); ++ gEarlyDomPrefs->AppendElement(pref); ++ p += length + 1; ++ MOZ_ASSERT(*(p - 1) == '|'); ++ } ++ p++; ++ ++ MOZ_ASSERT(*p == '\0'); ++ ++ // We finished parsing on a '\0'. That should be the last char in the shared ++ // memory. ++ MOZ_ASSERT(aStr + aStrLen - 1 == p); + + #ifdef DEBUG + MOZ_ASSERT(gPhase == ContentProcessPhase::eNoPrefsSet); +@@ -4298,15 +4417,6 @@ Preferences::HasUserValue(const char* aPrefName) + return pref && pref->HasUserValue(); + } + +-/* static */ bool +-Preferences::MustSendToContentProcesses(const char* aPrefName) +-{ +- NS_ENSURE_TRUE(InitStaticMembers(), false); +- +- Pref* pref = pref_HashTableLookup(aPrefName); +- return pref && pref->MustSendToContentProcesses(); +-} +- + /* static */ int32_t + Preferences::GetType(const char* aPrefName) + { +diff --git modules/libpref/Preferences.h modules/libpref/Preferences.h +index 1cb825ecbfe5..c149db62b525 100644 +--- modules/libpref/Preferences.h ++++ modules/libpref/Preferences.h +@@ -41,6 +41,11 @@ class PrefValue; + + struct PrefsSizes; + ++#ifdef XP_UNIX ++// XXX: bug 1440207 is about improving how fixed fds such as this are used. ++static const int kPrefsFileDescriptor = 8; ++#endif ++ + // Keep this in sync with PrefType in parser/src/lib.rs. + enum class PrefValueKind : uint8_t + { +@@ -230,9 +235,6 @@ public: + // Whether the pref has a user value or not. + static bool HasUserValue(const char* aPref); + +- // Must the pref be sent to content processes when they start? +- static bool MustSendToContentProcesses(const char* aPref); +- + // Adds/Removes the observer for the root pref branch. See nsIPrefBranch.idl + // for details. + static nsresult AddStrongObserver(nsIObserver* aObserver, const char* aPref); +@@ -328,11 +330,12 @@ public: + + // When a content process is created these methods are used to pass prefs in + // bulk from the parent process. "Early" preferences are ones that are needed +- // very early on in the content process's lifetime; they are passed via the +- // command line. "Late" preferences are the remainder, which are passed via +- // IPC message. ++ // very early on in the content process's lifetime; they are passed via a ++ // special shared memory segment. "Late" preferences are the remainder, which ++ // are passed via a standard IPC message. ++ static void SerializeEarlyPreferences(nsCString& aStr); ++ static void DeserializeEarlyPreferences(char* aStr, size_t aStrLen); + static void GetPreferences(InfallibleTArray* aSettings); +- static void SetEarlyPreferences(const nsTArray* aSettings); + static void SetLatePreferences(const nsTArray* aSettings); + + // When a single pref is changed in the parent process, these methods are +diff --git mozglue/android/APKOpen.cpp mozglue/android/APKOpen.cpp +index 5f1ef55b605e..b57192488725 100644 +--- mozglue/android/APKOpen.cpp ++++ mozglue/android/APKOpen.cpp +@@ -392,7 +392,7 @@ FreeArgv(char** argv, int argc) + } + + extern "C" APKOPEN_EXPORT void MOZ_JNICALL +-Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int ipcFd, int crashFd, int crashAnnotationFd) ++Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jobjectArray jargs, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd) + { + int argc = 0; + char** argv = CreateArgvFromObjectArray(jenv, jargs, &argc); +@@ -407,7 +407,7 @@ Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jo + gBootstrap->GeckoStart(jenv, argv, argc, sAppData); + ElfLoader::Singleton.ExpectShutdown(true); + } else { +- gBootstrap->XRE_SetAndroidChildFds(jenv, ipcFd, crashFd, crashAnnotationFd); ++ gBootstrap->XRE_SetAndroidChildFds(jenv, prefsFd, ipcFd, crashFd, crashAnnotationFd); + gBootstrap->XRE_SetProcessType(argv[argc - 1]); + + XREChildData childData; +diff --git toolkit/xre/Bootstrap.cpp toolkit/xre/Bootstrap.cpp +index 5688519822a9..7e857969a4fb 100644 +--- toolkit/xre/Bootstrap.cpp ++++ toolkit/xre/Bootstrap.cpp +@@ -78,8 +78,8 @@ public: + ::GeckoStart(aEnv, argv, argc, aAppData); + } + +- virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) override { +- ::XRE_SetAndroidChildFds(aEnv, aIPCFd, aCrashFd, aCrashAnnotationFd); ++ virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aPrefsFd, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) override { ++ ::XRE_SetAndroidChildFds(aEnv, aPrefsFd, aIPCFd, aCrashFd, aCrashAnnotationFd); + } + #endif + +diff --git toolkit/xre/Bootstrap.h toolkit/xre/Bootstrap.h +index 686d0a38e324..77adcef80e1f 100644 +--- toolkit/xre/Bootstrap.h ++++ toolkit/xre/Bootstrap.h +@@ -113,7 +113,7 @@ public: + #ifdef MOZ_WIDGET_ANDROID + virtual void GeckoStart(JNIEnv* aEnv, char** argv, int argc, const StaticXREAppData& aAppData) = 0; + +- virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) = 0; ++ virtual void XRE_SetAndroidChildFds(JNIEnv* aEnv, int aPrefsFd, int aIPCFd, int aCrashFd, int aCrashAnnotationFd) = 0; + #endif + + #ifdef LIBFUZZER +diff --git toolkit/xre/nsEmbedFunctions.cpp toolkit/xre/nsEmbedFunctions.cpp +index 53bd2bc2eb47..83184e97ba92 100644 +--- toolkit/xre/nsEmbedFunctions.cpp ++++ toolkit/xre/nsEmbedFunctions.cpp +@@ -243,9 +243,10 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default; + + #if defined(MOZ_WIDGET_ANDROID) + void +-XRE_SetAndroidChildFds (JNIEnv* env, int ipcFd, int crashFd, int crashAnnotationFd) ++XRE_SetAndroidChildFds (JNIEnv* env, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd) + { + mozilla::jni::SetGeckoThreadEnv(env); ++ mozilla::dom::SetPrefsFd(prefsFd); + IPC::Channel::SetClientChannelFd(ipcFd); + CrashReporter::SetNotificationPipeForChild(crashFd); + CrashReporter::SetCrashAnnotationPipeForChild(crashAnnotationFd); +diff --git widget/android/GeneratedJNIWrappers.cpp widget/android/GeneratedJNIWrappers.cpp +index e3f6af0cc575..4165df59f0e8 100644 +--- widget/android/GeneratedJNIWrappers.cpp ++++ widget/android/GeneratedJNIWrappers.cpp +@@ -2355,9 +2355,9 @@ constexpr char GeckoProcessManager::GetEditableParent_t::signature[]; + constexpr char GeckoProcessManager::Start_t::name[]; + constexpr char GeckoProcessManager::Start_t::signature[]; + +-auto GeckoProcessManager::Start(mozilla::jni::String::Param a0, mozilla::jni::ObjectArray::Param a1, int32_t a2, int32_t a3, int32_t a4) -> int32_t ++auto GeckoProcessManager::Start(mozilla::jni::String::Param a0, mozilla::jni::ObjectArray::Param a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5) -> int32_t + { +- return mozilla::jni::Method::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3, a4); ++ return mozilla::jni::Method::Call(GeckoProcessManager::Context(), nullptr, a0, a1, a2, a3, a4, a5); + } + + const char GeckoServiceChildProcess::name[] = +diff --git widget/android/GeneratedJNIWrappers.h widget/android/GeneratedJNIWrappers.h +index ece79ac94a71..228affa1e550 100644 +--- widget/android/GeneratedJNIWrappers.h ++++ widget/android/GeneratedJNIWrappers.h +@@ -6696,10 +6696,11 @@ public: + mozilla::jni::ObjectArray::Param, + int32_t, + int32_t, ++ int32_t, + int32_t> Args; + static constexpr char name[] = "start"; + static constexpr char signature[] = +- "(Ljava/lang/String;[Ljava/lang/String;III)I"; ++ "(Ljava/lang/String;[Ljava/lang/String;IIII)I"; + static const bool isStatic = true; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; +@@ -6709,7 +6710,7 @@ public: + mozilla::jni::DispatchTarget::CURRENT; + }; + +- static auto Start(mozilla::jni::String::Param, mozilla::jni::ObjectArray::Param, int32_t, int32_t, int32_t) -> int32_t; ++ static auto Start(mozilla::jni::String::Param, mozilla::jni::ObjectArray::Param, int32_t, int32_t, int32_t, int32_t) -> int32_t; + + static const mozilla::jni::CallingThread callingThread = + mozilla::jni::CallingThread::ANY; +diff --git xpcom/build/nsXULAppAPI.h xpcom/build/nsXULAppAPI.h +index 94f6daf864c9..d6ac10d51d76 100644 +--- xpcom/build/nsXULAppAPI.h ++++ xpcom/build/nsXULAppAPI.h +@@ -398,7 +398,7 @@ XRE_API(const char*, + + #if defined(MOZ_WIDGET_ANDROID) + XRE_API(void, +- XRE_SetAndroidChildFds, (JNIEnv* env, int ipcFd, int crashFd, int crashAnnotationFd)) ++ XRE_SetAndroidChildFds, (JNIEnv* env, int prefsFd, int ipcFd, int crashFd, int crashAnnotationFd)) + #endif // defined(MOZ_WIDGET_ANDROID) + + XRE_API(void, Index: head/mail/thunderbird/files/patch-bug1442583 =================================================================== --- head/mail/thunderbird/files/patch-bug1442583 +++ head/mail/thunderbird/files/patch-bug1442583 @@ -0,0 +1,39 @@ +commit 7371a080accd +Author: Lars T Hansen +Date: Mon Mar 5 09:55:28 2018 +0100 + + Bug 1442583 - Properly initialize ARM64 icache flushing machinery. r=sstangl + + --HG-- + extra : rebase_source : 73b5921da1fa0a19d6072e35d09bd7b528bb6bfc + extra : intermediate-source : 19516efbbf6750ba04e11c7099586d5be2fe818f + extra : source : 4316cc82d6302edf839a4af6fcb815f0ffa9f65c +--- + js/src/jit/ProcessExecutableMemory.cpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git js/src/jit/ProcessExecutableMemory.cpp js/src/jit/ProcessExecutableMemory.cpp +index e763a9d68dc17..8a6d50b6a7845 100644 +--- js/src/jit/ProcessExecutableMemory.cpp ++++ js/src/jit/ProcessExecutableMemory.cpp +@@ -20,6 +20,9 @@ + #include "jsutil.h" + + #include "gc/Memory.h" ++#ifdef JS_CODEGEN_ARM64 ++# include "jit/arm64/vixl/Cpu-vixl.h" ++#endif + #include "threading/LockGuard.h" + #include "threading/Mutex.h" + #include "util/Windows.h" +@@ -621,6 +624,10 @@ js::jit::DeallocateExecutableMemory(void* addr, size_t bytes) + bool + js::jit::InitProcessExecutableMemory() + { ++#ifdef JS_CODEGEN_ARM64 ++ // Initialize instruction cache flushing. ++ vixl::CPU::SetUp(); ++#endif + return execMemory.init(); + } + Index: head/mail/thunderbird/files/patch-bug1444798 =================================================================== --- head/mail/thunderbird/files/patch-bug1444798 +++ head/mail/thunderbird/files/patch-bug1444798 @@ -0,0 +1,45 @@ +commit 7871e211ec43 +Author: sotaro +Date: Fri Mar 16 21:03:59 2018 +0900 + + Bug 1444798 - Fix ExternalImageCallback func types r=jrmuizel +--- + gfx/webrender_bindings/src/bindings.rs | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git gfx/webrender_bindings/src/bindings.rs gfx/webrender_bindings/src/bindings.rs +index 8517d7dd33e5..cf885ee713f3 100644 +--- gfx/webrender_bindings/src/bindings.rs ++++ gfx/webrender_bindings/src/bindings.rs +@@ -312,8 +312,8 @@ struct WrExternalImage { + size: usize, + } + +-type LockExternalImageCallback = fn(*mut c_void, WrExternalImageId, u8) -> WrExternalImage; +-type UnlockExternalImageCallback = fn(*mut c_void, WrExternalImageId, u8); ++type LockExternalImageCallback = unsafe extern "C" fn(*mut c_void, WrExternalImageId, u8) -> WrExternalImage; ++type UnlockExternalImageCallback = unsafe extern "C" fn(*mut c_void, WrExternalImageId, u8); + + #[repr(C)] + pub struct WrExternalImageHandler { +@@ -327,7 +327,8 @@ impl ExternalImageHandler for WrExternalImageHandler { + id: ExternalImageId, + channel_index: u8) + -> ExternalImage { +- let image = (self.lock_func)(self.external_image_obj, id.into(), channel_index); ++ ++ let image = unsafe { (self.lock_func)(self.external_image_obj, id.into(), channel_index) }; + ExternalImage { + uv: TexelRect::new(image.u0, image.v0, image.u1, image.v1), + source: match image.image_type { +@@ -341,7 +342,9 @@ impl ExternalImageHandler for WrExternalImageHandler { + fn unlock(&mut self, + id: ExternalImageId, + channel_index: u8) { +- (self.unlock_func)(self.external_image_obj, id.into(), channel_index); ++ unsafe { ++ (self.unlock_func)(self.external_image_obj, id.into(), channel_index); ++ } + } + } + Index: head/mail/thunderbird/files/patch-bug1445907 =================================================================== --- head/mail/thunderbird/files/patch-bug1445907 +++ head/mail/thunderbird/files/patch-bug1445907 @@ -0,0 +1,75 @@ +commit 0c6dd4a750db +Author: Lars T Hansen +Date: Mon Mar 19 09:58:06 2018 +0100 + + Bug 1445907 - Save x28 before clobbering it in the regex compiler. r=sstangl +--- + js/src/irregexp/NativeRegExpMacroAssembler.cpp | 25 ++++++++++++++++++++++++- + js/src/jit-test/tests/regexp/bug1445907.js | 15 +++++++++++++++ + 2 files changed, 39 insertions(+), 1 deletion(-) + +diff --git js/src/irregexp/NativeRegExpMacroAssembler.cpp js/src/irregexp/NativeRegExpMacroAssembler.cpp +index 28a4c35e75bfe..c08b005cf856b 100644 +--- js/src/irregexp/NativeRegExpMacroAssembler.cpp ++++ js/src/irregexp/NativeRegExpMacroAssembler.cpp +@@ -123,7 +123,15 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only) + masm.bind(&entry_label_); + + #ifdef JS_CODEGEN_ARM64 +- // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing. ++ // ARM64 communicates stack address via SP, but uses a pseudo-sp (PSP) for ++ // addressing. The register we use for PSP may however also be used by ++ // calling code, and it is nonvolatile, so save it. Do this as a special ++ // case first because the generic save/restore code needs the PSP to be ++ // initialized already. ++ MOZ_ASSERT(PseudoStackPointer64.Is(masm.GetStackPointer64())); ++ masm.Str(PseudoStackPointer64, vixl::MemOperand(sp, -16, vixl::PreIndex)); ++ ++ // Initialize the PSP from the SP. + masm.initStackPtr(); + #endif + +@@ -421,7 +429,22 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only) + for (GeneralRegisterBackwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter) + masm.Pop(*iter); + ++#ifdef JS_CODEGEN_ARM64 ++ // Now restore the value that was in the PSP register on entry, and return. ++ ++ // Obtain the correct SP from the PSP. ++ masm.Mov(sp, PseudoStackPointer64); ++ ++ // Restore the saved value of the PSP register, this value is whatever the ++ // caller had saved in it, not any actual SP value, and it must not be ++ // overwritten subsequently. ++ masm.Ldr(PseudoStackPointer64, vixl::MemOperand(sp, 16, vixl::PostIndex)); ++ ++ // Perform a plain Ret(), as abiret() will move SP <- PSP and that is wrong. ++ masm.Ret(vixl::lr); ++#else + masm.abiret(); ++#endif + + // Backtrack code (branch target for conditional backtracks). + if (backtrack_label_.used()) { +diff --git js/src/jit-test/tests/regexp/bug1445907.js js/src/jit-test/tests/regexp/bug1445907.js +new file mode 100644 +index 0000000000000..75b23753eaf93 +--- /dev/null ++++ js/src/jit-test/tests/regexp/bug1445907.js +@@ -0,0 +1,15 @@ ++// On ARM64, we failed to save x28 properly when generating code for the regexp ++// matcher. ++// ++// There's wasm and Debugger code here because the combination forces the use of ++// x28 and exposes the bug when running on the simulator. ++ ++if (!wasmIsSupported()) ++ quit(); ++ ++var g = newGlobal(''); ++var dbg = new Debugger(g); ++g.eval(`var m = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func (export "test")))')))`); ++var re = /./; ++dbg.onEnterFrame = function(frame) { re.exec("x") }; ++result = g.eval("m.exports.test()"); Index: head/mail/thunderbird/files/patch-bug1447359 =================================================================== --- head/mail/thunderbird/files/patch-bug1447359 +++ head/mail/thunderbird/files/patch-bug1447359 @@ -0,0 +1,45 @@ +commit fef467b5a93d +Author: Luke Wagner +Date: Thu Mar 22 10:28:13 2018 -0500 + + Bug 1447359 - Baldr: add AutoForbidPools in a few missing places (r=lth) + + --HG-- + extra : rebase_source : 75f1909deb352391529ce5e58a89e5f9cfeb3662 +--- + js/src/jit/arm64/MacroAssembler-arm64-inl.h | 1 + + js/src/jit/arm64/MacroAssembler-arm64.cpp | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git js/src/jit/arm64/MacroAssembler-arm64-inl.h js/src/jit/arm64/MacroAssembler-arm64-inl.h +index 7061cbfd93ebb..190442f7afa0a 100644 +--- js/src/jit/arm64/MacroAssembler-arm64-inl.h ++++ js/src/jit/arm64/MacroAssembler-arm64-inl.h +@@ -359,6 +359,7 @@ MacroAssembler::sub32FromStackPtrWithPatch(Register dest) + { + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch = temps.AcquireX(); ++ AutoForbidPools afp(this, /* max number of instructions in scope = */ 3); + CodeOffset offs = CodeOffset(currentOffset()); + movz(scratch, 0, 0); + movk(scratch, 0, 16); +diff --git js/src/jit/arm64/MacroAssembler-arm64.cpp js/src/jit/arm64/MacroAssembler-arm64.cpp +index 7b599b7e9d610..4e8fdb6a67019 100644 +--- js/src/jit/arm64/MacroAssembler-arm64.cpp ++++ js/src/jit/arm64/MacroAssembler-arm64.cpp +@@ -707,6 +707,7 @@ MacroAssembler::patchFarJump(CodeOffset farJump, uint32_t targetOffset) + CodeOffset + MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc) + { ++ AutoForbidPools afp(this, /* max number of instructions in scope = */ 1); + CodeOffset offset(currentOffset()); + Nop(); + append(desc, CodeOffset(currentOffset())); +@@ -1077,6 +1078,7 @@ MacroAssembler::comment(const char* msg) + CodeOffset + MacroAssembler::wasmTrapInstruction() + { ++ AutoForbidPools afp(this, /* max number of instructions in scope = */ 1); + CodeOffset offs(currentOffset()); + Unreachable(); + return offs; Index: head/mail/thunderbird/files/patch-bug1447519 =================================================================== --- head/mail/thunderbird/files/patch-bug1447519 +++ head/mail/thunderbird/files/patch-bug1447519 @@ -0,0 +1,22 @@ +Enable SkiaGL by default on OpenGL compositing platforms + +diff --git modules/libpref/init/all.js modules/libpref/init/all.js +index 93e56b00a961..61a2174c3384 100644 +--- modules/libpref/init/all.js ++++ modules/libpref/init/all.js +@@ -882,15 +882,9 @@ pref("gfx.font_rendering.opentype_svg.enabled", true); + pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo"); + pref("gfx.content.azure.backends", "direct2d1.1,skia,cairo"); + #else +-#ifdef XP_MACOSX + pref("gfx.content.azure.backends", "skia"); + pref("gfx.canvas.azure.backends", "skia"); +-// Accelerated cg canvas where available (10.7+) + pref("gfx.canvas.azure.accelerated", true); +-#else +-pref("gfx.canvas.azure.backends", "skia"); +-pref("gfx.content.azure.backends", "skia"); +-#endif + #endif + + pref("gfx.canvas.skiagl.dynamic-cache", true); Index: head/mail/thunderbird/files/patch-bug1448770 =================================================================== --- head/mail/thunderbird/files/patch-bug1448770 +++ head/mail/thunderbird/files/patch-bug1448770 @@ -0,0 +1,27 @@ +Disable GL_EXT_debug_marker due to crashes on x86 with Mesa drivers. + +diff --git gfx/webrender/src/query.rs gfx/webrender/src/query.rs +index 999abc749115..68850ef025e4 100644 +--- gfx/webrender/src/query.rs ++++ gfx/webrender/src/query.rs +@@ -274,17 +274,20 @@ pub struct GpuMarker { + + impl GpuMarker { + fn new(gl: &Rc, message: &str) -> Self { ++#[cfg(not(target_arch = "x86"))] + gl.push_group_marker_ext(message); + GpuMarker { gl: Rc::clone(gl) } + } + + fn fire(gl: &Rc, message: &str) { ++#[cfg(not(target_arch = "x86"))] + gl.insert_event_marker_ext(message); + } + } + + impl Drop for GpuMarker { + fn drop(&mut self) { ++#[cfg(not(target_arch = "x86"))] + self.gl.pop_group_marker_ext(); + } + } Index: head/mail/thunderbird/files/patch-bug1451292 =================================================================== --- head/mail/thunderbird/files/patch-bug1451292 +++ head/mail/thunderbird/files/patch-bug1451292 @@ -0,0 +1,33 @@ +commit b3a02fddbce8 +Author: Lars T Hansen +Date: Wed Apr 4 15:48:48 2018 +0200 + + Bug 1451292 - Better payload for arm64 breakpoint instruction. r=sstangl + + At least some non-zero payloads confuse GDB and make it iloop on the + breakpoint instruction rather than break to the command line as it + should. There seems to be no reason not to use a zero payload. + + --HG-- + extra : rebase_source : 6d6f9aa2911b86b02572f88948d48bc2238c6353 + extra : amend_source : 9fed9235d481a9eadafc4a3e0075c9fef8b6050d +--- + js/src/jit/arm64/MacroAssembler-arm64.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git js/src/jit/arm64/MacroAssembler-arm64.cpp js/src/jit/arm64/MacroAssembler-arm64.cpp +index 4ea64b1225d00..a212de0ec2f45 100644 +--- js/src/jit/arm64/MacroAssembler-arm64.cpp ++++ js/src/jit/arm64/MacroAssembler-arm64.cpp +@@ -237,8 +237,9 @@ MacroAssemblerCompat::profilerEnterFrame(RegisterOrSP framePtr, Register scratch + void + MacroAssemblerCompat::breakpoint() + { +- static int code = 0xA77; +- Brk((code++) & 0xffff); ++ // Note, other payloads are possible, but GDB is known to misinterpret them ++ // sometimes and iloop on the breakpoint instead of stopping properly. ++ Brk(0); + } + + // Either `any` is valid or `sixtyfour` is valid. Return a 32-bit ARMRegister Index: head/mail/thunderbird/files/patch-bug1456556 =================================================================== --- head/mail/thunderbird/files/patch-bug1456556 +++ head/mail/thunderbird/files/patch-bug1456556 @@ -0,0 +1,22 @@ +commit f6fc0b418aa3 +Author: Andrea Marchesini +Date: Tue May 1 08:47:13 2018 +0200 + + Bug 1456556 - FetchConsumer scope-exit RAII must grab 'self' by value, r=erahm +--- + dom/fetch/FetchConsumer.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git dom/fetch/FetchConsumer.cpp dom/fetch/FetchConsumer.cpp +index 134bf7f2e703a..3c3687fea1d5a 100644 +--- dom/fetch/FetchConsumer.cpp ++++ dom/fetch/FetchConsumer.cpp +@@ -582,7 +582,7 @@ FetchBodyConsumer::ContinueConsumeBody(nsresult aStatus, + RefPtr localPromise = mConsumePromise.forget(); + + RefPtr> self = this; +- auto autoReleaseObject = mozilla::MakeScopeExit([&] { ++ auto autoReleaseObject = mozilla::MakeScopeExit([self] { + self->ReleaseObject(); + }); + Index: head/mail/thunderbird/files/patch-bug1467882 =================================================================== --- head/mail/thunderbird/files/patch-bug1467882 +++ head/mail/thunderbird/files/patch-bug1467882 @@ -0,0 +1,137 @@ + +# HG changeset patch +# User Alex Chronopoulos +# Date 1528999505 25200 +# Node ID 0e40938905915ec04bbbccb4f093182a6785ac3a +# Parent a75f33744de61543dc840cbb0324fedf997c3931 +Bug 1467882 - Update cubeb from upstream to 0677b30. r=kinetik + +diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA +--- media/libcubeb/README_MOZILLA ++++ media/libcubeb/README_MOZILLA +@@ -1,8 +1,8 @@ + The source from this directory was copied from the cubeb + git repository using the update.sh script. The only changes + made were those applied by update.sh and the addition of + Makefile.in build files for the Mozilla build system. + + The cubeb git repository is: git://github.com/kinetiknz/cubeb.git + +-The git commit ID used was abf6ae235b0f15a2656f2d8692ac13708188165e (2018-06-01 13:02:45 +1200) ++The git commit ID used was 0677b3027b78c629586b099b5155aa6ac7422674 (2018-06-12 08:48:55 -0700) +diff --git a/media/libcubeb/src/cubeb_sndio.c b/media/libcubeb/src/cubeb_sndio.c +--- media/libcubeb/src/cubeb_sndio.c ++++ media/libcubeb/src/cubeb_sndio.c +@@ -46,27 +46,43 @@ struct cubeb_stream { + unsigned int pbpf; /* play bytes per frame */ + unsigned int rchan; /* number of rec channels */ + unsigned int pchan; /* number of play channels */ + unsigned int nblks; /* number of blocks in the buffer */ + uint64_t hwpos; /* frame number Joe hears right now */ + uint64_t swpos; /* number of frames produced/consumed */ + cubeb_data_callback data_cb; /* cb to preapare data */ + cubeb_state_callback state_cb; /* cb to notify about state changes */ ++ float volume; /* current volume */ + }; + + static void +-float_to_s16(void *ptr, long nsamp) ++s16_setvol(void *ptr, long nsamp, float volume) ++{ ++ int16_t *dst = ptr; ++ int32_t mult = volume * 32768; ++ int32_t s; ++ ++ while (nsamp-- > 0) { ++ s = *dst; ++ s = (s * mult) >> 15; ++ *(dst++) = s; ++ } ++} ++ ++static void ++float_to_s16(void *ptr, long nsamp, float volume) + { + int16_t *dst = ptr; + float *src = ptr; ++ float mult = volume * 32768; + int s; + + while (nsamp-- > 0) { +- s = lrintf(*(src++) * 32768); ++ s = lrintf(*(src++) * mult); + if (s < -32768) + s = -32768; + else if (s > 32767) + s = 32767; + *(dst++) = s; + } + } + +@@ -164,18 +180,22 @@ sndio_mainloop(void *arg) + /* need to write (aka drain) the partial play block we got */ + pend = nfr * s->pbpf; + eof = 1; + } + + if (prime > 0) + prime--; + +- if ((s->mode & SIO_PLAY) && s->conv) +- float_to_s16(s->pbuf, nfr * s->pchan); ++ if (s->mode & SIO_PLAY) { ++ if (s->conv) ++ float_to_s16(s->pbuf, nfr * s->pchan, s->volume); ++ else ++ s16_setvol(s->pbuf, nfr * s->pchan, s->volume); ++ } + + if (s->mode & SIO_REC) + rstart = 0; + if (s->mode & SIO_PLAY) + pstart = 0; + } + + events = 0; +@@ -367,16 +387,17 @@ sndio_stream_init(cubeb * context, + if (s->pbuf == NULL) + goto err; + } + if (s->mode & SIO_REC) { + s->rbuf = malloc(bps * rpar.rchan * rpar.round); + if (s->rbuf == NULL) + goto err; + } ++ s->volume = 1.; + *stream = s; + DPR("sndio_stream_init() end, ok\n"); + (void)context; + (void)stream_name; + return CUBEB_OK; + err: + if (s->hdl) + sio_close(s->hdl); +@@ -471,17 +492,21 @@ sndio_stream_get_position(cubeb_stream * + return CUBEB_OK; + } + + static int + sndio_stream_set_volume(cubeb_stream *s, float volume) + { + DPR("sndio_stream_set_volume(%f)\n", volume); + pthread_mutex_lock(&s->mtx); +- sio_setvol(s->hdl, SIO_MAXVOL * volume); ++ if (volume < 0.) ++ volume = 0.; ++ else if (volume > 1.0) ++ volume = 1.; ++ s->volume = volume; + pthread_mutex_unlock(&s->mtx); + return CUBEB_OK; + } + + int + sndio_stream_get_latency(cubeb_stream * stm, uint32_t * latency) + { + // http://www.openbsd.org/cgi-bin/man.cgi?query=sio_open + Index: head/mail/thunderbird/files/patch-bug292127 =================================================================== --- head/mail/thunderbird/files/patch-bug292127 +++ head/mail/thunderbird/files/patch-bug292127 @@ -0,0 +1,232 @@ +--- comm/ldap/c-sdk/include/ldap.h~ ++++ comm/ldap/c-sdk/include/ldap.h +@@ -40,6 +40,229 @@ + #ifndef _LDAP_H + #define _LDAP_H + ++/* rename symbols to not clash with openldap (bug 292127) */ ++#define ldap_abandon moz_ldap_abandon ++#define ldap_abandon_ext moz_ldap_abandon_ext ++#define ldap_abandoned moz_ldap_abandoned ++#define ldap_add moz_ldap_add ++#define ldap_add_ext moz_ldap_add_ext ++#define ldap_add_ext_s moz_ldap_add_ext_s ++#define ldap_add_result_entry moz_ldap_add_result_entry ++#define ldap_add_s moz_ldap_add_s ++#define ldap_ber_free moz_ldap_ber_free ++#define ldap_bind moz_ldap_bind ++#define ldap_bind_s moz_ldap_bind_s ++#define ldap_build_filter moz_ldap_build_filter ++#define ldap_cache_flush moz_ldap_cache_flush ++#define ldap_charray_add moz_ldap_charray_add ++#define ldap_charray_dup moz_ldap_charray_dup ++#define ldap_charray_free moz_ldap_charray_free ++#define ldap_charray_inlist moz_ldap_charray_inlist ++#define ldap_charray_merge moz_ldap_charray_merge ++#define ldap_charray_position moz_ldap_charray_position ++#define ldap_compare moz_ldap_compare ++#define ldap_compare_ext moz_ldap_compare_ext ++#define ldap_compare_ext_s moz_ldap_compare_ext_s ++#define ldap_compare_s moz_ldap_compare_s ++#define ldap_control_free moz_ldap_control_free ++#define ldap_controls_free moz_ldap_controls_free ++#define ldap_count_entries moz_ldap_count_entries ++#define ldap_count_messages moz_ldap_count_messages ++#define ldap_count_references moz_ldap_count_references ++#define ldap_count_values moz_ldap_count_values ++#define ldap_count_values_len moz_ldap_count_values_len ++#define ldap_create_authzid_control moz_ldap_create_authzid_control ++#define ldap_create_filter moz_ldap_create_filter ++#define ldap_create_geteffectiveRights_control moz_ldap_create_geteffectiveRights_control ++#define ldap_create_passwordpolicy_control moz_ldap_create_passwordpolicy_control ++#define ldap_create_passwordpolicy_control_ext moz_ldap_create_passwordpolicy_control_ext ++#define ldap_create_persistentsearch_control moz_ldap_create_persistentsearch_control ++#define ldap_create_proxiedauth_control moz_ldap_create_proxiedauth_control ++#define ldap_create_proxyauth_control moz_ldap_create_proxyauth_control ++#define ldap_create_sort_control moz_ldap_create_sort_control ++#define ldap_create_sort_keylist moz_ldap_create_sort_keylist ++#define ldap_create_userstatus_control moz_ldap_create_userstatus_control ++#define ldap_create_virtuallist_control moz_ldap_create_virtuallist_control ++#define ldap_delete moz_ldap_delete ++#define ldap_delete_ext moz_ldap_delete_ext ++#define ldap_delete_ext_s moz_ldap_delete_ext_s ++#define ldap_delete_result_entry moz_ldap_delete_result_entry ++#define ldap_delete_s moz_ldap_delete_s ++#define ldap_dn2ufn moz_ldap_dn2ufn ++#define ldap_entry2html moz_ldap_entry2html ++#define ldap_entry2html_search moz_ldap_entry2html_search ++#define ldap_entry2text moz_ldap_entry2text ++#define ldap_entry2text_search moz_ldap_entry2text_search ++#define ldap_err2string moz_ldap_err2string ++#define ldap_errlist moz_ldap_errlist ++#define ldap_explode moz_ldap_explode ++#define ldap_explode_dn moz_ldap_explode_dn ++#define ldap_explode_dns moz_ldap_explode_dns ++#define ldap_explode_rdn moz_ldap_explode_rdn ++#define ldap_extended_operation moz_ldap_extended_operation ++#define ldap_extended_operation_s moz_ldap_extended_operation_s ++#define ldap_find_control moz_ldap_find_control ++#define ldap_first_attribute moz_ldap_first_attribute ++#define ldap_first_disptmpl moz_ldap_first_disptmpl ++#define ldap_first_entry moz_ldap_first_entry ++#define ldap_first_message moz_ldap_first_message ++#define ldap_first_reference moz_ldap_first_reference ++#define ldap_first_searchobj moz_ldap_first_searchobj ++#define ldap_first_tmplcol moz_ldap_first_tmplcol ++#define ldap_first_tmplrow moz_ldap_first_tmplrow ++#define ldap_free_friendlymap moz_ldap_free_friendlymap ++#define ldap_free_searchprefs moz_ldap_free_searchprefs ++#define ldap_free_sort_keylist moz_ldap_free_sort_keylist ++#define ldap_free_templates moz_ldap_free_templates ++#define ldap_free_urldesc moz_ldap_free_urldesc ++#define ldap_friendly_name moz_ldap_friendly_name ++#define ldap_get_dn moz_ldap_get_dn ++#define ldap_get_entry_controls moz_ldap_get_entry_controls ++#define ldap_get_lang_values moz_ldap_get_lang_values ++#define ldap_get_lang_values_len moz_ldap_get_lang_values_len ++#define ldap_get_lderrno moz_ldap_get_lderrno ++#define ldap_get_option moz_ldap_get_option ++#define ldap_get_values moz_ldap_get_values ++#define ldap_get_values_len moz_ldap_get_values_len ++#define ldap_getfilter_free moz_ldap_getfilter_free ++#define ldap_getfirstfilter moz_ldap_getfirstfilter ++#define ldap_getnextfilter moz_ldap_getnextfilter ++#define ldap_init moz_ldap_init ++#define ldap_init_getfilter moz_ldap_init_getfilter ++#define ldap_init_getfilter_buf moz_ldap_init_getfilter_buf ++#define ldap_init_searchprefs moz_ldap_init_searchprefs ++#define ldap_init_searchprefs_buf moz_ldap_init_searchprefs_buf ++#define ldap_init_templates moz_ldap_init_templates ++#define ldap_init_templates_buf moz_ldap_init_templates_buf ++#define ldap_is_dns_dn moz_ldap_is_dns_dn ++#define ldap_is_ldap_url moz_ldap_is_ldap_url ++#define ldap_keysort_entries moz_ldap_keysort_entries ++#define ldap_ld_free moz_ldap_ld_free ++#define ldap_memcache_abandon moz_ldap_memcache_abandon ++#define ldap_memcache_append moz_ldap_memcache_append ++#define ldap_memcache_createkey moz_ldap_memcache_createkey ++#define ldap_memcache_destroy moz_ldap_memcache_destroy ++#define ldap_memcache_flush moz_ldap_memcache_flush ++#define ldap_memcache_flush_results moz_ldap_memcache_flush_results ++#define ldap_memcache_get moz_ldap_memcache_get ++#define ldap_memcache_init moz_ldap_memcache_init ++#define ldap_memcache_new moz_ldap_memcache_new ++#define ldap_memcache_result moz_ldap_memcache_result ++#define ldap_memcache_set moz_ldap_memcache_set ++#define ldap_memcache_update moz_ldap_memcache_update ++#define ldap_memfree moz_ldap_memfree ++#define ldap_modify moz_ldap_modify ++#define ldap_modify_ext moz_ldap_modify_ext ++#define ldap_modify_ext_s moz_ldap_modify_ext_s ++#define ldap_modify_s moz_ldap_modify_s ++#define ldap_modrdn moz_ldap_modrdn ++#define ldap_modrdn2 moz_ldap_modrdn2 ++#define ldap_modrdn2_s moz_ldap_modrdn2_s ++#define ldap_modrdn_s moz_ldap_modrdn_s ++#define ldap_mods_free moz_ldap_mods_free ++#define ldap_msgdelete moz_ldap_msgdelete ++#define ldap_msgfree moz_ldap_msgfree ++#define ldap_msgid moz_ldap_msgid ++#define ldap_msgtype moz_ldap_msgtype ++#define ldap_multisort_entries moz_ldap_multisort_entries ++#define ldap_name2template moz_ldap_name2template ++#define ldap_next_attribute moz_ldap_next_attribute ++#define ldap_next_disptmpl moz_ldap_next_disptmpl ++#define ldap_next_entry moz_ldap_next_entry ++#define ldap_next_message moz_ldap_next_message ++#define ldap_next_reference moz_ldap_next_reference ++#define ldap_next_searchobj moz_ldap_next_searchobj ++#define ldap_next_tmplcol moz_ldap_next_tmplcol ++#define ldap_next_tmplrow moz_ldap_next_tmplrow ++#define ldap_oc2template moz_ldap_oc2template ++#define ldap_open moz_ldap_open ++#define ldap_parse_authzid_control moz_ldap_parse_authzid_control ++#define ldap_parse_entrychange_control moz_ldap_parse_entrychange_control ++#define ldap_parse_extended_result moz_ldap_parse_extended_result ++#define ldap_parse_passwd moz_ldap_parse_passwd ++#define ldap_parse_passwordpolicy_control moz_ldap_parse_passwordpolicy_control ++#define ldap_parse_passwordpolicy_control_ext moz_ldap_parse_passwordpolicy_control_ext ++#define ldap_parse_reference moz_ldap_parse_reference ++#define ldap_parse_result moz_ldap_parse_result ++#define ldap_parse_sasl_bind_result moz_ldap_parse_sasl_bind_result ++#define ldap_parse_sort_control moz_ldap_parse_sort_control ++#define ldap_parse_userstatus_control moz_ldap_parse_userstatus_control ++#define ldap_parse_virtuallist_control moz_ldap_parse_virtuallist_control ++#define ldap_parse_whoami moz_ldap_parse_whoami ++#define ldap_passwd moz_ldap_passwd ++#define ldap_passwd_s moz_ldap_passwd_s ++#define ldap_passwordpolicy_err2txt moz_ldap_passwordpolicy_err2txt ++#define ldap_perror moz_ldap_perror ++#define ldap_rename moz_ldap_rename ++#define ldap_rename_s moz_ldap_rename_s ++#define ldap_result moz_ldap_result ++#define ldap_result2error moz_ldap_result2error ++#define ldap_sasl_bind moz_ldap_sasl_bind ++#define ldap_sasl_bind_s moz_ldap_sasl_bind_s ++#define ldap_sasl_interactive_bind_ext_s moz_ldap_sasl_interactive_bind_ext_s ++#define ldap_sasl_interactive_bind_s moz_ldap_sasl_interactive_bind_s ++#define ldap_search moz_ldap_search ++#define ldap_search_ext moz_ldap_search_ext ++#define ldap_search_ext_s moz_ldap_search_ext_s ++#define ldap_search_s moz_ldap_search_s ++#define ldap_search_st moz_ldap_search_st ++#define ldap_set_filter_additions moz_ldap_set_filter_additions ++#define ldap_set_lderrno moz_ldap_set_lderrno ++#define ldap_set_option moz_ldap_set_option ++#define ldap_set_rebind_proc moz_ldap_set_rebind_proc ++#define ldap_setfilteraffixes moz_ldap_setfilteraffixes ++#define ldap_simple_bind moz_ldap_simple_bind ++#define ldap_simple_bind_s moz_ldap_simple_bind_s ++#define ldap_sort_entries moz_ldap_sort_entries ++#define ldap_sort_strcasecmp moz_ldap_sort_strcasecmp ++#define ldap_sort_values moz_ldap_sort_values ++#define ldap_start_tls_s moz_ldap_start_tls_s ++#define ldap_str2charray moz_ldap_str2charray ++#define ldap_tmplattrs moz_ldap_tmplattrs ++#define ldap_tmplerr2string moz_ldap_tmplerr2string ++#define ldap_tmplerrlist moz_ldap_tmplerrlist ++#define ldap_ufn_search_c moz_ldap_ufn_search_c ++#define ldap_ufn_search_ct moz_ldap_ufn_search_ct ++#define ldap_ufn_search_ctx moz_ldap_ufn_search_ctx ++#define ldap_ufn_search_s moz_ldap_ufn_search_s ++#define ldap_ufn_setfilter moz_ldap_ufn_setfilter ++#define ldap_ufn_setprefix moz_ldap_ufn_setprefix ++#define ldap_ufn_timeout moz_ldap_ufn_timeout ++#define ldap_unbind moz_ldap_unbind ++#define ldap_unbind_ext moz_ldap_unbind_ext ++#define ldap_unbind_s moz_ldap_unbind_s ++#define ldap_url_parse moz_ldap_url_parse ++#define ldap_url_parse_no_defaults moz_ldap_url_parse_no_defaults ++#define ldap_url_search moz_ldap_url_search ++#define ldap_url_search_s moz_ldap_url_search_s ++#define ldap_url_search_st moz_ldap_url_search_st ++#define ldap_utf8characters moz_ldap_utf8characters ++#define ldap_utf8copy moz_ldap_utf8copy ++#define ldap_utf8getcc moz_ldap_utf8getcc ++#define ldap_utf8isalnum moz_ldap_utf8isalnum ++#define ldap_utf8isalpha moz_ldap_utf8isalpha ++#define ldap_utf8isdigit moz_ldap_utf8isdigit ++#define ldap_utf8isspace moz_ldap_utf8isspace ++#define ldap_utf8isxdigit moz_ldap_utf8isxdigit ++#define ldap_utf8len moz_ldap_utf8len ++#define ldap_utf8next moz_ldap_utf8next ++#define ldap_utf8prev moz_ldap_utf8prev ++#define ldap_utf8strtok_r moz_ldap_utf8strtok_r ++#define ldap_vals2html moz_ldap_vals2html ++#define ldap_vals2text moz_ldap_vals2text ++#define ldap_value_free moz_ldap_value_free ++#define ldap_value_free_len moz_ldap_value_free_len ++#define ldap_version moz_ldap_version ++#define ldap_whoami moz_ldap_whoami ++#define ldap_whoami_s moz_ldap_whoami_s ++#define ldap_x_calloc moz_ldap_x_calloc ++#define ldap_x_free moz_ldap_x_free ++#define ldap_x_hostlist_first moz_ldap_x_hostlist_first ++#define ldap_x_hostlist_next moz_ldap_x_hostlist_next ++#define ldap_x_hostlist_statusfree moz_ldap_x_hostlist_statusfree ++#define ldap_x_malloc moz_ldap_x_malloc ++#define ldap_x_realloc moz_ldap_x_realloc ++ + /* Standard LDAP API functions and declarations */ + #include "ldap-standard.h" + Index: head/mail/thunderbird/files/patch-bug702179 =================================================================== --- head/mail/thunderbird/files/patch-bug702179 +++ head/mail/thunderbird/files/patch-bug702179 @@ -0,0 +1,12 @@ +Don't build static JS lib to make sure DTrace probes are picked up. + +--- js/src/build/moz.build.orig 2017-04-16 18:00:50 UTC ++++ js/src/build/moz.build +@@ -71,7 +71,3 @@ if CONFIG['OS_ARCH'] == 'SunOS': + ] + + OS_LIBS += CONFIG['REALTIME_LIBS'] +- +-NO_EXPAND_LIBS = True +- +-DIST_INSTALL = True Index: head/mail/thunderbird/files/patch-bug847568 =================================================================== --- head/mail/thunderbird/files/patch-bug847568 +++ head/mail/thunderbird/files/patch-bug847568 @@ -0,0 +1,259 @@ +# Allow building against system-wide graphite2/harfbuzz. + +diff --git config/system-headers.mozbuild config/system-headers.mozbuild +index 7620b4d00623..09d3db5ca8c0 100644 +--- config/system-headers.mozbuild ++++ config/system-headers.mozbuild +@@ -1312,6 +1312,19 @@ if not CONFIG['MOZ_TREE_PIXMAN']: + 'pixman.h', + ] + ++if CONFIG['MOZ_SYSTEM_GRAPHITE2']: ++ system_headers += [ ++ 'graphite2/Font.h', ++ 'graphite2/Segment.h', ++ ] ++ ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ system_headers += [ ++ 'harfbuzz/hb-glib.h', ++ 'harfbuzz/hb-ot.h', ++ 'harfbuzz/hb.h', ++ ] ++ + if CONFIG['MOZ_SYSTEM_LIBVPX']: + system_headers += [ + 'vpx_mem/vpx_mem.h', +diff --git dom/base/moz.build dom/base/moz.build +index 8e19020315ae..2fcdbb6f7b42 100644 +--- dom/base/moz.build ++++ dom/base/moz.build +@@ -470,6 +470,9 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']: + if CONFIG['MOZ_X11']: + CXXFLAGS += CONFIG['TK_CFLAGS'] + ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ CXXFLAGS += CONFIG['MOZ_HARFBUZZ_CFLAGS'] ++ + GENERATED_FILES += [ + 'PropertyUseCounterMap.inc', + 'UseCounterList.h', +diff --git gfx/graphite2/moz-gr-update.sh gfx/graphite2/moz-gr-update.sh +index faaab1b17971..04eff5f09882 100644 +--- gfx/graphite2/moz-gr-update.sh ++++ gfx/graphite2/moz-gr-update.sh +@@ -1,6 +1,7 @@ + #!/bin/bash + + # Script used to update the Graphite2 library in the mozilla source tree ++# and bump version for --with-system-graphite2 + + # This script lives in gfx/graphite2, along with the library source, + # but must be run from the top level of the mozilla-central tree. +@@ -37,12 +38,16 @@ echo "See" $0 "for update procedure." >> gfx/graphite2/README.mozilla + #find gfx/graphite2/ -name "*.cpp" -exec perl -p -i -e "s///;s/Windows.h/windows.h/;" {} \; + #find gfx/graphite2/ -name "*.h" -exec perl -p -i -e "s///;s/Windows.h/windows.h/;" {} \; + ++# chase version for --with-system-graphite2 ++perl -p -i -e "s/[0-9]+\,[0-9]+\,[0-9]+/$RELEASE/ and tr/./,/ \ ++ if /GR2_VERSION_REQUIRE/" old-configure.in ++ + # summarize what's been touched + echo Updated to $RELEASE. + echo Here is what changed in the gfx/graphite2 directory: + echo + +-hg stat gfx/graphite2 ++hg stat old-configure.in gfx/graphite2 + + echo + echo If gfx/graphite2/src/files.mk has changed, please make corresponding +diff --git gfx/harfbuzz/README-mozilla gfx/harfbuzz/README-mozilla +index 22c76a7df020..a01490bd49ee 100644 +--- gfx/harfbuzz/README-mozilla ++++ gfx/harfbuzz/README-mozilla +@@ -19,3 +19,8 @@ the mozilla tree. + + If the collection of source files changes, manual updates to moz.build may be + needed, as we don't use the upstream makefiles. ++ ++The in-tree copy may be omitted during build by --with-system-harfbuzz. ++Make sure to keep pkg-config version check within toolkit/moz.configure in sync ++with checkout version or increment latest tag by one if it's not based ++on upstream release. +diff --git gfx/moz.build gfx/moz.build +index 771f652e837a..3b358d84e384 100644 +--- gfx/moz.build ++++ gfx/moz.build +@@ -10,6 +10,12 @@ with Files('**'): + if CONFIG['MOZ_TREE_CAIRO']: + DIRS += ['cairo'] + ++if not CONFIG['MOZ_SYSTEM_GRAPHITE2']: ++ DIRS += ['graphite2/src' ] ++ ++if not CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ DIRS += ['harfbuzz/src'] ++ + DIRS += [ + '2d', + 'ycbcr', +@@ -18,8 +24,6 @@ DIRS += [ + 'qcms', + 'gl', + 'layers', +- 'graphite2/src', +- 'harfbuzz/src', + 'ots/src', + 'thebes', + 'ipc', +diff --git gfx/skia/generate_mozbuild.py gfx/skia/generate_mozbuild.py +index e06ae3457a47..93faa61594a3 100755 +--- gfx/skia/generate_mozbuild.py ++++ gfx/skia/generate_mozbuild.py +@@ -135,6 +135,9 @@ if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']: + '-Wno-unused-private-field', + ] + ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ CXXFLAGS += CONFIG['MOZ_HARFBUZZ_CFLAGS'] ++ + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk3', 'android'): + CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] + CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS'] +diff --git gfx/skia/moz.build gfx/skia/moz.build +index 2118677ca3a8..e4978b413784 100644 +--- gfx/skia/moz.build ++++ gfx/skia/moz.build +@@ -780,6 +780,9 @@ if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']: + '-Wno-unused-private-field', + ] + ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ CXXFLAGS += CONFIG['MOZ_HARFBUZZ_CFLAGS'] ++ + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk3', 'android'): + CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] + CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS'] +diff --git gfx/thebes/moz.build gfx/thebes/moz.build +index 56f1b9fe3f4b..0ac1100b0df3 100644 +--- gfx/thebes/moz.build ++++ gfx/thebes/moz.build +@@ -267,7 +267,13 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'): + + LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES'] + +-DEFINES['GRAPHITE2_STATIC'] = True ++if CONFIG['MOZ_SYSTEM_GRAPHITE2']: ++ CXXFLAGS += CONFIG['MOZ_GRAPHITE2_CFLAGS'] ++else: ++ DEFINES['GRAPHITE2_STATIC'] = True ++ ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ CXXFLAGS += CONFIG['MOZ_HARFBUZZ_CFLAGS'] + + if CONFIG['CC_TYPE'] == 'clang': + # Suppress warnings from Skia header files. +diff --git intl/unicharutil/util/moz.build intl/unicharutil/util/moz.build +index cb1233c56d7e..06fb1f9f174b 100644 +--- intl/unicharutil/util/moz.build ++++ intl/unicharutil/util/moz.build +@@ -25,4 +25,7 @@ UNIFIED_SOURCES += [ + 'nsUnicodeProperties.cpp', + ] + ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ CXXFLAGS += CONFIG['MOZ_HARFBUZZ_CFLAGS'] ++ + FINAL_LIBRARY = 'xul' +diff --git netwerk/dns/moz.build netwerk/dns/moz.build +index 79c26e3e7001..c4d93bc5f7dc 100644 +--- netwerk/dns/moz.build ++++ netwerk/dns/moz.build +@@ -73,3 +73,6 @@ USE_LIBS += ['icu'] + + if CONFIG['CC_TYPE'] in ('clang', 'gcc'): + CXXFLAGS += ['-Wno-error=shadow'] ++ ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ CXXFLAGS += CONFIG['MOZ_HARFBUZZ_CFLAGS'] +diff --git old-configure.in old-configure.in +index 95a58b634593..b614eef85c89 100644 +--- old-configure.in ++++ old-configure.in +@@ -4333,6 +4333,27 @@ dnl ======================================================== + + AC_SUBST(MOZ_LINUX_32_SSE2_STARTUP_ERROR) + ++dnl ======================================================== ++dnl Check for graphite2 ++dnl ======================================================== ++if test -n "$MOZ_SYSTEM_GRAPHITE2"; then ++ dnl graphite2.pc has bogus version, check manually ++ _SAVE_CFLAGS=$CFLAGS ++ CFLAGS="$CFLAGS $MOZ_GRAPHITE2_CFLAGS" ++ AC_TRY_COMPILE([ #include ++ #define GR2_VERSION_REQUIRE(major,minor,bugfix) \ ++ ( GR2_VERSION_MAJOR * 10000 + GR2_VERSION_MINOR \ ++ * 100 + GR2_VERSION_BUGFIX >= \ ++ (major) * 10000 + (minor) * 100 + (bugfix) ) ++ ], [ ++ #if !GR2_VERSION_REQUIRE(1,3,10) ++ #error "Insufficient graphite2 version." ++ #endif ++ ], [], ++ [AC_MSG_ERROR([--with-system-graphite2 requested but no working libgraphite2 found])]) ++ CFLAGS=$_SAVE_CFLAGS ++fi ++ + dnl ======================================================== + dnl Check for pixman and cairo + dnl ======================================================== +diff --git toolkit/library/moz.build toolkit/library/moz.build +index 24f940e1ed7e..079a575adec3 100644 +--- toolkit/library/moz.build ++++ toolkit/library/moz.build +@@ -231,6 +231,12 @@ if CONFIG['MOZ_SYSTEM_JPEG']: + if CONFIG['MOZ_SYSTEM_PNG']: + OS_LIBS += CONFIG['MOZ_PNG_LIBS'] + ++if CONFIG['MOZ_SYSTEM_GRAPHITE2']: ++ OS_LIBS += CONFIG['MOZ_GRAPHITE2_LIBS'] ++ ++if CONFIG['MOZ_SYSTEM_HARFBUZZ']: ++ OS_LIBS += CONFIG['MOZ_HARFBUZZ_LIBS'] ++ + if CONFIG['MOZ_SYSTEM_HUNSPELL']: + OS_LIBS += CONFIG['MOZ_HUNSPELL_LIBS'] + +diff --git toolkit/moz.configure toolkit/moz.configure +index 9297e4d6f501..d8e273887e4b 100644 +--- toolkit/moz.configure ++++ toolkit/moz.configure +@@ -1065,6 +1065,26 @@ add_old_configure_assignment('FT2_LIBS', + add_old_configure_assignment('FT2_CFLAGS', + ft2_info.cflags) + ++# Graphite2 ++# ============================================================== ++option('--with-system-graphite2', ++ help="Use system graphite2 (located with pkgconfig)") ++ ++system_graphite2 = pkg_check_modules('MOZ_GRAPHITE2', 'graphite2', ++ when='--with-system-graphite2') ++ ++set_config('MOZ_SYSTEM_GRAPHITE2', depends_if(system_graphite2)(lambda _: True)) ++ ++# HarfBuzz ++# ============================================================== ++option('--with-system-harfbuzz', ++ help="Use system harfbuzz (located with pkgconfig)") ++ ++system_harfbuzz = pkg_check_modules('MOZ_HARFBUZZ', 'harfbuzz >= 1.7.4', ++ when='--with-system-harfbuzz') ++ ++set_config('MOZ_SYSTEM_HARFBUZZ', depends_if(system_harfbuzz)(lambda _: True)) ++ + # Mortar + # ============================================================== + option('--enable-mortar', help='Enable mortar extension') Index: head/mail/thunderbird/files/patch-bug991253 =================================================================== --- head/mail/thunderbird/files/patch-bug991253 +++ head/mail/thunderbird/files/patch-bug991253 @@ -0,0 +1,17 @@ +--- extensions/spellcheck/hunspell/glue/mozHunspell.cpp~ ++++ extensions/spellcheck/hunspell/glue/mozHunspell.cpp +@@ -392,6 +392,14 @@ mozHunspell::LoadDictionaryList(bool aNo + } + } + ++ // load system hunspell dictionaries ++ nsCOMPtr hunDir; ++ NS_NewNativeLocalFile(NS_LITERAL_CSTRING("%%LOCALBASE%%/share/hunspell"), ++ true, getter_AddRefs(hunDir)); ++ if (hunDir) { ++ LoadDictionariesFromDir(hunDir); ++ } ++ + // find dictionaries from extensions requiring restart + nsCOMPtr dictDirs; + rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY_LIST, Index: head/mail/thunderbird/files/patch-dom_media_flac_FlacDecoder.cpp =================================================================== --- head/mail/thunderbird/files/patch-dom_media_flac_FlacDecoder.cpp +++ head/mail/thunderbird/files/patch-dom_media_flac_FlacDecoder.cpp @@ -0,0 +1,25 @@ +Enable FLAC on platforms without ffvpx like powerpc* + +diff --git dom/media/flac/FlacDecoder.cpp dom/media/flac/FlacDecoder.cpp +index 53fc3c9937f7..b23771ab80fa 100644 +--- dom/media/flac/FlacDecoder.cpp ++++ dom/media/flac/FlacDecoder.cpp +@@ -7,6 +7,7 @@ + #include "FlacDecoder.h" + #include "MediaContainerType.h" + #include "MediaPrefs.h" ++#include "PDMFactory.h" + + namespace mozilla { + +@@ -15,6 +16,10 @@ FlacDecoder::IsEnabled() + { + #ifdef MOZ_FFVPX + return MediaPrefs::FlacEnabled(); ++#elif defined(MOZ_FFMPEG) ++ RefPtr platform = new PDMFactory(); ++ return MediaPrefs::FlacEnabled() && platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/flac"), ++ /* DecoderDoctorDiagnostics* */ nullptr); + #else + // Until bug 1295886 is fixed. + return false; Index: head/mail/thunderbird/files/patch-env-api-keys =================================================================== --- head/mail/thunderbird/files/patch-env-api-keys +++ head/mail/thunderbird/files/patch-env-api-keys @@ -0,0 +1,21 @@ +# Accept API keys from environment like before bug 1294585 + +--- build/moz.configure/keyfiles.configure ++++ build/moz.configure/keyfiles.configure +@@ -18,6 +18,7 @@ def keyfile(desc, help=None, callback=lambda x: x): + @checking('for the %s key' % desc, lambda x: x and x is not no_key) + @imports(_from='__builtin__', _import='open') + @imports(_from='__builtin__', _import='IOError') ++ @imports(_from='os', _import='environ') + def keyfile(value): + if value: + try: +@@ -28,7 +29,7 @@ def keyfile(desc, help=None, callback=lambda x: x): + raise FatalCheckError("'%s' is empty." % value[0]) + except IOError as e: + raise FatalCheckError("'%s': %s." % (value[0], e.strerror)) +- return no_key ++ return environ.get('MOZ_%s_KEY' % desc.upper().replace(' ', '_')) or no_key + + return keyfile + Index: head/mail/thunderbird/files/patch-ijg-libjpeg =================================================================== --- head/mail/thunderbird/files/patch-ijg-libjpeg +++ head/mail/thunderbird/files/patch-ijg-libjpeg @@ -0,0 +1,383 @@ +# Partially revert bug 791305 to allow building with system IJG jpeg library + +diff --git old-configure.in configure.in +index f0aeb5d..1c01010 100644 +--- old-configure.in ++++ old-configure.in +@@ -4027,11 +4027,7 @@ if test "$MOZ_SYSTEM_JPEG" = 1; then + #include ], + [ #if JPEG_LIB_VERSION < $MOZJPEG + #error "Insufficient JPEG library version ($MOZJPEG required)." +- #endif +- #ifndef JCS_EXTENSIONS +- #error "libjpeg-turbo JCS_EXTENSIONS required" +- #endif +- ], ++ #endif ], + MOZ_SYSTEM_JPEG=1, + AC_MSG_ERROR([Insufficient JPEG library version for --with-system-jpeg])) + fi +diff --git image/decoders/nsJPEGDecoder.cpp image/decoders/nsJPEGDecoder.cpp +index 8fa8200..1d2a259 100644 +--- image/decoders/nsJPEGDecoder.cpp ++++ image/decoders/nsJPEGDecoder.cpp +@@ -21,13 +21,28 @@ + + extern "C" { + #include "iccjpeg.h" +-} + ++#ifdef JCS_EXTENSIONS + #if MOZ_BIG_ENDIAN + #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB + #else + #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX + #endif ++#else ++/* Colorspace conversion (copied from jpegint.h) */ ++struct jpeg_color_deconverter { ++ JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); ++ JMETHOD(void, color_convert, (j_decompress_ptr cinfo, ++ JSAMPIMAGE input_buf, JDIMENSION input_row, ++ JSAMPARRAY output_buf, int num_rows)); ++}; ++ ++METHODDEF(void) ++ycc_rgb_convert_argb (j_decompress_ptr cinfo, ++ JSAMPIMAGE input_buf, JDIMENSION input_row, ++ JSAMPARRAY output_buf, int num_rows); ++#endif ++} + + static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width); + +@@ -367,6 +382,7 @@ nsJPEGDecoder::WriteInternal(const char* + case JCS_GRAYSCALE: + case JCS_RGB: + case JCS_YCbCr: ++#ifdef JCS_EXTENSIONS + // if we're not color managing we can decode directly to + // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB + if (mCMSMode != eCMSMode_All) { +@@ -375,6 +391,9 @@ nsJPEGDecoder::WriteInternal(const char* + } else { + mInfo.out_color_space = JCS_RGB; + } ++#else ++ mInfo.out_color_space = JCS_RGB; ++#endif + break; + case JCS_CMYK: + case JCS_YCCK: +@@ -448,6 +467,16 @@ nsJPEGDecoder::WriteInternal(const char* + return; // I/O suspension + } + ++#ifndef JCS_EXTENSIONS ++ /* Force to use our YCbCr to Packed RGB converter when possible */ ++ if (!mTransform && (mCMSMode != eCMSMode_All) && ++ mInfo.jpeg_color_space == JCS_YCbCr && mInfo.out_color_space == JCS_RGB) { ++ /* Special case for the most common case: transform from YCbCr direct into packed ARGB */ ++ mInfo.out_color_components = 4; /* Packed ARGB pixels are always 4 bytes...*/ ++ mInfo.cconvert->color_convert = ycc_rgb_convert_argb; ++ } ++#endif ++ + // If this is a progressive JPEG ... + mState = mInfo.buffered_image ? + JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL; +@@ -605,7 +633,11 @@ nsJPEGDecoder::OutputScanlines(bool* sus + uint32_t* imageRow = ((uint32_t*)mImageData) + + (mInfo.output_scanline * mInfo.output_width); + ++#ifdef JCS_EXTENSIONS + if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) { ++#else ++ if (mInfo.cconvert->color_convert == ycc_rgb_convert_argb) { ++#endif + // Special case: scanline will be directly converted into packed ARGB + if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) { + *suspend = true; // suspend +@@ -920,6 +952,282 @@ term_source (j_decompress_ptr jd) + } // namespace mozilla + + ++#ifndef JCS_EXTENSIONS ++/**************** YCbCr -> Cairo's RGB24/ARGB32 conversion: most common case **************/ ++ ++/* ++ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are ++ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. ++ * The conversion equations to be implemented are therefore ++ * R = Y + 1.40200 * Cr ++ * G = Y - 0.34414 * Cb - 0.71414 * Cr ++ * B = Y + 1.77200 * Cb ++ * where Cb and Cr represent the incoming values less CENTERJSAMPLE. ++ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) ++ * ++ * To avoid floating-point arithmetic, we represent the fractional constants ++ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide ++ * the products by 2^16, with appropriate rounding, to get the correct answer. ++ * Notice that Y, being an integral input, does not contribute any fraction ++ * so it need not participate in the rounding. ++ * ++ * For even more speed, we avoid doing any multiplications in the inner loop ++ * by precalculating the constants times Cb and Cr for all possible values. ++ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); ++ * for 12-bit samples it is still acceptable. It's not very reasonable for ++ * 16-bit samples, but if you want lossless storage you shouldn't be changing ++ * colorspace anyway. ++ * The Cr=>R and Cb=>B values can be rounded to integers in advance; the ++ * values for the G calculation are left scaled up, since we must add them ++ * together before rounding. ++ */ ++ ++#define SCALEBITS 16 /* speediest right-shift on some machines */ ++ ++/* Use static tables for color processing. */ ++/* Four tables, each 256 entries of 4 bytes totals 4K which is not bad... */ ++ ++const int Cr_r_tab[(MAXJSAMPLE+1) * sizeof(int)] ={ ++ -0xb3, -0xb2, -0xb1, -0xaf, -0xae, -0xac, ++ -0xab, -0xaa, -0xa8, -0xa7, -0xa5, -0xa4, ++ -0xa3, -0xa1, -0xa0, -0x9e, -0x9d, -0x9c, ++ -0x9a, -0x99, -0x97, -0x96, -0x95, -0x93, ++ -0x92, -0x90, -0x8f, -0x8e, -0x8c, -0x8b, ++ -0x89, -0x88, -0x87, -0x85, -0x84, -0x82, ++ -0x81, -0x80, -0x7e, -0x7d, -0x7b, -0x7a, ++ -0x79, -0x77, -0x76, -0x74, -0x73, -0x72, ++ -0x70, -0x6f, -0x6d, -0x6c, -0x6b, -0x69, ++ -0x68, -0x66, -0x65, -0x64, -0x62, -0x61, ++ -0x5f, -0x5e, -0x5d, -0x5b, -0x5a, -0x58, ++ -0x57, -0x56, -0x54, -0x53, -0x51, -0x50, ++ -0x4f, -0x4d, -0x4c, -0x4a, -0x49, -0x48, ++ -0x46, -0x45, -0x43, -0x42, -0x40, -0x3f, ++ -0x3e, -0x3c, -0x3b, -0x39, -0x38, -0x37, ++ -0x35, -0x34, -0x32, -0x31, -0x30, -0x2e, ++ -0x2d, -0x2b, -0x2a, -0x29, -0x27, -0x26, ++ -0x24, -0x23, -0x22, -0x20, -0x1f, -0x1d, ++ -0x1c, -0x1b, -0x19, -0x18, -0x16, -0x15, ++ -0x14, -0x12, -0x11, -0x0f, -0x0e, -0x0d, ++ -0x0b, -0x0a, -0x08, -0x07, -0x06, -0x04, ++ -0x03, -0x01, 0x00, 0x01, 0x03, 0x04, ++ 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0d, ++ 0x0e, 0x0f, 0x11, 0x12, 0x14, 0x15, ++ 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1d, ++ 0x1f, 0x20, 0x22, 0x23, 0x24, 0x26, ++ 0x27, 0x29, 0x2a, 0x2b, 0x2d, 0x2e, ++ 0x30, 0x31, 0x32, 0x34, 0x35, 0x37, ++ 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, ++ 0x40, 0x42, 0x43, 0x45, 0x46, 0x48, ++ 0x49, 0x4a, 0x4c, 0x4d, 0x4f, 0x50, ++ 0x51, 0x53, 0x54, 0x56, 0x57, 0x58, ++ 0x5a, 0x5b, 0x5d, 0x5e, 0x5f, 0x61, ++ 0x62, 0x64, 0x65, 0x66, 0x68, 0x69, ++ 0x6b, 0x6c, 0x6d, 0x6f, 0x70, 0x72, ++ 0x73, 0x74, 0x76, 0x77, 0x79, 0x7a, ++ 0x7b, 0x7d, 0x7e, 0x80, 0x81, 0x82, ++ 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, ++ 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, ++ 0x95, 0x96, 0x97, 0x99, 0x9a, 0x9c, ++ 0x9d, 0x9e, 0xa0, 0xa1, 0xa3, 0xa4, ++ 0xa5, 0xa7, 0xa8, 0xaa, 0xab, 0xac, ++ 0xae, 0xaf, 0xb1, 0xb2, ++ }; ++ ++const int Cb_b_tab[(MAXJSAMPLE+1) * sizeof(int)] ={ ++ -0xe3, -0xe1, -0xdf, -0xde, -0xdc, -0xda, ++ -0xd8, -0xd6, -0xd5, -0xd3, -0xd1, -0xcf, ++ -0xce, -0xcc, -0xca, -0xc8, -0xc6, -0xc5, ++ -0xc3, -0xc1, -0xbf, -0xbe, -0xbc, -0xba, ++ -0xb8, -0xb7, -0xb5, -0xb3, -0xb1, -0xaf, ++ -0xae, -0xac, -0xaa, -0xa8, -0xa7, -0xa5, ++ -0xa3, -0xa1, -0x9f, -0x9e, -0x9c, -0x9a, ++ -0x98, -0x97, -0x95, -0x93, -0x91, -0x90, ++ -0x8e, -0x8c, -0x8a, -0x88, -0x87, -0x85, ++ -0x83, -0x81, -0x80, -0x7e, -0x7c, -0x7a, ++ -0x78, -0x77, -0x75, -0x73, -0x71, -0x70, ++ -0x6e, -0x6c, -0x6a, -0x69, -0x67, -0x65, ++ -0x63, -0x61, -0x60, -0x5e, -0x5c, -0x5a, ++ -0x59, -0x57, -0x55, -0x53, -0x52, -0x50, ++ -0x4e, -0x4c, -0x4a, -0x49, -0x47, -0x45, ++ -0x43, -0x42, -0x40, -0x3e, -0x3c, -0x3a, ++ -0x39, -0x37, -0x35, -0x33, -0x32, -0x30, ++ -0x2e, -0x2c, -0x2b, -0x29, -0x27, -0x25, ++ -0x23, -0x22, -0x20, -0x1e, -0x1c, -0x1b, ++ -0x19, -0x17, -0x15, -0x13, -0x12, -0x10, ++ -0x0e, -0x0c, -0x0b, -0x09, -0x07, -0x05, ++ -0x04, -0x02, 0x00, 0x02, 0x04, 0x05, ++ 0x07, 0x09, 0x0b, 0x0c, 0x0e, 0x10, ++ 0x12, 0x13, 0x15, 0x17, 0x19, 0x1b, ++ 0x1c, 0x1e, 0x20, 0x22, 0x23, 0x25, ++ 0x27, 0x29, 0x2b, 0x2c, 0x2e, 0x30, ++ 0x32, 0x33, 0x35, 0x37, 0x39, 0x3a, ++ 0x3c, 0x3e, 0x40, 0x42, 0x43, 0x45, ++ 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x50, ++ 0x52, 0x53, 0x55, 0x57, 0x59, 0x5a, ++ 0x5c, 0x5e, 0x60, 0x61, 0x63, 0x65, ++ 0x67, 0x69, 0x6a, 0x6c, 0x6e, 0x70, ++ 0x71, 0x73, 0x75, 0x77, 0x78, 0x7a, ++ 0x7c, 0x7e, 0x80, 0x81, 0x83, 0x85, ++ 0x87, 0x88, 0x8a, 0x8c, 0x8e, 0x90, ++ 0x91, 0x93, 0x95, 0x97, 0x98, 0x9a, ++ 0x9c, 0x9e, 0x9f, 0xa1, 0xa3, 0xa5, ++ 0xa7, 0xa8, 0xaa, 0xac, 0xae, 0xaf, ++ 0xb1, 0xb3, 0xb5, 0xb7, 0xb8, 0xba, ++ 0xbc, 0xbe, 0xbf, 0xc1, 0xc3, 0xc5, ++ 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xcf, ++ 0xd1, 0xd3, 0xd5, 0xd6, 0xd8, 0xda, ++ 0xdc, 0xde, 0xdf, 0xe1, ++ }; ++ ++const int Cr_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={ ++ 0x5b6900, 0x5ab22e, 0x59fb5c, 0x59448a, 0x588db8, 0x57d6e6, ++ 0x572014, 0x566942, 0x55b270, 0x54fb9e, 0x5444cc, 0x538dfa, ++ 0x52d728, 0x522056, 0x516984, 0x50b2b2, 0x4ffbe0, 0x4f450e, ++ 0x4e8e3c, 0x4dd76a, 0x4d2098, 0x4c69c6, 0x4bb2f4, 0x4afc22, ++ 0x4a4550, 0x498e7e, 0x48d7ac, 0x4820da, 0x476a08, 0x46b336, ++ 0x45fc64, 0x454592, 0x448ec0, 0x43d7ee, 0x43211c, 0x426a4a, ++ 0x41b378, 0x40fca6, 0x4045d4, 0x3f8f02, 0x3ed830, 0x3e215e, ++ 0x3d6a8c, 0x3cb3ba, 0x3bfce8, 0x3b4616, 0x3a8f44, 0x39d872, ++ 0x3921a0, 0x386ace, 0x37b3fc, 0x36fd2a, 0x364658, 0x358f86, ++ 0x34d8b4, 0x3421e2, 0x336b10, 0x32b43e, 0x31fd6c, 0x31469a, ++ 0x308fc8, 0x2fd8f6, 0x2f2224, 0x2e6b52, 0x2db480, 0x2cfdae, ++ 0x2c46dc, 0x2b900a, 0x2ad938, 0x2a2266, 0x296b94, 0x28b4c2, ++ 0x27fdf0, 0x27471e, 0x26904c, 0x25d97a, 0x2522a8, 0x246bd6, ++ 0x23b504, 0x22fe32, 0x224760, 0x21908e, 0x20d9bc, 0x2022ea, ++ 0x1f6c18, 0x1eb546, 0x1dfe74, 0x1d47a2, 0x1c90d0, 0x1bd9fe, ++ 0x1b232c, 0x1a6c5a, 0x19b588, 0x18feb6, 0x1847e4, 0x179112, ++ 0x16da40, 0x16236e, 0x156c9c, 0x14b5ca, 0x13fef8, 0x134826, ++ 0x129154, 0x11da82, 0x1123b0, 0x106cde, 0x0fb60c, 0x0eff3a, ++ 0x0e4868, 0x0d9196, 0x0cdac4, 0x0c23f2, 0x0b6d20, 0x0ab64e, ++ 0x09ff7c, 0x0948aa, 0x0891d8, 0x07db06, 0x072434, 0x066d62, ++ 0x05b690, 0x04ffbe, 0x0448ec, 0x03921a, 0x02db48, 0x022476, ++ 0x016da4, 0x00b6d2, 0x000000, -0x00b6d2, -0x016da4, -0x022476, ++ -0x02db48, -0x03921a, -0x0448ec, -0x04ffbe, -0x05b690, -0x066d62, ++ -0x072434, -0x07db06, -0x0891d8, -0x0948aa, -0x09ff7c, -0x0ab64e, ++ -0x0b6d20, -0x0c23f2, -0x0cdac4, -0x0d9196, -0x0e4868, -0x0eff3a, ++ -0x0fb60c, -0x106cde, -0x1123b0, -0x11da82, -0x129154, -0x134826, ++ -0x13fef8, -0x14b5ca, -0x156c9c, -0x16236e, -0x16da40, -0x179112, ++ -0x1847e4, -0x18feb6, -0x19b588, -0x1a6c5a, -0x1b232c, -0x1bd9fe, ++ -0x1c90d0, -0x1d47a2, -0x1dfe74, -0x1eb546, -0x1f6c18, -0x2022ea, ++ -0x20d9bc, -0x21908e, -0x224760, -0x22fe32, -0x23b504, -0x246bd6, ++ -0x2522a8, -0x25d97a, -0x26904c, -0x27471e, -0x27fdf0, -0x28b4c2, ++ -0x296b94, -0x2a2266, -0x2ad938, -0x2b900a, -0x2c46dc, -0x2cfdae, ++ -0x2db480, -0x2e6b52, -0x2f2224, -0x2fd8f6, -0x308fc8, -0x31469a, ++ -0x31fd6c, -0x32b43e, -0x336b10, -0x3421e2, -0x34d8b4, -0x358f86, ++ -0x364658, -0x36fd2a, -0x37b3fc, -0x386ace, -0x3921a0, -0x39d872, ++ -0x3a8f44, -0x3b4616, -0x3bfce8, -0x3cb3ba, -0x3d6a8c, -0x3e215e, ++ -0x3ed830, -0x3f8f02, -0x4045d4, -0x40fca6, -0x41b378, -0x426a4a, ++ -0x43211c, -0x43d7ee, -0x448ec0, -0x454592, -0x45fc64, -0x46b336, ++ -0x476a08, -0x4820da, -0x48d7ac, -0x498e7e, -0x4a4550, -0x4afc22, ++ -0x4bb2f4, -0x4c69c6, -0x4d2098, -0x4dd76a, -0x4e8e3c, -0x4f450e, ++ -0x4ffbe0, -0x50b2b2, -0x516984, -0x522056, -0x52d728, -0x538dfa, ++ -0x5444cc, -0x54fb9e, -0x55b270, -0x566942, -0x572014, -0x57d6e6, ++ -0x588db8, -0x59448a, -0x59fb5c, -0x5ab22e, ++ }; ++ ++const int Cb_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={ ++ 0x2c8d00, 0x2c34e6, 0x2bdccc, 0x2b84b2, 0x2b2c98, 0x2ad47e, ++ 0x2a7c64, 0x2a244a, 0x29cc30, 0x297416, 0x291bfc, 0x28c3e2, ++ 0x286bc8, 0x2813ae, 0x27bb94, 0x27637a, 0x270b60, 0x26b346, ++ 0x265b2c, 0x260312, 0x25aaf8, 0x2552de, 0x24fac4, 0x24a2aa, ++ 0x244a90, 0x23f276, 0x239a5c, 0x234242, 0x22ea28, 0x22920e, ++ 0x2239f4, 0x21e1da, 0x2189c0, 0x2131a6, 0x20d98c, 0x208172, ++ 0x202958, 0x1fd13e, 0x1f7924, 0x1f210a, 0x1ec8f0, 0x1e70d6, ++ 0x1e18bc, 0x1dc0a2, 0x1d6888, 0x1d106e, 0x1cb854, 0x1c603a, ++ 0x1c0820, 0x1bb006, 0x1b57ec, 0x1affd2, 0x1aa7b8, 0x1a4f9e, ++ 0x19f784, 0x199f6a, 0x194750, 0x18ef36, 0x18971c, 0x183f02, ++ 0x17e6e8, 0x178ece, 0x1736b4, 0x16de9a, 0x168680, 0x162e66, ++ 0x15d64c, 0x157e32, 0x152618, 0x14cdfe, 0x1475e4, 0x141dca, ++ 0x13c5b0, 0x136d96, 0x13157c, 0x12bd62, 0x126548, 0x120d2e, ++ 0x11b514, 0x115cfa, 0x1104e0, 0x10acc6, 0x1054ac, 0x0ffc92, ++ 0x0fa478, 0x0f4c5e, 0x0ef444, 0x0e9c2a, 0x0e4410, 0x0debf6, ++ 0x0d93dc, 0x0d3bc2, 0x0ce3a8, 0x0c8b8e, 0x0c3374, 0x0bdb5a, ++ 0x0b8340, 0x0b2b26, 0x0ad30c, 0x0a7af2, 0x0a22d8, 0x09cabe, ++ 0x0972a4, 0x091a8a, 0x08c270, 0x086a56, 0x08123c, 0x07ba22, ++ 0x076208, 0x0709ee, 0x06b1d4, 0x0659ba, 0x0601a0, 0x05a986, ++ 0x05516c, 0x04f952, 0x04a138, 0x04491e, 0x03f104, 0x0398ea, ++ 0x0340d0, 0x02e8b6, 0x02909c, 0x023882, 0x01e068, 0x01884e, ++ 0x013034, 0x00d81a, 0x008000, 0x0027e6, -0x003034, -0x00884e, ++ -0x00e068, -0x013882, -0x01909c, -0x01e8b6, -0x0240d0, -0x0298ea, ++ -0x02f104, -0x03491e, -0x03a138, -0x03f952, -0x04516c, -0x04a986, ++ -0x0501a0, -0x0559ba, -0x05b1d4, -0x0609ee, -0x066208, -0x06ba22, ++ -0x07123c, -0x076a56, -0x07c270, -0x081a8a, -0x0872a4, -0x08cabe, ++ -0x0922d8, -0x097af2, -0x09d30c, -0x0a2b26, -0x0a8340, -0x0adb5a, ++ -0x0b3374, -0x0b8b8e, -0x0be3a8, -0x0c3bc2, -0x0c93dc, -0x0cebf6, ++ -0x0d4410, -0x0d9c2a, -0x0df444, -0x0e4c5e, -0x0ea478, -0x0efc92, ++ -0x0f54ac, -0x0facc6, -0x1004e0, -0x105cfa, -0x10b514, -0x110d2e, ++ -0x116548, -0x11bd62, -0x12157c, -0x126d96, -0x12c5b0, -0x131dca, ++ -0x1375e4, -0x13cdfe, -0x142618, -0x147e32, -0x14d64c, -0x152e66, ++ -0x158680, -0x15de9a, -0x1636b4, -0x168ece, -0x16e6e8, -0x173f02, ++ -0x17971c, -0x17ef36, -0x184750, -0x189f6a, -0x18f784, -0x194f9e, ++ -0x19a7b8, -0x19ffd2, -0x1a57ec, -0x1ab006, -0x1b0820, -0x1b603a, ++ -0x1bb854, -0x1c106e, -0x1c6888, -0x1cc0a2, -0x1d18bc, -0x1d70d6, ++ -0x1dc8f0, -0x1e210a, -0x1e7924, -0x1ed13e, -0x1f2958, -0x1f8172, ++ -0x1fd98c, -0x2031a6, -0x2089c0, -0x20e1da, -0x2139f4, -0x21920e, ++ -0x21ea28, -0x224242, -0x229a5c, -0x22f276, -0x234a90, -0x23a2aa, ++ -0x23fac4, -0x2452de, -0x24aaf8, -0x250312, -0x255b2c, -0x25b346, ++ -0x260b60, -0x26637a, -0x26bb94, -0x2713ae, -0x276bc8, -0x27c3e2, ++ -0x281bfc, -0x287416, -0x28cc30, -0x29244a, -0x297c64, -0x29d47e, ++ -0x2a2c98, -0x2a84b2, -0x2adccc, -0x2b34e6, ++ }; ++ ++ ++/* We assume that right shift corresponds to signed division by 2 with ++ * rounding towards minus infinity. This is correct for typical "arithmetic ++ * shift" instructions that shift in copies of the sign bit. But some ++ * C compilers implement >> with an unsigned shift. For these machines you ++ * must define RIGHT_SHIFT_IS_UNSIGNED. ++ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. ++ * It is only applied with constant shift counts. SHIFT_TEMPS must be ++ * included in the variables of any routine using RIGHT_SHIFT. ++ */ ++ ++#ifdef RIGHT_SHIFT_IS_UNSIGNED ++#define SHIFT_TEMPS INT32 shift_temp; ++#define RIGHT_SHIFT(x,shft) \ ++ ((shift_temp = (x)) < 0 ? \ ++ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ ++ (shift_temp >> (shft))) ++#else ++#define SHIFT_TEMPS ++#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) ++#endif ++ ++ ++METHODDEF(void) ++ycc_rgb_convert_argb (j_decompress_ptr cinfo, ++ JSAMPIMAGE input_buf, JDIMENSION input_row, ++ JSAMPARRAY output_buf, int num_rows) ++{ ++ JDIMENSION num_cols = cinfo->output_width; ++ JSAMPLE * range_limit = cinfo->sample_range_limit; ++ ++ SHIFT_TEMPS ++ ++ /* This is used if we don't have SSE2 */ ++ ++ while (--num_rows >= 0) { ++ JSAMPROW inptr0 = input_buf[0][input_row]; ++ JSAMPROW inptr1 = input_buf[1][input_row]; ++ JSAMPROW inptr2 = input_buf[2][input_row]; ++ input_row++; ++ uint32_t *outptr = (uint32_t *) *output_buf++; ++ for (JDIMENSION col = 0; col < num_cols; col++) { ++ int y = GETJSAMPLE(inptr0[col]); ++ int cb = GETJSAMPLE(inptr1[col]); ++ int cr = GETJSAMPLE(inptr2[col]); ++ JSAMPLE * range_limit_y = range_limit + y; ++ /* Range-limiting is essential due to noise introduced by DCT losses. */ ++ outptr[col] = 0xFF000000 | ++ ( range_limit_y[Cr_r_tab[cr]] << 16 ) | ++ ( range_limit_y[((int) RIGHT_SHIFT(Cb_g_tab[cb] + Cr_g_tab[cr], SCALEBITS))] << 8 ) | ++ ( range_limit_y[Cb_b_tab[cb]] ); ++ } ++ } ++} ++#endif ++ ++ + ///*************** Inverted CMYK -> RGB conversion ************************* + /// Input is (Inverted) CMYK stored as 4 bytes per pixel. + /// Output is RGB stored as 3 bytes per pixel. Index: head/mail/thunderbird/files/patch-ipc_glue_MessageChannel.cpp =================================================================== --- head/mail/thunderbird/files/patch-ipc_glue_MessageChannel.cpp +++ head/mail/thunderbird/files/patch-ipc_glue_MessageChannel.cpp @@ -0,0 +1,16 @@ +To be removed after FreeBSD 10.* EOL + +--- ipc/glue/MessageChannel.cpp.orig 2017-11-02 16:16:32 UTC ++++ ipc/glue/MessageChannel.cpp +@@ -685,6 +685,11 @@ MessageChannel::WillDestroyCurrentMessageLoop() + mWorkerLoop = nullptr; + } + ++#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 ++// Work around UB in __tree crashing mPendingPromises.clear() ++// http://llvm.org/viewvc/llvm-project?view=revision&revision=276003 ++[[clang::optnone]] ++#endif + void + MessageChannel::Clear() + { Index: head/mail/thunderbird/files/patch-mail-app-nsMailApp.cpp =================================================================== --- head/mail/thunderbird/files/patch-mail-app-nsMailApp.cpp +++ head/mail/thunderbird/files/patch-mail-app-nsMailApp.cpp @@ -0,0 +1,12 @@ +--- comm/mail/app/nsMailApp.cpp.orig 2017-03-21 17:00:12 UTC ++++ comm/mail/app/nsMailApp.cpp +@@ -322,6 +322,9 @@ int main(int argc, char* argv[], char* e + { + mozilla::TimeStamp start = mozilla::TimeStamp::Now(); + ++ setenv("MOZ_GMP_PATH", "%%LOCALBASE%%/lib/browser_plugins/symlinks/gecko", 0); ++ setenv("MOZ_PLUGIN_PATH", "%%LOCALBASE%%/lib/browser_plugins/symlinks/gecko", 0); ++ + #ifdef HAS_DLL_BLOCKLIST + DllBlocklist_Initialize(); + Index: head/mail/thunderbird/files/patch-sample-type =================================================================== --- head/mail/thunderbird/files/patch-sample-type +++ head/mail/thunderbird/files/patch-sample-type @@ -0,0 +1,13 @@ +# Let ports handle default sample type + +--- old-configure.in~ ++++ old-configure.in +@@ -5144,7 +5144,7 @@ dnl Use integers over floats for audio o + dnl (regarless of the CPU architecture, because audio + dnl backends for those platforms don't support floats. We also + dnl use integers on ARM with other OS, because it's more efficient. +-if test "$OS_TARGET" = "Android" -o "$CPU_ARCH" = "arm"; then ++if test -n "$MOZ_INTEGER_SAMPLES"; then + MOZ_SAMPLE_TYPE_S16=1 + AC_DEFINE(MOZ_SAMPLE_TYPE_S16) + AC_SUBST(MOZ_SAMPLE_TYPE_S16) Index: head/mail/thunderbird/files/patch-toolkit_moz.configure =================================================================== --- head/mail/thunderbird/files/patch-toolkit_moz.configure +++ head/mail/thunderbird/files/patch-toolkit_moz.configure @@ -0,0 +1,15 @@ +diff --git toolkit/moz.configure toolkit/moz.configure +index 1befea00c485..7999b7acd5bd 100644 +--- toolkit/moz.configure ++++ toolkit/moz.configure +@@ -842,8 +842,8 @@ def webrender(value, milestone): + enable_webrender = None + + if value.origin == 'default': +- # if nothing is specified, default to just building on Nightly +- build_webrender = milestone.is_nightly ++ # build by default downstream ++ build_webrender = True + elif len(value) and value[0] == 'build': + # if explicitly set to 'build', then we build but don't enable + build_webrender = True Index: head/mail/thunderbird/files/patch-u2f-hid-rs62 =================================================================== --- head/mail/thunderbird/files/patch-u2f-hid-rs62 +++ head/mail/thunderbird/files/patch-u2f-hid-rs62 @@ -0,0 +1,31339 @@ +https://github.com/jcjones/u2f-hid-rs/pull/62 + +diff --git Cargo.lock Cargo.lock +index 4bfba0eb2f52..cd4d80035d81 100644 +--- Cargo.lock ++++ Cargo.lock +@@ -486,6 +486,15 @@ dependencies = [ + "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + ] + ++[[package]] ++name = "devd-rs" ++version = "0.2.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++dependencies = [ ++ "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ++ "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ++] ++ + [[package]] + name = "dtoa" + version = "0.4.2" +@@ -1170,6 +1179,14 @@ name = "nom" + version = "1.2.4" + source = "registry+https://github.com/rust-lang/crates.io-index" + ++[[package]] ++name = "nom" ++version = "3.2.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++dependencies = [ ++ "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ++] ++ + [[package]] + name = "nserror" + version = "0.1.0" +@@ -1863,6 +1880,7 @@ dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ++ "devd-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +@@ -2220,6 +2238,7 @@ dependencies = [ + "checksum darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "167dd3e235c2f1da16a635c282630452cdf49191eb05711de1bcd1d3d5068c00" + "checksum darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c53edaba455f6073a10c27c72440860eb3f60444f8c8660a391032eeae744d82" + "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" ++"checksum devd-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c9ac481c38baf400d3b732e4a06850dfaa491d1b6379a249d9d40d14c2434c" + "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" + "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d" + "checksum dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a207eb7b40e25d1d28dc679f451d321fb6954b73ceaa47986702575865469461" +@@ -2279,6 +2298,7 @@ dependencies = [ + "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" + "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" + "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce" ++"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" + "checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" + "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" + "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +diff --git dom/webauthn/u2f-hid-rs/Cargo.toml dom/webauthn/u2f-hid-rs/Cargo.toml +index a0ab8ce71067..046de1e46f15 100644 +--- dom/webauthn/u2f-hid-rs/Cargo.toml ++++ dom/webauthn/u2f-hid-rs/Cargo.toml +@@ -6,6 +6,9 @@ authors = ["Kyle Machulis ", "J.C. Jones { + match $val { +- Ok(v) => { v } +- Err(e) => { return $or(e); } ++ Ok(v) => v, ++ Err(e) => { ++ return $or(e); ++ } + } +- } ++ }; + } + + fn u2f_get_key_handle_from_register_response(register_response: &Vec) -> io::Result> { +@@ -46,15 +47,13 @@ fn main() { + let challenge_str = format!("{}{}", + r#"{"challenge": "1vQ9mxionq0ngCnjD-wTsv1zUSrGRtFqG2xP09SbZ70","#, + r#" "version": "U2F_V2", "appId": "http://demo.yubico.com"}"#); +- let mut challenge = Sha256::new(); +- challenge.input_str(&challenge_str); +- let mut chall_bytes: Vec = vec![0; challenge.output_bytes()]; +- challenge.result(&mut chall_bytes); ++ let mut challenge = Sha256::default(); ++ challenge.input(challenge_str.as_bytes()); ++ let chall_bytes = Vec::from(challenge.result().as_slice()); + +- let mut application = Sha256::new(); +- application.input_str("http://demo.yubico.com"); +- let mut app_bytes: Vec = vec![0; application.output_bytes()]; +- application.result(&mut app_bytes); ++ let mut application = Sha256::default(); ++ application.input("http://demo.yubico.com".as_bytes()); ++ let app_bytes = Vec::from(application.result().as_slice()); + + let manager = U2FManager::new().unwrap(); + let flags = RegisterFlags::empty(); +diff --git dom/webauthn/u2f-hid-rs/src/freebsd/device.rs dom/webauthn/u2f-hid-rs/src/freebsd/device.rs +new file mode 100644 +index 000000000000..5b9e7f2a912e +--- /dev/null ++++ dom/webauthn/u2f-hid-rs/src/freebsd/device.rs +@@ -0,0 +1,88 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++extern crate libc; ++ ++use std::ffi::{CString, OsString}; ++use std::io; ++use std::io::{Read, Write}; ++use std::os::unix::prelude::*; ++ ++use consts::CID_BROADCAST; ++use platform::uhid; ++use u2ftypes::U2FDevice; ++use util::from_unix_result; ++ ++#[derive(Debug)] ++pub struct Device { ++ path: OsString, ++ fd: libc::c_int, ++ cid: [u8; 4], ++} ++ ++impl Device { ++ pub fn new(path: OsString) -> io::Result { ++ let cstr = CString::new(path.as_bytes())?; ++ let fd = unsafe { libc::open(cstr.as_ptr(), libc::O_RDWR) }; ++ let fd = from_unix_result(fd)?; ++ Ok(Self { ++ path, ++ fd, ++ cid: CID_BROADCAST, ++ }) ++ } ++ ++ pub fn is_u2f(&self) -> bool { ++ uhid::is_u2f_device(self.fd) ++ } ++} ++ ++impl Drop for Device { ++ fn drop(&mut self) { ++ // Close the fd, ignore any errors. ++ let _ = unsafe { libc::close(self.fd) }; ++ } ++} ++ ++impl PartialEq for Device { ++ fn eq(&self, other: &Device) -> bool { ++ self.path == other.path ++ } ++} ++ ++impl Read for Device { ++ fn read(&mut self, buf: &mut [u8]) -> io::Result { ++ let bufp = buf.as_mut_ptr() as *mut libc::c_void; ++ let rv = unsafe { libc::read(self.fd, bufp, buf.len()) }; ++ from_unix_result(rv as usize) ++ } ++} ++ ++impl Write for Device { ++ fn write(&mut self, buf: &[u8]) -> io::Result { ++ let report_id = buf[0] as i64; ++ // Skip report number when not using numbered reports. ++ let start = if report_id == 0x0 { 1 } else { 0 }; ++ let data = &buf[start..]; ++ ++ let data_ptr = data.as_ptr() as *const libc::c_void; ++ let rv = unsafe { libc::write(self.fd, data_ptr, data.len()) }; ++ from_unix_result(rv as usize + 1) ++ } ++ ++ // USB HID writes don't buffer, so this will be a nop. ++ fn flush(&mut self) -> io::Result<()> { ++ Ok(()) ++ } ++} ++ ++impl U2FDevice for Device { ++ fn get_cid<'a>(&'a self) -> &'a [u8; 4] { ++ &self.cid ++ } ++ ++ fn set_cid(&mut self, cid: [u8; 4]) { ++ self.cid = cid; ++ } ++} +diff --git dom/webauthn/u2f-hid-rs/src/freebsd/mod.rs dom/webauthn/u2f-hid-rs/src/freebsd/mod.rs +new file mode 100644 +index 000000000000..7ed5727157d5 +--- /dev/null ++++ dom/webauthn/u2f-hid-rs/src/freebsd/mod.rs +@@ -0,0 +1,9 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++pub mod device; ++pub mod transaction; ++ ++mod monitor; ++mod uhid; +diff --git dom/webauthn/u2f-hid-rs/src/freebsd/monitor.rs dom/webauthn/u2f-hid-rs/src/freebsd/monitor.rs +new file mode 100644 +index 000000000000..174c11d8955c +--- /dev/null ++++ dom/webauthn/u2f-hid-rs/src/freebsd/monitor.rs +@@ -0,0 +1,139 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++use devd_rs; ++use std::collections::HashMap; ++use std::ffi::OsString; ++use std::sync::Arc; ++use std::{fs, io}; ++ ++use runloop::RunLoop; ++ ++const POLL_TIMEOUT: usize = 100; ++ ++pub enum Event { ++ Add(OsString), ++ Remove(OsString), ++} ++ ++impl Event { ++ fn from_devd(event: devd_rs::Event) -> Option { ++ match event { ++ devd_rs::Event::Attach { ++ ref dev, ++ parent: _, ++ location: _, ++ } if dev.starts_with("uhid") => ++ { ++ Some(Event::Add(("/dev/".to_owned() + dev).into())) ++ } ++ devd_rs::Event::Detach { ++ ref dev, ++ parent: _, ++ location: _, ++ } if dev.starts_with("uhid") => ++ { ++ Some(Event::Remove(("/dev/".to_owned() + dev).into())) ++ } ++ _ => None, ++ } ++ } ++} ++ ++fn convert_error(e: devd_rs::Error) -> io::Error { ++ e.into() ++} ++ ++pub struct Monitor ++where ++ F: Fn(OsString, &Fn() -> bool) + Sync, ++{ ++ runloops: HashMap, ++ new_device_cb: Arc, ++} ++ ++impl Monitor ++where ++ F: Fn(OsString, &Fn() -> bool) + Send + Sync + 'static, ++{ ++ pub fn new(new_device_cb: F) -> Self { ++ Self { ++ runloops: HashMap::new(), ++ new_device_cb: Arc::new(new_device_cb), ++ } ++ } ++ ++ pub fn run(&mut self, alive: &Fn() -> bool) -> io::Result<()> { ++ let mut ctx = devd_rs::Context::new().map_err(convert_error)?; ++ ++ // Iterate all existing devices. ++ for dev in fs::read_dir("/dev")? { ++ if let Ok(dev) = dev { ++ let filename_ = dev.file_name(); ++ let filename = filename_.to_str().unwrap_or(""); ++ if filename.starts_with("uhid") { ++ self.add_device(("/dev/".to_owned() + filename).into()); ++ } ++ } ++ } ++ ++ // Loop until we're stopped by the controlling thread, or fail. ++ while alive() { ++ // Wait for new events, break on failure. ++ match ctx.wait_for_event(POLL_TIMEOUT) { ++ Err(devd_rs::Error::Timeout) => (), ++ Err(e) => return Err(e.into()), ++ Ok(event) => { ++ if let Some(event) = Event::from_devd(event) { ++ self.process_event(event); ++ } ++ } ++ } ++ } ++ ++ // Remove all tracked devices. ++ self.remove_all_devices(); ++ ++ Ok(()) ++ } ++ ++ fn process_event(&mut self, event: Event) { ++ match event { ++ Event::Add(path) => { ++ self.add_device(path); ++ } ++ Event::Remove(path) => { ++ self.remove_device(path); ++ } ++ } ++ } ++ ++ fn add_device(&mut self, path: OsString) { ++ let f = self.new_device_cb.clone(); ++ let key = path.clone(); ++ ++ let runloop = RunLoop::new(move |alive| { ++ if alive() { ++ f(path, alive); ++ } ++ }); ++ ++ if let Ok(runloop) = runloop { ++ self.runloops.insert(key, runloop); ++ } ++ } ++ ++ fn remove_device(&mut self, path: OsString) { ++ if let Some(runloop) = self.runloops.remove(&path) { ++ runloop.cancel(); ++ } ++ } ++ ++ fn remove_all_devices(&mut self) { ++ while !self.runloops.is_empty() { ++ let path = self.runloops.keys().next().unwrap().clone(); ++ self.remove_device(path); ++ } ++ } ++} +diff --git dom/webauthn/u2f-hid-rs/src/freebsd/transaction.rs dom/webauthn/u2f-hid-rs/src/freebsd/transaction.rs +new file mode 100644 +index 000000000000..8f5ed990c8a0 +--- /dev/null ++++ dom/webauthn/u2f-hid-rs/src/freebsd/transaction.rs +@@ -0,0 +1,48 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++use platform::monitor::Monitor; ++use runloop::RunLoop; ++use std::ffi::OsString; ++use util::OnceCallback; ++ ++pub struct Transaction { ++ // Handle to the thread loop. ++ thread: Option, ++} ++ ++impl Transaction { ++ pub fn new( ++ timeout: u64, ++ callback: OnceCallback, ++ new_device_cb: F, ++ ) -> Result ++ where ++ F: Fn(OsString, &Fn() -> bool) + Sync + Send + 'static, ++ T: 'static, ++ { ++ let thread = RunLoop::new_with_timeout( ++ move |alive| { ++ // Create a new device monitor. ++ let mut monitor = Monitor::new(new_device_cb); ++ ++ // Start polling for new devices. ++ try_or!(monitor.run(alive), |_| callback.call(Err(::Error::Unknown))); ++ ++ // Send an error, if the callback wasn't called already. ++ callback.call(Err(::Error::NotAllowed)); ++ }, ++ timeout, ++ ).map_err(|_| ::Error::Unknown)?; ++ ++ Ok(Self { ++ thread: Some(thread), ++ }) ++ } ++ ++ pub fn cancel(&mut self) { ++ // This must never be None. ++ self.thread.take().unwrap().cancel(); ++ } ++} +diff --git dom/webauthn/u2f-hid-rs/src/freebsd/uhid.rs dom/webauthn/u2f-hid-rs/src/freebsd/uhid.rs +new file mode 100644 +index 000000000000..dc7fd0ca7a3f +--- /dev/null ++++ dom/webauthn/u2f-hid-rs/src/freebsd/uhid.rs +@@ -0,0 +1,90 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++extern crate libc; ++ ++use std::io; ++use std::os::unix::io::RawFd; ++use std::ptr; ++ ++use hidproto::*; ++use util::from_unix_result; ++ ++#[allow(non_camel_case_types)] ++#[repr(C)] ++#[derive(Debug)] ++pub struct GenDescriptor { ++ ugd_data: *mut u8, ++ ugd_lang_id: u16, ++ ugd_maxlen: u16, ++ ugd_actlen: u16, ++ ugd_offset: u16, ++ ugd_config_index: u8, ++ ugd_string_index: u8, ++ ugd_iface_index: u8, ++ ugd_altif_index: u8, ++ ugd_endpt_index: u8, ++ ugd_report_index: u8, ++ reserved: [u8; 16], ++} ++ ++impl Default for GenDescriptor { ++ fn default() -> GenDescriptor { ++ GenDescriptor { ++ ugd_data: ptr::null_mut(), ++ ugd_lang_id: 0, ++ ugd_maxlen: 65535, ++ ugd_actlen: 0, ++ ugd_offset: 0, ++ ugd_config_index: 0, ++ ugd_string_index: 0, ++ ugd_iface_index: 0, ++ ugd_altif_index: 0, ++ ugd_endpt_index: 0, ++ ugd_report_index: 0, ++ reserved: [0; 16], ++ } ++ } ++} ++ ++const IOWR: u32 = 0x40000000 | 0x80000000; ++ ++const IOCPARM_SHIFT: u32 = 13; ++const IOCPARM_MASK: u32 = ((1 << IOCPARM_SHIFT) - 1); ++ ++const TYPESHIFT: u32 = 8; ++const SIZESHIFT: u32 = 16; ++ ++macro_rules! ioctl { ++ ($dir:expr, $name:ident, $ioty:expr, $nr:expr, $size:expr; $ty:ty) => { ++ pub unsafe fn $name(fd: libc::c_int, val: *mut $ty) -> io::Result { ++ let ioc = ($dir as u32) | (($size as u32 & IOCPARM_MASK) << SIZESHIFT) ++ | (($ioty as u32) << TYPESHIFT) | ($nr as u32); ++ from_unix_result(libc::ioctl(fd, ioc as libc::c_ulong, val)) ++ } ++ }; ++} ++ ++// https://github.com/freebsd/freebsd/blob/master/sys/dev/usb/usb_ioctl.h ++ioctl!(IOWR, usb_get_report_desc, b'U', 21, 32; /*struct*/ GenDescriptor); ++ ++fn read_report_descriptor(fd: RawFd) -> io::Result { ++ let mut desc = GenDescriptor::default(); ++ let _ = unsafe { usb_get_report_desc(fd, &mut desc)? }; ++ desc.ugd_maxlen = desc.ugd_actlen; ++ let mut value = Vec::with_capacity(desc.ugd_actlen as usize); ++ unsafe { ++ value.set_len(desc.ugd_actlen as usize); ++ } ++ desc.ugd_data = value.as_mut_ptr(); ++ let _ = unsafe { usb_get_report_desc(fd, &mut desc)? }; ++ Ok(ReportDescriptor { value }) ++} ++ ++pub fn is_u2f_device(fd: RawFd) -> bool { ++ match read_report_descriptor(fd) { ++ Ok(desc) => has_fido_usage(desc), ++ Err(_) => false, // Upon failure, just say it's not a U2F device. ++ } ++} +diff --git dom/webauthn/u2f-hid-rs/src/hidproto.rs dom/webauthn/u2f-hid-rs/src/hidproto.rs +new file mode 100644 +index 000000000000..ea30890e0e1e +--- /dev/null ++++ dom/webauthn/u2f-hid-rs/src/hidproto.rs +@@ -0,0 +1,158 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++// Shared code for platforms that use raw HID access (Linux, FreeBSD, etc.) ++ ++use std::mem; ++ ++use consts::{FIDO_USAGE_U2FHID, FIDO_USAGE_PAGE}; ++ ++// The 4 MSBs (the tag) are set when it's a long item. ++const HID_MASK_LONG_ITEM_TAG: u8 = 0b11110000; ++// The 2 LSBs denote the size of a short item. ++const HID_MASK_SHORT_ITEM_SIZE: u8 = 0b00000011; ++// The 6 MSBs denote the tag (4) and type (2). ++const HID_MASK_ITEM_TAGTYPE: u8 = 0b11111100; ++// tag=0000, type=10 (local) ++const HID_ITEM_TAGTYPE_USAGE: u8 = 0b00001000; ++// tag=0000, type=01 (global) ++const HID_ITEM_TAGTYPE_USAGE_PAGE: u8 = 0b00000100; ++ ++pub struct ReportDescriptor { ++ pub value: Vec, ++} ++ ++impl ReportDescriptor { ++ fn iter(self) -> ReportDescriptorIterator { ++ ReportDescriptorIterator::new(self) ++ } ++} ++ ++#[derive(Debug)] ++pub enum Data { ++ UsagePage { data: u32 }, ++ Usage { data: u32 }, ++} ++ ++pub struct ReportDescriptorIterator { ++ desc: ReportDescriptor, ++ pos: usize, ++} ++ ++impl ReportDescriptorIterator { ++ fn new(desc: ReportDescriptor) -> Self { ++ Self { desc, pos: 0 } ++ } ++ ++ fn next_item(&mut self) -> Option { ++ let item = get_hid_item(&self.desc.value[self.pos..]); ++ if item.is_none() { ++ self.pos = self.desc.value.len(); // Close, invalid data. ++ return None; ++ } ++ ++ let (tag_type, key_len, data) = item.unwrap(); ++ ++ // Advance if we have a valid item. ++ self.pos += key_len + data.len(); ++ ++ // We only check short items. ++ if key_len > 1 { ++ return None; // Check next item. ++ } ++ ++ // Short items have max. length of 4 bytes. ++ assert!(data.len() <= mem::size_of::()); ++ ++ // Convert data bytes to a uint. ++ let data = read_uint_le(data); ++ ++ match tag_type { ++ HID_ITEM_TAGTYPE_USAGE_PAGE => Some(Data::UsagePage { data }), ++ HID_ITEM_TAGTYPE_USAGE => Some(Data::Usage { data }), ++ _ => None, ++ } ++ } ++} ++ ++impl Iterator for ReportDescriptorIterator { ++ type Item = Data; ++ ++ fn next(&mut self) -> Option { ++ if self.pos >= self.desc.value.len() { ++ return None; ++ } ++ ++ self.next_item().or_else(|| self.next()) ++ } ++} ++ ++fn get_hid_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> { ++ if (buf[0] & HID_MASK_LONG_ITEM_TAG) == HID_MASK_LONG_ITEM_TAG { ++ get_hid_long_item(buf) ++ } else { ++ get_hid_short_item(buf) ++ } ++} ++ ++fn get_hid_long_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> { ++ // A valid long item has at least three bytes. ++ if buf.len() < 3 { ++ return None; ++ } ++ ++ let len = buf[1] as usize; ++ ++ // Ensure that there are enough bytes left in the buffer. ++ if len > buf.len() - 3 { ++ return None; ++ } ++ ++ Some((buf[2], 3 /* key length */, &buf[3..])) ++} ++ ++fn get_hid_short_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> { ++ // This is a short item. The bottom two bits of the key ++ // contain the length of the data section (value) for this key. ++ let len = match buf[0] & HID_MASK_SHORT_ITEM_SIZE { ++ s @ 0...2 => s as usize, ++ _ => 4, /* _ == 3 */ ++ }; ++ ++ // Ensure that there are enough bytes left in the buffer. ++ if len > buf.len() - 1 { ++ return None; ++ } ++ ++ Some(( ++ buf[0] & HID_MASK_ITEM_TAGTYPE, ++ 1, /* key length */ ++ &buf[1..1 + len], ++ )) ++} ++ ++fn read_uint_le(buf: &[u8]) -> u32 { ++ assert!(buf.len() <= 4); ++ // Parse the number in little endian byte order. ++ buf.iter().rev().fold(0, |num, b| (num << 8) | (*b as u32)) ++} ++ ++pub fn has_fido_usage(desc: ReportDescriptor) -> bool { ++ let mut usage_page = None; ++ let mut usage = None; ++ ++ for data in desc.iter() { ++ match data { ++ Data::UsagePage { data } => usage_page = Some(data), ++ Data::Usage { data } => usage = Some(data), ++ } ++ ++ // Check the values we found. ++ if let (Some(usage_page), Some(usage)) = (usage_page, usage) { ++ return usage_page == FIDO_USAGE_PAGE as u32 && usage == FIDO_USAGE_U2FHID as u32; ++ } ++ } ++ ++ false ++} +diff --git dom/webauthn/u2f-hid-rs/src/lib.rs dom/webauthn/u2f-hid-rs/src/lib.rs +index 1307497e91ac..e0cdc5080924 100644 +--- dom/webauthn/u2f-hid-rs/src/lib.rs ++++ dom/webauthn/u2f-hid-rs/src/lib.rs +@@ -5,6 +5,9 @@ + #[macro_use] + mod util; + ++#[cfg(any(target_os = "linux", target_os = "freebsd"))] ++pub mod hidproto; ++ + #[cfg(any(target_os = "linux"))] + extern crate libudev; + +@@ -12,6 +15,13 @@ extern crate libudev; + #[path = "linux/mod.rs"] + pub mod platform; + ++#[cfg(any(target_os = "freebsd"))] ++extern crate devd_rs; ++ ++#[cfg(any(target_os = "freebsd"))] ++#[path = "freebsd/mod.rs"] ++pub mod platform; ++ + #[cfg(any(target_os = "macos"))] + extern crate core_foundation_sys; + +@@ -23,7 +33,9 @@ pub mod platform; + #[path = "windows/mod.rs"] + pub mod platform; + +-#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] ++#[cfg( ++ not(any(target_os = "linux", target_os = "freebsd", target_os = "macos", target_os = "windows")) ++)] + #[path = "stub/mod.rs"] + pub mod platform; + +@@ -39,8 +51,8 @@ extern crate bitflags; + + mod consts; + mod statemachine; +-mod u2ftypes; + mod u2fprotocol; ++mod u2ftypes; + + mod manager; + pub use manager::U2FManager; +@@ -88,9 +100,9 @@ pub enum Error { + NotAllowed = 5, + } + ++#[cfg(fuzzing)] ++pub use consts::*; + #[cfg(fuzzing)] + pub use u2fprotocol::*; + #[cfg(fuzzing)] + pub use u2ftypes::*; +-#[cfg(fuzzing)] +-pub use consts::*; +diff --git dom/webauthn/u2f-hid-rs/src/linux/device.rs dom/webauthn/u2f-hid-rs/src/linux/device.rs +index 6ed57106920f..35569f88a190 100644 +--- dom/webauthn/u2f-hid-rs/src/linux/device.rs ++++ dom/webauthn/u2f-hid-rs/src/linux/device.rs +@@ -11,8 +11,8 @@ use std::os::unix::prelude::*; + + use consts::CID_BROADCAST; + use platform::hidraw; +-use util::from_unix_result; + use u2ftypes::U2FDevice; ++use util::from_unix_result; + + #[derive(Debug)] + pub struct Device { +diff --git dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs +index 0ce5d379c3f7..182fe0ec5f2e 100644 +--- dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs ++++ dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs +@@ -8,22 +8,16 @@ use std::io; + use std::mem; + use std::os::unix::io::RawFd; + +-use consts::{FIDO_USAGE_U2FHID, FIDO_USAGE_PAGE}; ++use hidproto::*; + use util::{from_unix_result, io_err}; + + #[allow(non_camel_case_types)] + #[repr(C)] +-pub struct ReportDescriptor { ++pub struct LinuxReportDescriptor { + size: ::libc::c_int, + value: [u8; 4096], + } + +-impl ReportDescriptor { +- fn iter(self) -> ReportDescriptorIterator { +- ReportDescriptorIterator::new(self) +- } +-} +- + const NRBITS: u32 = 8; + const TYPEBITS: u32 = 8; + +@@ -35,28 +29,15 @@ const TYPESHIFT: u32 = NRSHIFT + NRBITS as u32; + const SIZESHIFT: u32 = TYPESHIFT + TYPEBITS as u32; + const DIRSHIFT: u32 = SIZESHIFT + SIZEBITS as u32; + +-// The 4 MSBs (the tag) are set when it's a long item. +-const HID_MASK_LONG_ITEM_TAG: u8 = 0b11110000; +-// The 2 LSBs denote the size of a short item. +-const HID_MASK_SHORT_ITEM_SIZE: u8 = 0b00000011; +-// The 6 MSBs denote the tag (4) and type (2). +-const HID_MASK_ITEM_TAGTYPE: u8 = 0b11111100; +-// tag=0000, type=10 (local) +-const HID_ITEM_TAGTYPE_USAGE: u8 = 0b00001000; +-// tag=0000, type=01 (global) +-const HID_ITEM_TAGTYPE_USAGE_PAGE: u8 = 0b00000100; +- + // https://github.com/torvalds/linux/blob/master/include/uapi/linux/hid.h + const HID_MAX_DESCRIPTOR_SIZE: usize = 4096; + + macro_rules! ioctl { +- ($dir:expr, $name:ident, $ioty:expr, $nr:expr; $ty:ty) => ( ++ ($dir:expr, $name:ident, $ioty:expr, $nr:expr; $ty:ty) => { + pub unsafe fn $name(fd: libc::c_int, val: *mut $ty) -> io::Result { + let size = mem::size_of::<$ty>(); +- let ioc = (($dir as u32) << DIRSHIFT) | +- (($ioty as u32) << TYPESHIFT) | +- (($nr as u32) << NRSHIFT) | +- ((size as u32) << SIZESHIFT); ++ let ioc = (($dir as u32) << DIRSHIFT) | (($ioty as u32) << TYPESHIFT) ++ | (($nr as u32) << NRSHIFT) | ((size as u32) << SIZESHIFT); + + #[cfg(not(target_env = "musl"))] + type IocType = libc::c_ulong; +@@ -65,120 +46,12 @@ macro_rules! ioctl { + + from_unix_result(libc::ioctl(fd, ioc as IocType, val)) + } +- ); ++ }; + } + + // https://github.com/torvalds/linux/blob/master/include/uapi/linux/hidraw.h + ioctl!(READ, hidiocgrdescsize, b'H', 0x01; ::libc::c_int); +-ioctl!(READ, hidiocgrdesc, b'H', 0x02; /*struct*/ ReportDescriptor); +- +-enum Data { +- UsagePage { data: u32 }, +- Usage { data: u32 }, +-} +- +-struct ReportDescriptorIterator { +- desc: ReportDescriptor, +- pos: usize, +-} +- +-impl ReportDescriptorIterator { +- fn new(desc: ReportDescriptor) -> Self { +- Self { desc, pos: 0 } +- } +- +- fn next_item(&mut self) -> Option { +- let item = get_hid_item(&self.desc.value[self.pos..]); +- if item.is_none() { +- self.pos = self.desc.size as usize; // Close, invalid data. +- return None; +- } +- +- let (tag_type, key_len, data) = item.unwrap(); +- +- // Advance if we have a valid item. +- self.pos += key_len + data.len(); +- +- // We only check short items. +- if key_len > 1 { +- return None; // Check next item. +- } +- +- // Short items have max. length of 4 bytes. +- assert!(data.len() <= mem::size_of::()); +- +- // Convert data bytes to a uint. +- let data = read_uint_le(data); +- +- match tag_type { +- HID_ITEM_TAGTYPE_USAGE_PAGE => Some(Data::UsagePage { data }), +- HID_ITEM_TAGTYPE_USAGE => Some(Data::Usage { data }), +- _ => None, +- } +- } +-} +- +-impl Iterator for ReportDescriptorIterator { +- type Item = Data; +- +- fn next(&mut self) -> Option { +- if self.pos >= self.desc.size as usize { +- return None; +- } +- +- self.next_item().or_else(|| self.next()) +- } +-} +- +-fn get_hid_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> { +- if (buf[0] & HID_MASK_LONG_ITEM_TAG) == HID_MASK_LONG_ITEM_TAG { +- get_hid_long_item(buf) +- } else { +- get_hid_short_item(buf) +- } +-} +- +-fn get_hid_long_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> { +- // A valid long item has at least three bytes. +- if buf.len() < 3 { +- return None; +- } +- +- let len = buf[1] as usize; +- +- // Ensure that there are enough bytes left in the buffer. +- if len > buf.len() - 3 { +- return None; +- } +- +- Some((buf[2], 3 /* key length */, &buf[3..])) +-} +- +-fn get_hid_short_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> { +- // This is a short item. The bottom two bits of the key +- // contain the length of the data section (value) for this key. +- let len = match buf[0] & HID_MASK_SHORT_ITEM_SIZE { +- s @ 0...2 => s as usize, +- _ => 4, /* _ == 3 */ +- }; +- +- // Ensure that there are enough bytes left in the buffer. +- if len > buf.len() - 1 { +- return None; +- } +- +- Some(( +- buf[0] & HID_MASK_ITEM_TAGTYPE, +- 1, /* key length */ +- &buf[1..1 + len], +- )) +-} +- +-fn read_uint_le(buf: &[u8]) -> u32 { +- assert!(buf.len() <= 4); +- // Parse the number in little endian byte order. +- buf.iter().rev().fold(0, |num, b| (num << 8) | (*b as u32)) +-} ++ioctl!(READ, hidiocgrdesc, b'H', 0x02; /*struct*/ LinuxReportDescriptor); + + pub fn is_u2f_device(fd: RawFd) -> bool { + match read_report_descriptor(fd) { +@@ -188,7 +61,7 @@ pub fn is_u2f_device(fd: RawFd) -> bool { + } + + fn read_report_descriptor(fd: RawFd) -> io::Result { +- let mut desc = ReportDescriptor { ++ let mut desc = LinuxReportDescriptor { + size: 0, + value: [0; HID_MAX_DESCRIPTOR_SIZE], + }; +@@ -199,24 +72,7 @@ fn read_report_descriptor(fd: RawFd) -> io::Result { + } + + let _ = unsafe { hidiocgrdesc(fd, &mut desc)? }; +- Ok(desc) +-} +- +-fn has_fido_usage(desc: ReportDescriptor) -> bool { +- let mut usage_page = None; +- let mut usage = None; +- +- for data in desc.iter() { +- match data { +- Data::UsagePage { data } => usage_page = Some(data), +- Data::Usage { data } => usage = Some(data), +- } +- +- // Check the values we found. +- if let (Some(usage_page), Some(usage)) = (usage_page, usage) { +- return usage_page == FIDO_USAGE_PAGE as u32 && usage == FIDO_USAGE_U2FHID as u32; +- } +- } +- +- false ++ let mut value = Vec::from(&desc.value[..]); ++ value.truncate(desc.size as usize); ++ Ok(ReportDescriptor { value }) + } +diff --git dom/webauthn/u2f-hid-rs/src/linux/monitor.rs dom/webauthn/u2f-hid-rs/src/linux/monitor.rs +index 47c376ba9176..408ea4b7b9ad 100644 +--- dom/webauthn/u2f-hid-rs/src/linux/monitor.rs ++++ dom/webauthn/u2f-hid-rs/src/linux/monitor.rs +@@ -65,13 +65,11 @@ where + + // Start listening for new devices. + let mut socket = monitor.listen()?; +- let mut fds = vec![ +- ::libc::pollfd { +- fd: socket.as_raw_fd(), +- events: POLLIN, +- revents: 0, +- }, +- ]; ++ let mut fds = vec![::libc::pollfd { ++ fd: socket.as_raw_fd(), ++ events: POLLIN, ++ revents: 0, ++ }]; + + while alive() { + // Wait for new events, break on failure. +diff --git dom/webauthn/u2f-hid-rs/src/macos/iokit.rs dom/webauthn/u2f-hid-rs/src/macos/iokit.rs +index 7e550af2a445..79e53599004e 100644 +--- dom/webauthn/u2f-hid-rs/src/macos/iokit.rs ++++ dom/webauthn/u2f-hid-rs/src/macos/iokit.rs +@@ -282,13 +282,13 @@ extern "C" { + + #[cfg(test)] + mod tests { ++ use super::*; + use core_foundation_sys::base::*; + use core_foundation_sys::runloop::*; + use libc::c_void; + use std::ptr; + use std::sync::mpsc::{channel, Sender}; + use std::thread; +- use super::*; + + extern "C" fn observe(_: CFRunLoopObserverRef, _: CFRunLoopActivity, context: *mut c_void) { + let tx: &Sender = unsafe { &*(context as *mut _) }; +diff --git dom/webauthn/u2f-hid-rs/src/macos/monitor.rs dom/webauthn/u2f-hid-rs/src/macos/monitor.rs +index c346fe5eff57..b971ed885d18 100644 +--- dom/webauthn/u2f-hid-rs/src/macos/monitor.rs ++++ dom/webauthn/u2f-hid-rs/src/macos/monitor.rs +@@ -10,9 +10,9 @@ use core_foundation_sys::runloop::*; + use libc::c_void; + use platform::iokit::*; + use runloop::RunLoop; +-use std::{io, slice}; + use std::collections::HashMap; + use std::sync::mpsc::{channel, Receiver, Sender}; ++use std::{io, slice}; + use util::io_err; + + struct DeviceData { +diff --git dom/webauthn/u2f-hid-rs/src/manager.rs dom/webauthn/u2f-hid-rs/src/manager.rs +index c9f92bdbfad5..ca8b80a9584a 100644 +--- dom/webauthn/u2f-hid-rs/src/manager.rs ++++ dom/webauthn/u2f-hid-rs/src/manager.rs +@@ -7,8 +7,8 @@ use std::sync::mpsc::{channel, RecvTimeoutError, Sender}; + use std::time::Duration; + + use consts::PARAMETER_SIZE; +-use statemachine::StateMachine; + use runloop::RunLoop; ++use statemachine::StateMachine; + use util::OnceCallback; + + enum QueueAction { +diff --git dom/webauthn/u2f-hid-rs/src/statemachine.rs dom/webauthn/u2f-hid-rs/src/statemachine.rs +index 8e4abaa7cf02..55e7d36155a3 100644 +--- dom/webauthn/u2f-hid-rs/src/statemachine.rs ++++ dom/webauthn/u2f-hid-rs/src/statemachine.rs +@@ -7,8 +7,8 @@ use platform::device::Device; + use platform::transaction::Transaction; + use std::thread; + use std::time::Duration; +-use util::OnceCallback; + use u2fprotocol::{u2f_init_device, u2f_is_keyhandle_valid, u2f_register, u2f_sign}; ++use util::OnceCallback; + + fn is_valid_transport(transports: ::AuthenticatorTransports) -> bool { + transports.is_empty() || transports.contains(::AuthenticatorTransports::USB) +diff --git dom/webauthn/u2f-hid-rs/src/u2fprotocol.rs dom/webauthn/u2f-hid-rs/src/u2fprotocol.rs +index 4d6737b1289e..0b984407d873 100644 +--- dom/webauthn/u2f-hid-rs/src/u2fprotocol.rs ++++ dom/webauthn/u2f-hid-rs/src/u2fprotocol.rs +@@ -5,9 +5,9 @@ + extern crate std; + + use rand::{thread_rng, Rng}; ++use std::ffi::CString; + use std::io; + use std::io::{Read, Write}; +-use std::ffi::CString; + + use consts::*; + use u2ftypes::*; +diff --git dom/webauthn/u2f-hid-rs/src/util.rs dom/webauthn/u2f-hid-rs/src/util.rs +index 27db864e2fcd..770e166d57d2 100644 +--- dom/webauthn/u2f-hid-rs/src/util.rs ++++ dom/webauthn/u2f-hid-rs/src/util.rs +@@ -12,10 +12,12 @@ use boxfnonce::SendBoxFnOnce; + macro_rules! try_or { + ($val:expr, $or:expr) => { + match $val { +- Ok(v) => { v } +- Err(e) => { return $or(e); } ++ Ok(v) => v, ++ Err(e) => { ++ return $or(e); ++ } + } +- } ++ }; + } + + pub trait Signed { +@@ -44,6 +46,16 @@ pub fn from_unix_result(rv: T) -> io::Result { + } + } + ++#[cfg(any(target_os = "freebsd"))] ++pub fn from_unix_result(rv: T) -> io::Result { ++ if rv.is_negative() { ++ let errno = unsafe { *libc::__error() }; ++ Err(io::Error::from_raw_os_error(errno)) ++ } else { ++ Ok(rv) ++ } ++} ++ + pub fn io_err(msg: &str) -> io::Error { + io::Error::new(io::ErrorKind::Other, msg) + } +diff --git dom/webauthn/u2f-hid-rs/src/windows/device.rs dom/webauthn/u2f-hid-rs/src/windows/device.rs +index cbbe2811d672..5579cc052a6f 100644 +--- dom/webauthn/u2f-hid-rs/src/windows/device.rs ++++ dom/webauthn/u2f-hid-rs/src/windows/device.rs +@@ -7,8 +7,8 @@ use std::io; + use std::io::{Read, Write}; + use std::os::windows::io::AsRawHandle; + +-use consts::{FIDO_USAGE_U2FHID, CID_BROADCAST, FIDO_USAGE_PAGE, HID_RPT_SIZE}; + use super::winapi::DeviceCapabilities; ++use consts::{FIDO_USAGE_U2FHID, CID_BROADCAST, FIDO_USAGE_PAGE, HID_RPT_SIZE}; + + use u2ftypes::U2FDevice; + +diff --git dom/webauthn/u2f-hid-rs/src/windows/winapi.rs dom/webauthn/u2f-hid-rs/src/windows/winapi.rs +index 18c6898e86ee..bd8a7e58d06a 100644 +--- dom/webauthn/u2f-hid-rs/src/windows/winapi.rs ++++ dom/webauthn/u2f-hid-rs/src/windows/winapi.rs +@@ -60,7 +60,7 @@ extern "stdcall" { + macro_rules! offset_of { + ($ty:ty, $field:ident) => { + unsafe { &(*(0 as *const $ty)).$field as *const _ as usize } +- } ++ }; + } + + fn from_wide_ptr(ptr: *const u16, len: usize) -> String { +diff --git third_party/rust/devd-rs/.cargo-checksum.json third_party/rust/devd-rs/.cargo-checksum.json +new file mode 100644 +index 000000000000..7f8c6af3141e +--- /dev/null ++++ third_party/rust/devd-rs/.cargo-checksum.json +@@ -0,0 +1 @@ ++{"files":{".rustfmt.toml":"2af0439152afb5f592e67eb815db1a2711e3951d94d6ec2a3343ccf17cf7eb53","CODE_OF_CONDUCT.md":"62f073941a34756006851cef8d5d081f6332a986063e87deafeb621f3f6ff554","Cargo.toml":"82c3a9280afb5f4ac916fbca17ca4913b9f66f90c28eb48be1b66f5efe363e87","README.md":"27a78f684d46d92d64bdda18e8b55f132960836347a654d4024ede000e980bec","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","examples/main.rs":"734a87846b61d09d2aaca444c69dc61765f66df34602f3a4acf1255f95404226","src/data.rs":"677b52a636deb1f0ffc623dbdc5ed7acd78d915117825ced7031c6fa6f0c861e","src/lib.rs":"5e1539f2e197214f90cdcb5835c9b082773b0cd18f6c18e03067ebe04f18a6b7","src/parser.rs":"8459eed676eb9190f592b159d099d542bbcc447d6fb19b46f7a61c60a1ef8a8e","src/result.rs":"4088fc879652c115a13d8a6e6a71fab8571a7982e740af6a91115f3a82aef236"},"package":"e7c9ac481c38baf400d3b732e4a06850dfaa491d1b6379a249d9d40d14c2434c"} +\ No newline at end of file +diff --git third_party/rust/devd-rs/.rustfmt.toml third_party/rust/devd-rs/.rustfmt.toml +new file mode 100644 +index 000000000000..6be7cd87020f +--- /dev/null ++++ third_party/rust/devd-rs/.rustfmt.toml +@@ -0,0 +1,9 @@ ++max_width = 256 ++fn_call_width = 96 ++struct_lit_width = 64 ++struct_variant_width = 96 ++array_width = 256 ++newline_style = "Native" ++use_try_shorthand = true ++match_block_trailing_comma = true ++fn_call_style = "Block" +diff --git third_party/rust/devd-rs/CODE_OF_CONDUCT.md third_party/rust/devd-rs/CODE_OF_CONDUCT.md +new file mode 100644 +index 000000000000..a375db8308be +--- /dev/null ++++ third_party/rust/devd-rs/CODE_OF_CONDUCT.md +@@ -0,0 +1,74 @@ ++# Contributor Covenant Code of Conduct ++ ++## Our Pledge ++ ++In the interest of fostering an open and welcoming environment, we as ++contributors and maintainers pledge to making participation in our project and ++our community a harassment-free experience for everyone, regardless of age, body ++size, disability, ethnicity, gender identity and expression, level of experience, ++nationality, personal appearance, race, religion, or sexual identity and ++orientation. ++ ++## Our Standards ++ ++Examples of behavior that contributes to creating a positive environment ++include: ++ ++* Using welcoming and inclusive language ++* Being respectful of differing viewpoints and experiences ++* Gracefully accepting constructive criticism ++* Focusing on what is best for the community ++* Showing empathy towards other community members ++ ++Examples of unacceptable behavior by participants include: ++ ++* The use of sexualized language or imagery and unwelcome sexual attention or ++advances ++* Trolling, insulting/derogatory comments, and personal or political attacks ++* Public or private harassment ++* Publishing others' private information, such as a physical or electronic ++ address, without explicit permission ++* Other conduct which could reasonably be considered inappropriate in a ++ professional setting ++ ++## Our Responsibilities ++ ++Project maintainers are responsible for clarifying the standards of acceptable ++behavior and are expected to take appropriate and fair corrective action in ++response to any instances of unacceptable behavior. ++ ++Project maintainers have the right and responsibility to remove, edit, or ++reject comments, commits, code, wiki edits, issues, and other contributions ++that are not aligned to this Code of Conduct, or to ban temporarily or ++permanently any contributor for other behaviors that they deem inappropriate, ++threatening, offensive, or harmful. ++ ++## Scope ++ ++This Code of Conduct applies both within project spaces and in public spaces ++when an individual is representing the project or its community. Examples of ++representing a project or community include using an official project e-mail ++address, posting via an official social media account, or acting as an appointed ++representative at an online or offline event. Representation of a project may be ++further defined and clarified by project maintainers. ++ ++## Enforcement ++ ++Instances of abusive, harassing, or otherwise unacceptable behavior may be ++reported by contacting the project owner at greg@unrelenting.technology. All ++complaints will be reviewed and investigated and will result in a response that ++is deemed necessary and appropriate to the circumstances. The project owner is ++obligated to maintain confidentiality with regard to the reporter of an incident. ++Further details of specific enforcement policies may be posted separately. ++ ++Project maintainers who do not follow or enforce the Code of Conduct in good ++faith may face temporary or permanent repercussions as determined by other ++members of the project's leadership. ++ ++## Attribution ++ ++This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, ++available at [http://contributor-covenant.org/version/1/4][version] ++ ++[homepage]: http://contributor-covenant.org ++[version]: http://contributor-covenant.org/version/1/4/ +diff --git third_party/rust/devd-rs/Cargo.toml third_party/rust/devd-rs/Cargo.toml +new file mode 100644 +index 000000000000..9c6f1250697f +--- /dev/null ++++ third_party/rust/devd-rs/Cargo.toml +@@ -0,0 +1,28 @@ ++# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO ++# ++# When uploading crates to the registry Cargo will automatically ++# "normalize" Cargo.toml files for maximal compatibility ++# with all versions of Cargo and also rewrite `path` dependencies ++# to registry (e.g. crates.io) dependencies ++# ++# If you believe there's an error in this file please file an ++# issue against the rust-lang/cargo repository. If you're ++# editing this file be aware that the upstream Cargo.toml ++# will likely look very different (and much more reasonable) ++ ++[package] ++name = "devd-rs" ++version = "0.2.1" ++authors = ["Greg V "] ++description = "An interface to devd, the device hotplug daemon on FreeBSD and DragonFlyBSD" ++homepage = "https://github.com/myfreeweb/devd-rs" ++readme = "README.md" ++keywords = ["System", "FreeBSD", "DragonFlyBSD", "devd", "hotplug"] ++categories = ["os::unix-apis"] ++license = "Unlicense/MIT" ++repository = "https://github.com/myfreeweb/devd-rs" ++[dependencies.libc] ++version = "0" ++ ++[dependencies.nom] ++version = "3.2" +diff --git third_party/rust/devd-rs/README.md third_party/rust/devd-rs/README.md +new file mode 100644 +index 000000000000..c10c4081f189 +--- /dev/null ++++ third_party/rust/devd-rs/README.md +@@ -0,0 +1,25 @@ ++[![crates.io](https://img.shields.io/crates/v/systemstat.svg)](https://crates.io/crates/systemstat) ++[![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](http://unlicense.org) ++ ++# devd-rs ++ ++A Rust library for listening to FreeBSD (also DragonFlyBSD) [devd](https://www.freebsd.org/cgi/man.cgi?devd)'s device attach-detach notifications. ++ ++Listens on `/var/run/devd.seqpacket.pipe` and parses messages using [nom](https://github.com/Geal/nom). ++ ++## Usage ++ ++See [examples/main.rs](https://github.com/myfreeweb/devd-rs/blob/master/examples/main.rs). ++ ++## Contributing ++ ++Please feel free to submit pull requests! ++ ++By participating in this project you agree to follow the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/4/). ++ ++[The list of contributors is available on GitHub](https://github.com/myfreeweb/devd-rs/graphs/contributors). ++ ++## License ++ ++This is free and unencumbered software released into the public domain. ++For more information, please refer to the `UNLICENSE` file or [unlicense.org](http://unlicense.org). +diff --git third_party/rust/devd-rs/UNLICENSE third_party/rust/devd-rs/UNLICENSE +new file mode 100644 +index 000000000000..68a49daad8ff +--- /dev/null ++++ third_party/rust/devd-rs/UNLICENSE +@@ -0,0 +1,24 @@ ++This is free and unencumbered software released into the public domain. ++ ++Anyone is free to copy, modify, publish, use, compile, sell, or ++distribute this software, either in source code form or as a compiled ++binary, for any purpose, commercial or non-commercial, and by any ++means. ++ ++In jurisdictions that recognize copyright laws, the author or authors ++of this software dedicate any and all copyright interest in the ++software to the public domain. We make this dedication for the benefit ++of the public at large and to the detriment of our heirs and ++successors. We intend this dedication to be an overt act of ++relinquishment in perpetuity of all present and future rights to this ++software under copyright law. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS 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. ++ ++For more information, please refer to +diff --git third_party/rust/devd-rs/examples/main.rs third_party/rust/devd-rs/examples/main.rs +new file mode 100644 +index 000000000000..fee8612f1e6b +--- /dev/null ++++ third_party/rust/devd-rs/examples/main.rs +@@ -0,0 +1,12 @@ ++extern crate devd_rs; ++ ++use devd_rs::*; ++ ++fn main() { ++ let mut ctx = Context::new().unwrap(); ++ loop { ++ if let Ok(ev) = ctx.wait_for_event(1000) { ++ println!("{:?}", ev); ++ } ++ } ++} +diff --git third_party/rust/devd-rs/src/data.rs third_party/rust/devd-rs/src/data.rs +new file mode 100644 +index 000000000000..52084362e537 +--- /dev/null ++++ third_party/rust/devd-rs/src/data.rs +@@ -0,0 +1,9 @@ ++pub use std::collections::BTreeMap; ++ ++#[derive(Debug, Clone, PartialEq)] ++pub enum Event { ++ Notify { system: String, subsystem: String, kind: String, data: BTreeMap }, ++ Attach { dev: String, parent: BTreeMap, location: String }, ++ Detach { dev: String, parent: BTreeMap, location: String }, ++ Nomatch { parent: BTreeMap, location: String }, ++} +diff --git third_party/rust/devd-rs/src/lib.rs third_party/rust/devd-rs/src/lib.rs +new file mode 100644 +index 000000000000..10e43a328c4d +--- /dev/null ++++ third_party/rust/devd-rs/src/lib.rs +@@ -0,0 +1,98 @@ ++extern crate libc; ++#[macro_use] ++extern crate nom; ++ ++pub mod result; ++pub mod data; ++pub mod parser; ++ ++use libc::{ ++ c_int, nfds_t, ++ poll, pollfd, POLLIN, ++ socket, connect, sockaddr_un, AF_UNIX, SOCK_SEQPACKET ++}; ++use std::os::unix::io::{FromRawFd, RawFd}; ++use std::os::unix::net::UnixStream; ++use std::{io, mem, ptr}; ++use io::{BufRead, BufReader}; ++ ++pub use result::*; ++pub use data::*; ++ ++const SOCKET_PATH: &'static str = "/var/run/devd.seqpacket.pipe"; ++ ++pub fn parse_devd_event(e: String) -> Result { ++ match parser::event(e.as_bytes()) { ++ parser::IResult::Done(_, x) => Ok(x), ++ _ => Err(Error::Parse), ++ } ++} ++ ++#[derive(Debug)] ++pub struct Context { ++ sock: BufReader, ++ sockfd: RawFd, ++} ++ ++impl Context { ++ pub fn new() -> Result { ++ unsafe { ++ let sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0); ++ if sockfd < 0 { ++ return Err(io::Error::last_os_error().into()); ++ } ++ let mut sockaddr = sockaddr_un { ++ sun_family: AF_UNIX as _, ++ .. mem::zeroed() ++ }; ++ ptr::copy_nonoverlapping( ++ SOCKET_PATH.as_ptr(), ++ sockaddr.sun_path.as_mut_ptr() as *mut u8, ++ SOCKET_PATH.len()); ++ if connect( ++ sockfd, ++ &sockaddr as *const sockaddr_un as *const _, ++ (mem::size_of_val(&AF_UNIX) + SOCKET_PATH.len()) as _) < 0 { ++ return Err(io::Error::last_os_error().into()); ++ } ++ Ok(Context { ++ sock: BufReader::new(UnixStream::from_raw_fd(sockfd)), ++ sockfd: sockfd, ++ }) ++ } ++ } ++ ++ /// Waits for an event using poll(), reads it but does not parse ++ pub fn wait_for_event_raw(&mut self, timeout_ms: usize) -> Result { ++ let mut fds = vec![pollfd { fd: self.sockfd, events: POLLIN, revents: 0 }]; ++ let x = unsafe { poll((&mut fds).as_mut_ptr(), fds.len() as nfds_t, timeout_ms as c_int) }; ++ if x < 0 { ++ Err(io::Error::last_os_error().into()) ++ } else if x == 0 { ++ Err(Error::Timeout) ++ } else { ++ let mut s = String::new(); ++ let _ = self.sock.read_line(&mut s); ++ Ok(s) ++ } ++ } ++ ++ /// Waits for an event using poll(), reads and parses it ++ pub fn wait_for_event<'a>(&mut self, timeout_ms: usize) -> Result { ++ self.wait_for_event_raw(timeout_ms) ++ .and_then(parse_devd_event) ++ } ++ ++ /// Returns the devd socket file descriptor in case you want to select/poll on it together with ++ /// other file descriptors ++ pub fn fd(&self) -> RawFd { ++ self.sockfd ++ } ++ ++ /// Reads an event and parses it. Use when polling on the raw fd by yourself ++ pub fn read_event(&mut self) -> Result { ++ let mut s = String::new(); ++ let _ = self.sock.read_line(&mut s); ++ parse_devd_event(s) ++ } ++} +diff --git third_party/rust/devd-rs/src/parser.rs third_party/rust/devd-rs/src/parser.rs +new file mode 100644 +index 000000000000..59e5a9ce60e3 +--- /dev/null ++++ third_party/rust/devd-rs/src/parser.rs +@@ -0,0 +1,164 @@ ++use std::str; ++use nom::{alphanumeric, multispace}; ++pub use nom::IResult; ++use data::*; ++ ++named!(key<&str>, map_res!(alphanumeric, str::from_utf8)); ++ ++named!( ++ val<&str>, ++ alt!(delimited!(char!('"'), map_res!(take_while!(call!(|c| c != '"' as u8)), str::from_utf8), char!('"')) | map_res!(take_while!(call!(|c| c != '\n' as u8 && c != ' ' as u8)), str::from_utf8)) ++); ++ ++named!(keyval <&[u8], (String, String)>, ++ do_parse!( ++ key: key ++ >> char!('=') ++ >> val: val ++ >> (key.to_owned(), val.to_owned()) ++ ) ++ ); ++ ++named!(keyvals <&[u8], BTreeMap >, ++ map!( ++ many0!(terminated!(keyval, opt!(multispace))), ++ |vec: Vec<_>| vec.into_iter().collect() ++ ) ++ ); ++ ++named!(pub event <&[u8], Event>, ++ alt!( ++ do_parse!( ++ tag!("!") >> ++ tag!("system=") >> ++ sys: val >> ++ multispace >> ++ tag!("subsystem=") >> ++ subsys: val >> ++ multispace >> ++ tag!("type=") >> ++ kind: val >> ++ multispace >> ++ data: keyvals >> ++ (Event::Notify { system: sys.to_owned(), subsystem: subsys.to_owned(), kind: kind.to_owned(), data: data }) ++ ) | ++ do_parse!( ++ tag!("+") >> ++ dev: key >> ++ multispace >> ++ tag!("at") >> ++ multispace >> ++ parent: keyvals >> ++ tag!("on") >> ++ multispace >> ++ loc: val >> ++ (Event::Attach { dev: dev.to_owned(), parent: parent, location: loc.to_owned() }) ++ ) | ++ do_parse!( ++ tag!("-") >> ++ dev: key >> ++ multispace >> ++ tag!("at") >> ++ multispace >> ++ parent: keyvals >> ++ tag!("on") >> ++ multispace >> ++ loc: val >> ++ (Event::Detach { dev: dev.to_owned(), parent: parent, location: loc.to_owned() }) ++ ) | ++ do_parse!( ++ tag!("?") >> ++ multispace >> ++ tag!("at") >> ++ multispace >> ++ parent: keyvals >> ++ tag!("on") >> ++ multispace >> ++ loc: val >> ++ (Event::Nomatch { parent: parent, location: loc.to_owned() }) ++ ) ++ ++ ++ ++ ++ ) ++ ); ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ ++ #[test] ++ fn test_notify() { ++ let txt = b"!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.2 vendor=0x1050 sernum=\"\" mode=host\n"; ++ let res = event(txt); ++ let mut data = BTreeMap::new(); ++ data.insert("ugen".to_owned(), "ugen0.2".to_owned()); ++ data.insert("vendor".to_owned(), "0x1050".to_owned()); ++ data.insert("sernum".to_owned(), "".to_owned()); ++ data.insert("mode".to_owned(), "host".to_owned()); ++ assert_eq!( ++ res, ++ IResult::Done( ++ &b""[..], ++ Event::Notify { ++ system: "USB".to_owned(), ++ subsystem: "INTERFACE".to_owned(), ++ kind: "ATTACH".to_owned(), ++ data: data, ++ } ++ ) ++ ) ++ } ++ ++ #[test] ++ fn test_attach() { ++ let txt = b"+uhid1 at bus=0 sernum=\"\" on uhub1"; ++ let res = event(txt); ++ let mut data = BTreeMap::new(); ++ data.insert("bus".to_owned(), "0".to_owned()); ++ data.insert("sernum".to_owned(), "".to_owned()); ++ assert_eq!( ++ res, ++ IResult::Done( ++ &b""[..], ++ Event::Attach { ++ dev: "uhid1".to_owned(), ++ parent: data, ++ location: "uhub1".to_owned(), ++ } ++ ) ++ ) ++ } ++ ++ #[test] ++ fn test_detach() { ++ let txt = b"-uhid1 at on uhub1"; ++ let res = event(txt); ++ let data = BTreeMap::new(); ++ assert_eq!( ++ res, ++ IResult::Done( ++ &b""[..], ++ Event::Detach { ++ dev: "uhid1".to_owned(), ++ parent: data.to_owned(), ++ location: "uhub1".to_owned(), ++ } ++ ) ++ ) ++ } ++ ++ #[test] ++ fn test_nomatch() { ++ let txt = b"? at bus=0 on uhub1"; ++ let res = event(txt); ++ let mut data = BTreeMap::new(); ++ data.insert("bus".to_owned(), "0".to_owned()); ++ assert_eq!( ++ res, ++ IResult::Done(&b""[..], Event::Nomatch { parent: data, location: "uhub1".to_owned() }) ++ ) ++ } ++ ++} +diff --git third_party/rust/devd-rs/src/result.rs third_party/rust/devd-rs/src/result.rs +new file mode 100644 +index 000000000000..481cd808ed93 +--- /dev/null ++++ third_party/rust/devd-rs/src/result.rs +@@ -0,0 +1,26 @@ ++use std::{io, result}; ++ ++#[derive(Debug)] ++pub enum Error { ++ IoError(io::Error), ++ Timeout, ++ Parse, ++} ++ ++impl Into for Error { ++ fn into(self) -> io::Error { ++ match self { ++ Error::IoError(e) => e, ++ Error::Timeout => io::Error::new(io::ErrorKind::Other, "devd poll timeout"), ++ Error::Parse => io::Error::new(io::ErrorKind::Other, "devd parse error"), ++ } ++ } ++} ++ ++impl From for Error { ++ fn from(err: io::Error) -> Error { ++ Error::IoError(err) ++ } ++} ++ ++pub type Result = result::Result; +diff --git third_party/rust/nom-1.2.4/.cargo-checksum.json third_party/rust/nom-1.2.4/.cargo-checksum.json +new file mode 100644 +index 000000000000..9d93bcc0afc2 +--- /dev/null ++++ third_party/rust/nom-1.2.4/.cargo-checksum.json +@@ -0,0 +1 @@ ++{"files":{".travis.yml":"6d4e81838b10c5e330749857c72c2f2b1a2e575e71abcd11c094f3b612347b2a","CHANGELOG.md":"d4722e028b2a5b88c466b0d759e463b90bdcfa1b79181a1c76cd313b0a27c615","Cargo.toml":"aebcb999933c3425db85012bea19f9ce78da8e7834dbab54d4a2966e8bc62149","LICENSE":"de730187d5563a81342a3c011d968f78dff37c934fac9b3701e8c762b6118a55","src/bits.rs":"97c9148f63e175489bb6199d039c594ddc56bdf0b7491b9f38b8d74e898bca80","src/bytes.rs":"8f29b976a5e8e6500eb618a9dead7f212688ba9eb06c7066a4016e2db99fed00","src/character.rs":"9ee081f56b508212231ff70d7455b1b85ae44722a39aa60223e8cd95c6570859","src/internal.rs":"ada499b9c178be2a7f9b56319ffb10a778f25fafcda39c78d26b364d89debd72","src/lib.rs":"34efb051214acfde2053e93a7ba718a4fd41b6e0d9edd65a1737605d99b994ab","src/macros.rs":"d39ce3a2cd2b1cb9dd57ce90c06a1ca84720a2dc75e6332cffebba6086cb75d3","src/methods.rs":"24bdbcb0e3570c8bf3fa270dd8d79dd6dfcb982276c82180a89a1e73c5e38019","src/nom.rs":"b0a9c7ce0d09388179bce8f8e23bf57df76b504d925815583c249ec3fc04baab","src/regexp.rs":"8fdae52b761dbad90179e6be87e0e66357fefa34d76af541fb0fcf550fd6ec08","src/str.rs":"198fa15d45c3636289d92c0a592002a07e5a04a431e8cfdf724266e44d484be2","src/stream.rs":"c1bd5b8e7a2061ff66eb2c954033146001f1d65a26d12efa06af8cf93ffa53e4","src/util.rs":"da40ebac865d3176567d3a37b01170234398a03e938553720ce30aa1f6005b6d","tests/arithmetic.rs":"b98936b7fa0228835ca022f6db5342b72a9c01cc3f16a4e05263bbe6424ba3e9","tests/arithmetic_ast.rs":"b18b9a46ba573ae13c40a31217425f6e8cf8fade09a75cdbbfa7146ec668f0b2","tests/cross_function_backtracking.rs":"b071d13031c1f12195473186e3775943991496b10f4590db3f36d511e9f98a1c","tests/ini.rs":"776f681542028564899e55f71533b3bcda5ed1bbb971f24b5b1b9578111ba0cb","tests/ini_str.rs":"315046d9b6dc38d6d306d3562d7ac6518c9ecce9aabcc58fb80c07577ad99789","tests/issues.rs":"2193c219397b7a417cc009b72c13adc42471e7a4917a2a4009aa0fca23c6ea8c","tests/mp4.rs":"b4bf0514fd645160851cc4da9ad6bf81d571cd14865bf134837c19578caaf6e6","tests/omnom.rs":"409d2349fa24f3503bd02e0079c1554a58ce3d40dd7eb0e5d4bb63b588afdae4","tests/test1.rs":"3e0c187bad91d822ebc113eb5cf30fc6585e53a961728304ac24e05ab2123d10"},"package":"a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"} +\ No newline at end of file +diff --git third_party/rust/nom-1.2.4/.travis.yml third_party/rust/nom-1.2.4/.travis.yml +new file mode 100644 +index 000000000000..1d1e36c593aa +--- /dev/null ++++ third_party/rust/nom-1.2.4/.travis.yml +@@ -0,0 +1,46 @@ ++language: rust ++ ++addons: ++ apt: ++ packages: ++ - libcurl4-openssl-dev ++ - libelf-dev ++ - libdw-dev ++ ++rust: ++ - nightly ++ - beta ++ - stable ++ - 1.2.0 ++ ++before_script: ++ - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH ++ ++script: ++ - | ++ travis-cargo --only 1.2 test -- --features regexp && ++ travis-cargo --only stable test -- --features "regexp regexp_macros" && ++ travis-cargo --only beta test -- --features "regexp regexp_macros" && ++ travis-cargo --only nightly build -- --features "nightly core regexp" && ++ travis-cargo --only nightly test -- --features "regexp" && ++ travis-cargo bench && ++ travis-cargo --only stable doc -- --features "regexp" ++ ++after_success: ++ - travis-cargo coveralls --no-sudo ++ ++notifications: ++ webhooks: ++ urls: ++ - https://webhooks.gitter.im/e/9c035a194ac4fd4cc061 ++ on_success: change ++ on_failure: always ++ on_start: false ++ ++ ++env: ++ global: ++ # override the default `--features unstable` used for the nightly branch (optional) ++ - TRAVIS_CARGO_NIGHTLY_FEATURE=nightly ++ ++sudo: false +diff --git third_party/rust/nom-1.2.4/CHANGELOG.md third_party/rust/nom-1.2.4/CHANGELOG.md +new file mode 100644 +index 000000000000..f1c331585779 +--- /dev/null ++++ third_party/rust/nom-1.2.4/CHANGELOG.md +@@ -0,0 +1,555 @@ ++# Change Log ++ ++## [Unreleased][unreleased] ++ ++### Changed ++ ++## 1.2.4 - 2016-07-20 ++ ++### Thanks ++- @Phlosioneer for documentation fixes ++- @sourrust for fixing offsets in `take_bits!` ++- @ChrisMacNaughton for the XFS crate ++- @pwoolcoc for `rest_s` ++- @fitzgen for more `IResult` methods ++- @gtors for the negative lookahead feature ++- @frk1 and @jeandudey for little endian float parsing ++- @jethrogb for fixing input usage in `many1` ++- @acatton for beating me at nom golf :D ++ ++### Added ++- the `rest_s` method on `IResult` returns the remaining `&str` input ++- `unwrap_err` and `unwrap_inc` methods on `IResult` ++- `not!` will peek at the input and return `Done` if the underlying parser returned `Error` or `Incomplete`, without consuming the input ++- `le_f32` and `le_f64` parse little endian floating point numbers (IEEE 754) ++- ++ ++### Fixed ++- documentation fixes ++- `take_bits!` is now more precise ++- `many1` inccorectly used the `len` function instead of `input_len` ++- the INI parser is simpler ++- `recognize!` had an early `return` taht is removed now ++ ++## 1.2.3 - 2016-05-10 ++ ++### Thanks ++- @lu-zero for the contribution guidelines ++- @GuillaumeGomez for fixes on `length_bytes` and some documentation ++- @Hywan for ducomentation and test fixes ++- @Xirdus for correct trait import issues ++- @mspiegel for the new AST example ++- @cholcombe973 for adding the `cond_with_error!` combinator ++- @tstorch for refactoring `many0!` ++- @panicbit for the folding combinators ++- @evestera for `separated_list!` fixes ++- @DanielKeep for correcting some enum imports ++ ++### Added ++- Regular expression combinators starting with `re_bytes_` work on byte slices ++- example parsing arithmetic expressions to an AST ++- `cond_with_error!` works like `cond!` but will return `None` if the condition is false, and `Some(value)` if the underlying parser succeeded ++- `fold_many0!`, `fold_many1!` and `fold_many_m_n!` will take a parser, an initial value and a combining function, and fold over the successful applications of the parser ++ ++### Fixed ++- `length_bytes!` converts the result of its child parser to usize ++- `take_till!` now imports `InputLength` instead of assuming it's in scope ++- `separated_list!` and `separated_nonempty_list!` will not consume the separator if there's no following successfully parsed value ++- no more warnings on build ++ ++### Changed ++- simpler implementation of `many0!` ++ ++## 1.2.2 - 2016-03-09 ++ ++### Thanks ++- @conradev for fixing take_until_s!` ++- @GuillaumeGomez for some documentation fixes ++- @frewsxcv for some documentation fixes ++- @tstorch for some test refactorings ++ ++### Added ++- `nom::Err` now implements `std::error::Error` ++ ++### Fixed ++- `hex_u32` does not parses more than 8 chars now ++- `take_while!` and `take_while1!` will not perturb the behaviour of `recognize!` anymore ++ ++## 1.2.1 - 2016-02-23 ++ ++### Thanks ++- @sourrust for adding methods to `IResult` ++- @tstorch for the test refactoring, and for adding methods to `IResult` and `Needed` ++- @joelself for fixing the method system ++ ++### Added ++ ++- mapping methods over `IResult` and `Needed` ++ ++### Changed ++ ++- `apply_rf` is renamed to `apply_m`. This will not warrant a major version, since it is part missing from the methods feture added in the 1.2.0 release ++- the `regexp_macros` feature that used `regex!` to precompile regular expressions has been replaced by the normal regex engine combined with `lazy_static` ++ ++### Fixed ++ ++- when a parser or combinator was returning an empty buffer as remaining part, it was generating one from a static empty string. This was messing with buffer offset calculation. Now, that empty slice is taken like this: `&input[input.len()..]`. ++- The `regexp_macros` and `no_std` feature build again and are now tested with Travis CI ++ ++## 1.2.0 - 2016-02-08 ++ ++### Thanks ++- @zentner-kyle for type inference fixes ++- @joelself for his work on `&str` parsing and method parsers ++- @GuillaumeGomez for implementing methods on `IResult` ++- @dirk for the `alt_complete!` combinator ++- @tstorch for a lot of refactoring work and unit tests additions ++- @jansegre for the hex digit parsers ++- @belgum for some documentation fixes ++- @lwandrebeck for some documentation fixes and code fixes in `hex_digit` ++ ++### Added ++- `take_until_and_consume_s!` for consumption of string data until a tag ++- more function patterns in `named!`. The error type can now be specified ++- `alt_complete!` works like the `alt!` combinator, but tries the next branch if the current one returned `Incomplete`, instead of returning directly ++- more unit tests for a lot of combinators ++- hexadecimal digit parsers ++- the `tuple!` combinator takes a list of parsers as argument, and applies them serially on the input. If all of them are successful, it willr eturn a tuple accumulating all the values. This combinator will (hopefully) replace most uses of `chain!` ++- parsers can now be implemented as a method for a struct thanks to the `method!`, `call_m!` and `apply_rf!` combinators ++ ++### Fixed ++- there were type inference issues in a few combinators. They will now be easier to compile ++- `peek!` compilation with bare functions ++- `&str` parsers were splitting data at the byte level, not at the char level, which can result in inconsistencies in parsing UTF-8 characters. They now use character indexes ++- some method implementations were missing on `ÌResult` (with specified error type instead of implicit) ++ ++## 1.1.0 - 2016-01-01 ++ ++This release adds a lot of features related to `&str` parsing. The previous versions ++were focused on `&[u8]` and bit streams parsing, but there's a need for more text ++parsing with nom. The parsing functions like `alpha`, `digit` and others will now ++accept either a `&[u8]` or a `&str`, so there is no breaking change on that part. ++ ++There are also a few performance improvements and documentation fixes. ++ ++### Thanks ++- @Binero for pushing the work on `&str` parsing ++- @meh for fixing `Option` and `Vec` imports ++- @hoodie for a documentation fix ++- @joelself for some documentation fixes ++- @vberger for his traits magic making `nom functions more generic ++ ++### Added ++ ++- string related parsers: `tag_s!`, `take_s!`, `is_a_s!`, `is_not_s!`, `take_while_s!`, `take_while1_s!`, `take_till_s! ++- `value!` is a combinator that always returns the same value. If a child parser is passed as second argument, that value is returned when the child parser succeeds ++ ++### Changed ++ ++- `tag!` will now compare even on partial input. If it expects "abcd" but receives "ef", it will now return an `Error` instead of `Incomplete` ++- `many0!` and others will preallocate a larger vector to avoid some copies and reallocations ++- `alpha`, `digit`, `alphanumeric`, `space` and `multispace` now accept as input a `&[u8]` or a `&str`. Additionally, they return an error if they receive an empty input ++- `take_while!`, `take_while1!`, `take_while_s!`, `take_while1_s!` wilreturn an error on empty input ++ ++### Fixed ++ ++- if the child parser of `many0!` or `many1!` returns `Incomplete`, it will return `Incomplete` too, possibly updating the needed size ++- `Option,` `Some`, `None` and `Vec` are now used with full path imports ++ ++## 1.0.1 - 2015-11-22 ++ ++This releases makes the 1.0 version compatible with Rust 1.2 and 1.3 ++ ++### Thanks ++- @steveklabnik for fixing lifetime issues in Producers and Consumers ++ ++## 1.0.0 - 2015-11-16 ++ ++Stable release for nom. A lot of new features, a few breaking changes ++ ++### Thanks ++- @ahenry for macro fixes ++- @bluss for fixing documentation ++- @sourrust for cleaning code and debugging the new streaming utilities ++- @meh for inline optimizations ++- @ccmtaylor for fixing function imports ++- @soro for improvements to the streaming utilities ++- @breard-r for catching my typos ++- @nelsonjchen for catching my typos too ++- @divarvel for hex string parsers ++- @mrordinaire for the `length_bytes!` combinator ++ ++### Breaking changes ++- `IResult::Error` can now use custom error types, and is generic over the input type ++- Producers and consumers have been replaced. The new implementation uses less memory and integrates more with parsers ++- `nom::ErrorCode` is now `nom::ErrorKind` ++- `filter!` has been renamed to `take_while!` ++- `chain!` will count how much data is consumed and use that number to calculate how much data is needed if a parser returned `Incomplete` ++- `alt!` returns `Incomplete` if a child parser returned `Incomplete`, instead of skipping to the next parser ++- `IResult` does not require a lifetime tag anymore, yay! ++ ++### Added ++ ++- `complete!` will return an error if the child parser returned `Incomplete` ++- `add_error!` will wrap an error, but allow backtracking ++- `hex_u32` parser ++ ++### Fixed ++- the behaviour around `Incomplete` is better for most parsers now ++ ++## 0.5.0 - 2015-10-16 ++ ++This release fixes a few issues and stabilizes the code. ++ ++### Thanks ++- @nox for documentation fixes ++- @daboross for linting fixes ++- @ahenry for fixing `tap!` and extending `dbg!` and `dbg_dmp!` ++- @bluss for tracking down and fixing issues with unsafe code ++- @meh for inlining parser functions ++- @ccmtaylor for fixing import of `str::from_utf8` ++ ++### Fixed ++- `tap!`, `dbg!` and `dbg_dmp!` now accept function parameters ++ ++### Changed ++- the type used in `count_fixed!` must be `Copy` ++- `chain!` calculates how much data is needed if one of the parsers returns `Incomplete ++- optional parsers in `chain!` can return `Incomplete` ++ ++## 0.4.0 - 2015-09-08 ++ ++Considering the number of changes since the last release, this version can contain breaking changes, so the version number becomes 0.4.0. A lot of new features and performance improvements! ++ ++### Thanks ++- @frewsxcv for documentation fixes ++- @ngrewe for his work on producers and consumers ++- @meh for fixes on `chain!` and for the `rest` parser ++- @daboross for refactoring `many0!` and `many1!` ++- @aleksander for the `switch!` combinator idea ++- @TechnoMancer for his help with bit level parsing ++- @sxeraverx for pointing out a bug in `is_a!` ++ ++### Fixed ++- `count_fixed!` must take an explicit type as argument to generate the fixed-size array ++- optional parsing behaviour in `chain!` ++- `count!` can take 0 elements ++- `is_a!` and `is_not!` can now consume the whole input ++ ++### Added ++- it is now possible to seek to the end of a `MemProducer` ++- `opt!` returns `Done(input, None)` if `the child parser returned `Incomplete` ++- `rest` will return the remaining input ++- consumers can now seek to and from the end of input ++- `switch!` applies a first parser then matches on its result to choose the next parser ++- bit-level parsers ++- character-level parsers ++- regular expression parsers ++- implementation of `take_till!`, `take_while!` and `take_while1!` ++ ++### Changed ++- `alt!` can return `Incomplete` ++- the error analysis functions will now take references to functions instead of moving them ++- performance improvements on producers ++- performance improvement for `filter!` ++- performance improvement for `count!`: a `Vec` of the right size is directly allocated ++ ++## 0.3.11 - 2015-08-04 ++ ++### Thanks ++- @bluss for remarking that the crate included random junk lying non commited in my local repository ++ ++### Fixed ++- cleanup of my local repository will ship less files in the crates, resulting in a smaller download ++ ++## 0.3.10 - 2015-08-03 ++ ++### Added ++ ++- `bits!` for bit level parsing. It indicates that all child parsers will take a `(&[u8], usize)`as input, with the second parameter indicating the bit offset in the first byte. This allows viewing a byte slice as a bit stream. Most combinators can be used directly under `bits!` ++- `take_bits!` takes an integer type and a number of bits, consumes that number of bits and updates the offset, possibly by crossing byte boundaries ++- bit level parsers are all written in `src/bits.rs` ++ ++### Changed ++ ++- Parsers that specifically handle bytes have been moved to src/bytes.rs`. This applies to `tag!`, `is_not!`, `is_a!`, `filter!`, `take!`, `take_str!`, `take_until_and_consume!`, `take_until!`, `take_until_either_and_consume!`, `take_until_either!` ++ ++## 0.3.9 - 2015-07-20 ++ ++### Thanks ++- @badboy for fixing `filter!` ++- @idmit for some documentation fixes ++ ++### Added ++- `opt_res!` applies a parser and transform its result in a Result. This parser never fails ++- `cond_reduce!` takes an expression as parameter, applies the parser if the expression is true, and returns an error if the expression is false ++- `tap!` pass the result of a parser to a block to manipulate it, but do not affect the parser's result ++- `AccReader` is a Read+BufRead that supports data accumulation and partial consumption. The `consume` method must be called afterwardsto indicate how much was consumed ++- Arithmetic expression evaluation and parsing example ++- `u16!`, `u32!`, `u64!`, `i16!`, `i32!`, `i64!` take an expression as parameter, if the expression is true, apply the big endian integer parser, if false, the little endian version ++- type information for combinators. This will make the documentation a bit easier to navigate ++ ++### Fixed ++- `map_opt!` and `map_res!` had issues with argument order due to bad macros ++- `delimited!` did not compile for certain combinations of arguments ++- `filter!` did not return a byte slice but a fixed array ++ ++## 0.3.8 - 2015-07-03 ++ ++### Added ++- code coverage is now calculated automatically on Travis CI ++- `Stepper`: wrap a `Producer`, and call the method `step` with a parser. This method will buffer data if there is not enough, apply the parser if there is, and keep the rest of the input in memory for the next call ++- `ReadProducer`: takes something implementing `Read`, and makes a `Producer` out of it ++ ++### Fixed ++- the combinators `separated_pair!` and `delimited!` did not work because an implementation macro was not exported ++- if a `MemProducer` reached its end, it should always return `Eof` ++- `map!` had issues with argument matching ++ ++## 0.3.7 - 2015-06-24 ++ ++### Added ++- `expr_res!` and `expr_opt!` evaluate an expression returning a Result or Opt and convert it to IResult ++- `AsBytes` is implemented for fixed size arrays. This allows `tag!([41u8, 42u8])` ++ ++### Fixed ++- `count_fixed!` argument parsing works again ++ ++## 0.3.6 - 2015-06-15 ++ ++### Added ++- documentation for a few functions ++- the consumer trait now requires the `failed(&self, error_code)` method in case of parsing error ++- `named!` now handles thge alternative `named!(pub fun_name, ...)` ++ ++### Fixed ++- `filter!` now returns the whole input if the filter function never returned false ++- `take!` casts its argument as usize, so it can accepts any integer type now ++ ++## 0.3.5 - 2015-06-10 ++ ++### Thanks ++- @cmr for some documentation fixes ++ ++### Added ++- `count_fixed!` returns a fixed array ++ ++### Fixed ++- `count!` is back to the previous behaviour, returning a `Vec` for sizes known at runtime ++ ++### Changed ++- functions and traits exported from `nom::util` are now directly in `nom::` ++ ++## 0.3.4 - 2015-06-09 ++ ++### Thanks ++- @andrew-d for fixes on `cond!` ++- @keruspe for features in `chain!` ++ ++### Added ++- `chain!` can now have mutable fields ++ ++### Fixed ++- `cond!` had an infinite macro recursion ++ ++### Changed ++- `chain!` generates less code now. No apprent compilation time improvement ++ ++## 0.3.3 - 2015-06-09 ++ ++### Thanks ++- @andrew-d for the little endian signed integer parsers ++- @keruspe for fixes on `count!` ++ ++### Added ++- `le_i8`, `le_i16`, `le_i32`, `le_i64`: little endian signed integer parsers ++ ++### Changed ++- the `alt!` parser compiles much faster, even with more than 8 branches ++- `count!` can now return a fixed size array instead of a growable vector ++ ++## 0.3.2 - 2015-05-31 ++ ++### Thanks ++- @keruspe for the `take_str` parser and the function application combinator ++ ++### Added ++- `take_str!`: takes the specified number of bytes and return a UTF-8 string ++- `apply!`: do partial application on the parameters of a function ++ ++### Changed ++- `Needed::Size` now contains a `usize` instead of a `u32` ++ ++## 0.3.1 - 2015-05-21 ++ ++### Thanks ++- @divarvel for the big endian signed integer parsers ++ ++### Added ++- `be_i8`, `be_i16`, `be_i32`, `be_i64`: big endian signed integer parsers ++- the `core` feature can be passed to cargo to build with `no_std` ++- colored hexdump can be generated from error chains ++ ++## 0.3.0 - 2015-05-07 ++ ++### Thanks ++- @filipegoncalves for some documentation and the new eof parser ++- @CrimsonVoid for putting fully qualified types in the macros ++- @lu_zero for some documentation fixes ++ ++### Added ++- new error types that can contain an error code, an input slice, and a list of following errors ++- `error!` will cut backtracking and return directly from the parser, with a specified error code ++- `eof` parser, successful if there is no more input ++- specific error codes for the parsers provided by nom ++ ++### Changed ++- fully qualified types in macros. A lot of imports are not needed anymore ++ ++### Removed ++- `FlatMap`, `FlatpMapOpt` and `Functor` traits (replaced by `map!`, `map_opt!` and `map_res!`) ++ ++## 0.2.2 - 2015-04-12 ++ ++### Thanks ++- @filipegoncalves and @thehydroimpulse for debugging an infinite loop in many0 and many1 ++- @thehydroimpulse for suggesting public named parsers ++- @skade for removing the dependency on the collections gate ++ ++### Added ++- `named!` can now declare public functions like this: `named!(pub tst, tag!("abcd"));` ++- `pair!(X,Y)` returns a tuple `(x, y)` ++- `separated_pair!(X, sep, Y)` returns a tuple `(x, y)` ++- `preceded!(opening, X)` returns `x` ++- `terminated!(X, closing)` returns `x` ++- `delimited(opening, X, closing)` returns `x` ++- `separated_list(sep, X)` returns a `Vec` ++- `separated_nonempty_list(sep, X)` returns a `Vec` of at list one element ++ ++### Changed ++- `many0!` and `many1!` forbid parsers that do not consume input ++- `is_a!`, `is_not!`, `alpha`, `digit`, `space`, `multispace` will now return an error if they do not consume at least one byte ++ ++## 0.2.1 - 2015-04-04 ++ ++### Thanks ++- @mtsr for catching the remaining debug println! ++- @jag426 who killed a lot of warnings ++- @skade for removing the dependency on the core feature gate ++ ++ ++### Added ++- little endian unsigned int parsers le_u8, le_u16, le_u32, le_u64 ++- `count!` to apply a parser a specified number of times ++- `cond!` applies a parser if the condition is met ++- more parser development tools in `util::*` ++ ++### Fixed ++- in one case, `opt!` would not compile ++ ++### Removed ++- most of the feature gates are now removed. The only one still needed is `collections` ++ ++## 0.2.0 - 2015-03-24 ++*works with `rustc 1.0.0-dev (81e2396c7 2015-03-19) (built 2015-03-19)`* ++ ++### Thanks ++- Ryman for the AsBytes implementation ++- jag426 and jaredly for documentation fixes ++- eternaleye on #rust IRC for his help on the new macro syntax ++ ++### Changed ++- the AsBytes trait improves readability, no more b"...", but "..." instead ++- Incomplete will now hold either Needed;;Unknown, or Needed::Size(u32). Matching on Incomplete without caring for the value is done with `Incomplete(_)`, but if more granularity is mandatory, `Needed` can be matched too ++- `alt!` can pass the result of the parser to a closure ++- the `take_*` macros changed behaviour, the default case is now not to consume the separator. The macros have been renamed as follows: `take_until!` -> `take_until_and_consume!`, `take_until_and_leave!` -> `take_until!`, `take_until_either_and_leave!` -> `take_until_either!`, `take_until_either!` -> `take_until_either_and_consume!` ++ ++### Added ++- `peek!` macro: matches the future input but does not consume it ++- `length_value!` macro: the first argument is a parser returning a `n` that can cast to usize, then applies the second parser `n` times. The macro has a variant with a third argument indicating the expected input size for the second parser ++- benchmarks are available at https://github.com/Geal/nom_benchmarks ++- more documentation ++- **Unnamed parser syntax**: warning, this is a breaking change. With this new syntax, the macro combinators do not generate functions anymore, they create blocks. That way, they can be nested, for better readability. The `named!` macro is provided to create functions from parsers. Please be aware that nesting parsers comes with a small cost of compilation time, negligible in most cases, but can quickly get to the minutes scale if not careful. If this happens, separate your parsers in multiple subfunctions. ++- `named!`, `closure!` and `call!` macros used to support the unnamed syntax ++- `map!`, `map_opt!` and `map_res!` to combine a parser with a normal function, transforming the input directly, or returning an `Option` or `Result` ++ ++### Fixed ++- `is_a!` is now working properly ++ ++### Removed ++- the `o!` macro does less than `chain!`, so it has been removed ++- the `fold0!` and `fold1!` macros were too complex and awkward to use, the `many*` combinators will be useful for most uses for now ++ ++## 0.1.6 - 2015-02-24 ++### Changed ++- consumers must have an end method that will be called after parsing ++ ++### Added ++- big endian unsigned int and float parsers: be_u8, be_u16, be_u32, be_u64, be_f32, be_f64 ++- producers can seek ++- function and macros documentation ++- README documentation ++### Fixed ++- lifetime declarations ++- tag! can return Incomplete ++ ++## 0.1.5 - 2015-02-17 ++### Changed ++- traits were renamed: FlatMapper -> FlatMap, Mapper -> FlatMapOpt, Mapper2 -> Functor ++ ++### Fixed ++- woeks with rustc f1bb6c2f4 ++ ++## 0.1.4 - 2015-02-17 ++### Changed ++- the chaining macro can take optional arguments with '?' ++ ++## 0.1.3 - 2015-02-16 ++### Changed ++- the chaining macro now takes the closure at the end of the argument list ++ ++## 0.1.2 - 2015-02-16 ++### Added ++- flat_map implementation for <&[u8], &[u8]> ++- chaining macro ++- partial MP4 parser example ++ ++ ++## 0.1.1 - 2015-02-06 ++### Fixed ++- closure syntax change ++ ++## Compare code ++ ++* [unreleased]: https://github.com/Geal/nom/compare/1.2.4...HEAD ++* [1.2.3]: https://github.com/Geal/nom/compare/1.2.3...1.2.4 ++* [1.2.3]: https://github.com/Geal/nom/compare/1.2.2...1.2.3 ++* [1.2.2]: https://github.com/Geal/nom/compare/1.2.1...1.2.2 ++* [1.2.1]: https://github.com/Geal/nom/compare/1.2.0...1.2.1 ++* [1.2.0]: https://github.com/Geal/nom/compare/1.1.0...1.2.0 ++* [1.1.0]: https://github.com/Geal/nom/compare/1.0.1...1.1.0 ++* [1.0.1]: https://github.com/Geal/nom/compare/1.0.0...1.0.1 ++* [1.0.0]: https://github.com/Geal/nom/compare/0.5.0...1.0.0 ++* [0.5.0]: https://github.com/geal/nom/compare/0.4.0...0.5.0 ++* [0.4.0]: https://github.com/geal/nom/compare/0.3.11...0.4.0 ++* [0.3.11]: https://github.com/geal/nom/compare/0.3.10...0.3.11 ++* [0.3.10]: https://github.com/geal/nom/compare/0.3.9...0.3.10 ++* [0.3.9]: https://github.com/geal/nom/compare/0.3.8...0.3.9 ++* [0.3.8]: https://github.com/Geal/nom/compare/0.3.7...0.3.8 ++* [0.3.7]: https://github.com/Geal/nom/compare/0.3.6...0.3.7 ++* [0.3.6]: https://github.com/Geal/nom/compare/0.3.5...0.3.6 ++* [0.3.5]: https://github.com/Geal/nom/compare/0.3.4...0.3.5 ++* [0.3.4]: https://github.com/Geal/nom/compare/0.3.3...0.3.4 ++* [0.3.3]: https://github.com/Geal/nom/compare/0.3.2...0.3.3 ++* [0.3.2]: https://github.com/Geal/nom/compare/0.3.1...0.3.2 ++* [0.3.1]: https://github.com/Geal/nom/compare/0.3.0...0.3.1 ++* [0.3.0]: https://github.com/Geal/nom/compare/0.2.2...0.3.0 ++* [0.2.2]: https://github.com/Geal/nom/compare/0.2.1...0.2.2 ++* [0.2.1]: https://github.com/Geal/nom/compare/0.2.0...0.2.1 ++* [0.2.0]: https://github.com/Geal/nom/compare/0.1.6...0.2.0 ++* [0.1.6]: https://github.com/Geal/nom/compare/0.1.5...0.1.6 ++* [0.1.5]: https://github.com/Geal/nom/compare/0.1.4...0.1.5 ++* [0.1.4]: https://github.com/Geal/nom/compare/0.1.3...0.1.4 ++* [0.1.3]: https://github.com/Geal/nom/compare/0.1.2...0.1.3 ++* [0.1.2]: https://github.com/Geal/nom/compare/0.1.1...0.1.2 ++* [0.1.1]: https://github.com/Geal/nom/compare/0.1.0...0.1.1 +diff --git third_party/rust/nom-1.2.4/Cargo.toml third_party/rust/nom-1.2.4/Cargo.toml +new file mode 100644 +index 000000000000..ae8045bf1135 +--- /dev/null ++++ third_party/rust/nom-1.2.4/Cargo.toml +@@ -0,0 +1,38 @@ ++[package] ++ ++name = "nom" ++version = "1.2.4" ++authors = [ "contact@geoffroycouprie.com" ] ++description = "A byte-oriented, zero-copy, parser combinators library" ++license = "MIT" ++repository = "https://github.com/Geal/nom" ++readme = "README.md" ++documentation = "http://rust.unhandledexpression.com/nom/" ++keywords = ["parser", "parser-combinators", "parsing", "streaming", "bit"] ++ ++include = [ ++ "CHANGELOG.md", ++ "LICENSE", ++ ".gitignore", ++ ".travis.yml", ++ "Cargo.toml", ++ "src/*.rs", ++ "tests/*.rs" ++] ++ ++[features] ++core = [] ++nightly = [] ++default = ["stream"] ++regexp = ["regex"] ++regexp_macros = ["regexp", "lazy_static"] ++stream = [] ++ ++[dependencies.regex] ++version = "^0.1.56" ++optional = true ++ ++[dependencies.lazy_static] ++version = "^0.2.1" ++optional = true ++ +diff --git third_party/rust/nom-1.2.4/LICENSE third_party/rust/nom-1.2.4/LICENSE +new file mode 100644 +index 000000000000..0bd6a1c33dc6 +--- /dev/null ++++ third_party/rust/nom-1.2.4/LICENSE +@@ -0,0 +1,20 @@ ++Copyright (c) 2015 Geoffroy Couprie ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, 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. +diff --git third_party/rust/nom-1.2.4/src/bits.rs third_party/rust/nom-1.2.4/src/bits.rs +new file mode 100644 +index 000000000000..a8bd8b24aa99 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/bits.rs +@@ -0,0 +1,220 @@ ++//! Bit level parsers and combinators ++//! ++//! Bit parsing is handled by tweaking the input in most macros. ++//! In byte level parsing, the input is generally a `&[u8]` passed from combinator ++//! to combinator until the slices are manipulated. ++//! ++//! Bit parsers take a `(&[u8], usize)` as input. The first part of the tuple is an byte slice, ++//! the second part is a bit offset in the first byte of the slice. ++//! ++//! By passing a pair like this, we can leverage most of the combinators, and avoid ++//! transforming the whole slice to a vector of booleans. This should make it easy ++//! to see a byte slice as a bit stream, and parse code points of arbitrary bit length. ++ ++ ++/// `bits!( parser ) => ( &[u8], (&[u8], usize) -> IResult<(&[u8], usize), T> ) -> IResult<&[u8], T>` ++/// transforms its byte slice input into a bit stream for the underlying parsers ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!( take_3_bits, bits!( take_bits!( u8, 3 ) ) ); ++/// ++/// let input = vec![0b10101010, 0b11110000, 0b00110011]; ++/// let sl = &input[..]; ++/// ++/// assert_eq!(take_3_bits( sl ), Done(&sl[1..], 5) ); ++/// # } ++#[macro_export] ++macro_rules! bits ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ bits_impl!($i, $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr) => ( ++ bits_impl!($i, call!($f)); ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! bits_impl ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let input = ($i, 0usize); ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(e) => { ++ let err = match e { ++ $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k), ++ $crate::Err::Position(k, (i,b)) | $crate::Err::NodePosition(k, (i,b), _) => { ++ $crate::Err::Position(k, &i[b/8..]) ++ } ++ }; ++ $crate::IResult::Error(err) ++ } ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ //println!("bits parser returned Needed::Size({})", i); ++ $crate::IResult::Incomplete($crate::Needed::Size(i / 8 + 1)) ++ }, ++ $crate::IResult::Done((i, bit_index), o) => { ++ let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ; ++ //println!("bit index=={} => byte index=={}", bit_index, byte_index); ++ $crate::IResult::Done(&i[byte_index..], o) ++ } ++ } ++ } ++ ); ++); ++ ++/// `take_bits!(type, nb) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>` ++/// generates a parser consuming the specified number of bits. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!( take_pair<(u8, u8)>, bits!( pair!( take_bits!( u8, 3 ), take_bits!(u8, 5) ) ) ); ++/// ++/// let input = vec![0b10101010, 0b11110000, 0b00110011]; ++/// let sl = &input[..]; ++/// ++/// assert_eq!(take_pair( sl ), Done(&sl[1..], (5, 10)) ); ++/// assert_eq!(take_pair( &sl[1..] ), Done(&sl[2..], (7, 16)) ); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! take_bits ( ++ ($i:expr, $t:ty, $count:expr) => ( ++ { ++ use std::ops::Div; ++ //println!("taking {} bits from {:?}", $count, $i); ++ let (input, bit_offset) = $i; ++ let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 { ++ $crate::IResult::Done( (input, bit_offset), 0) ++ } else { ++ let cnt = ($count as usize + bit_offset).div(8); ++ if input.len() * 8 < $count as usize + bit_offset { ++ //println!("returning incomplete: {}", $count as usize + bit_offset); ++ $crate::IResult::Incomplete($crate::Needed::Size($count as usize)) ++ } else { ++ let mut acc:$t = 0; ++ let mut offset: usize = bit_offset; ++ let mut remaining: usize = $count; ++ let mut end_offset: usize = 0; ++ ++ for byte in input.iter().take(cnt + 1) { ++ if remaining == 0 { ++ break; ++ } ++ let val: $t = if offset == 0 { ++ *byte as $t ++ } else { ++ ((*byte << offset) as u8 >> offset) as $t ++ }; ++ ++ if remaining < 8 - offset { ++ acc += val >> (8 - offset - remaining); ++ end_offset = remaining + offset; ++ break; ++ } else { ++ acc += val << (remaining - (8 - offset)); ++ remaining -= 8 - offset; ++ offset = 0; ++ } ++ } ++ $crate::IResult::Done( (&input[cnt..], end_offset) , acc) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// matches an integer pattern to a bitstream. The number of bits of the input to compare must be specified ++#[macro_export] ++macro_rules! tag_bits ( ++ ($i:expr, $t:ty, $count:expr, $p: pat) => ( ++ { ++ match take_bits!($i, $t, $count) { ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ if let $p = o { ++ let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o); ++ res ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i)) ++ } ++ }, ++ _ => { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i)) ++ } ++ } ++ } ++ ) ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::{IResult,Needed,Err}; ++ use ErrorKind; ++ ++ #[test] ++ fn take_bits() { ++ let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let sl = &input[..]; ++ ++ assert_eq!(take_bits!( (sl, 0), u8, 0 ), IResult::Done((sl, 0), 0)); ++ assert_eq!(take_bits!( (sl, 0), u8, 8 ), IResult::Done((&sl[1..], 0), 170)); ++ assert_eq!(take_bits!( (sl, 0), u8, 3 ), IResult::Done((&sl[0..], 3), 5)); ++ assert_eq!(take_bits!( (sl, 0), u8, 6 ), IResult::Done((&sl[0..], 6), 42)); ++ assert_eq!(take_bits!( (sl, 1), u8, 1 ), IResult::Done((&sl[0..], 2), 0)); ++ assert_eq!(take_bits!( (sl, 1), u8, 2 ), IResult::Done((&sl[0..], 3), 1)); ++ assert_eq!(take_bits!( (sl, 1), u8, 3 ), IResult::Done((&sl[0..], 4), 2)); ++ assert_eq!(take_bits!( (sl, 6), u8, 3 ), IResult::Done((&sl[1..], 1), 5)); ++ assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683)); ++ assert_eq!(take_bits!( (sl, 0), u16, 8 ), IResult::Done((&sl[1..], 0), 170)); ++ assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752)); ++ assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504)); ++ assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163)); ++ assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851)); ++ assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(22))); ++ } ++ ++ #[test] ++ fn tag_bits() { ++ let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let sl = &input[..]; ++ ++ assert_eq!(tag_bits!( (sl, 0), u8, 3, 0b101), IResult::Done((&sl[0..], 3), 5)); ++ assert_eq!(tag_bits!( (sl, 0), u8, 4, 0b1010), IResult::Done((&sl[0..], 4), 10)); ++ } ++ ++ named!(ch<(&[u8],usize),(u8,u8)>, ++ chain!( ++ tag_bits!(u8, 3, 0b101) ~ ++ x: take_bits!(u8, 4) ~ ++ y: take_bits!(u8, 5) , ++ || { (x,y) } ++ ) ++ ); ++ ++ #[test] ++ fn chain_bits() { ++ let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let sl = &input[..]; ++ assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15))); ++ assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16))); ++ assert_eq!(ch((&input[..1],0)), IResult::Incomplete(Needed::Size(12))); ++ } ++ ++ named!(ch_bytes<(u8,u8)>, bits!(ch)); ++ #[test] ++ fn bits_to_bytes() { ++ let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15))); ++ assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2))); ++ assert_eq!(ch_bytes(&input[1..]), IResult::Error(Err::Position(ErrorKind::TagBits, &input[1..]))); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/bytes.rs third_party/rust/nom-1.2.4/src/bytes.rs +new file mode 100644 +index 000000000000..3f31598dc344 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/bytes.rs +@@ -0,0 +1,1027 @@ ++//! Byte level parsers and combinators ++//! ++ ++/// `recognize!(&[T] -> IResult<&[T], O> ) => &[T] -> IResult<&[T], &[T]>` ++/// if the child parser was successful, return the consumed input as produced value ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(x, recognize!(delimited!(tag!("")))); ++/// let r = x(&b" aaa"[..]); ++/// assert_eq!(r, Done(&b" aaa"[..], &b""[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! recognize ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::HexDisplay; ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,_) => { ++ let index = ($i).offset(i); ++ $crate::IResult::Done(i, &($i)[..index]) ++ }, ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ recognize!($i, call!($f)) ++ ); ++); ++ ++/// `tag!(&[T]: nom::AsBytes) => &[T] -> IResult<&[T], &[T]>` ++/// declares a byte array as a suite to recognize ++/// ++/// consumes the recognized characters ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(x, tag!("abcd")); ++/// let r = x(&b"abcdefgh"[..]); ++/// assert_eq!(r, Done(&b"efgh"[..], &b"abcd"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! tag ( ++ ($i:expr, $inp: expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ ++ tag_bytes!($i,bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! tag_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ let len = $i.len(); ++ let blen = $bytes.len(); ++ let m = if len < blen { len } else { blen }; ++ let reduced = &$i[..m]; ++ let b = &$bytes[..m]; ++ ++ let res: $crate::IResult<_,_> = if reduced != b { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Tag, $i)) ++ } else if m < blen { ++ $crate::IResult::Incomplete($crate::Needed::Size(blen)) ++ } else { ++ $crate::IResult::Done(&$i[blen..], reduced) ++ }; ++ res ++ } ++ ); ++); ++ ++/// `is_not!(&[T:AsBytes]) => &[T] -> IResult<&[T], &[T]>` ++/// returns the longest list of bytes that do not appear in the provided array ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!( not_space, is_not!( " \t\r\n" ) ); ++/// ++/// let r = not_space(&b"abcdefgh\nijkl"[..]); ++/// assert_eq!(r, Done(&b"\nijkl"[..], &b"abcdefgh"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! is_not( ++ ($input:expr, $arr:expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $arr; ++ let bytes = as_bytes(&expected); ++ ++ is_not_bytes!($input, bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! is_not_bytes ( ++ ($input:expr, $bytes:expr) => ( ++ { ++ use $crate::InputLength; ++ let res: $crate::IResult<_,_> = match $input.iter().position(|c| { ++ for &i in $bytes.iter() { ++ if *c == i { return true } ++ } ++ false ++ }) { ++ Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsNot,$input)), ++ Some(n) => { ++ let res = $crate::IResult::Done(&$input[n..], &$input[..n]); ++ res ++ }, ++ None => { ++ $crate::IResult::Done(&$input[$input.input_len()..], $input) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `is_a!(&[T]) => &[T] -> IResult<&[T], &[T]>` ++/// returns the longest list of bytes that appear in the provided array ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(abcd, is_a!( "abcd" )); ++/// ++/// let r1 = abcd(&b"aaaaefgh"[..]); ++/// assert_eq!(r1, Done(&b"efgh"[..], &b"aaaa"[..])); ++/// ++/// let r2 = abcd(&b"dcbaefgh"[..]); ++/// assert_eq!(r2, Done(&b"efgh"[..], &b"dcba"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! is_a ( ++ ($input:expr, $arr:expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $arr; ++ let bytes = as_bytes(&expected); ++ ++ is_a_bytes!($input, bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! is_a_bytes ( ++ ($input:expr, $bytes:expr) => ( ++ { ++ use $crate::InputLength; ++ let res: $crate::IResult<_,_> = match $input.iter().position(|c| { ++ for &i in $bytes.iter() { ++ if *c == i { return false } ++ } ++ true ++ }) { ++ Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsA,$input)), ++ Some(n) => { ++ let res: $crate::IResult<_,_> = $crate::IResult::Done(&$input[n..], &$input[..n]); ++ res ++ }, ++ None => { ++ $crate::IResult::Done(&$input[($input).input_len()..], $input) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `escaped!(&[T] -> IResult<&[T], &[T]>, T, &[T] -> IResult<&[T], &[T]>) => &[T] -> IResult<&[T], &[T]>` ++/// matches a byte string with escaped characters. ++/// ++/// The first argument matches the normal characters (it must not accept the control character), the second argument is the control character (like `\` in most languages), ++/// the third argument matches the escaped characters ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::alpha; ++/// # fn main() { ++/// named!(esc, escaped!(call!(alpha), '\\', is_a_bytes!(&b"\"n\\"[..]))); ++/// assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], &b"abcd"[..])); ++/// assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], &b"ab\\\"cd"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! escaped ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( ++ { ++ escaped1!($i, $submac!($($args)*), $control_char, $($rest)*) ++ } ++ ); ++ ++ ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( ++ escaped1!($i, call!($f), $control_char, $($rest)*) ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! escaped1 ( ++ ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( ++ { ++ escaped_impl!($i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) ++ } ++ ); ++ ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( ++ escaped_impl!($i, $submac1!($($args)*), $control_char, call!($g)) ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! escaped_impl ( ++ ($i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $escapable:ident!( $($args2:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ let cl = || { ++ use $crate::HexDisplay; ++ let mut index = 0; ++ ++ while index < $i.len() { ++ if let $crate::IResult::Done(i,_) = $normal!(&$i[index..], $($args)*) { ++ if i.is_empty() { ++ return $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ } else { ++ index = $i.offset(i); ++ } ++ } else if $i[index] == $control_char as u8 { ++ if index + 1 >= $i.len() { ++ return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Escaped,&$i[index..])); ++ } else { ++ match $escapable!(&$i[index+1..], $($args2)*) { ++ $crate::IResult::Done(i,_) => { ++ if i.is_empty() { ++ return $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ } else { ++ index = $i.offset(i); ++ } ++ }, ++ $crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i), ++ $crate::IResult::Error(e) => return $crate::IResult::Error(e) ++ } ++ } ++ } else { ++ if index == 0 { ++ return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Escaped,&$i[index..])) ++ } else { ++ return $crate::IResult::Done(&$i[index..], &$i[..index]) ++ } ++ } ++ } ++ $crate::IResult::Done(&$i[index..], &$i[..index]) ++ }; ++ match cl() { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => { ++ return $crate::IResult::Error($crate::Err::NodePosition($crate::ErrorKind::Escaped, $i, Box::new(e))) ++ } ++ } ++ } ++ ); ++); ++ ++/// `escaped_transform!(&[T] -> IResult<&[T], &[T]>, T, &[T] -> IResult<&[T], &[T]>) => &[T] -> IResult<&[T], Vec>` ++/// matches a byte string with escaped characters. ++/// ++/// The first argument matches the normal characters (it must not match the control character), the second argument is the control character (like `\` in most languages), ++/// the third argument matches the escaped characters and trnasforms them. ++/// ++/// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::alpha; ++/// # use std::str::from_utf8; ++/// # fn main() { ++/// fn to_s(i:Vec) -> String { ++/// String::from_utf8_lossy(&i).into_owned() ++/// } ++ ++/// named!(transform < String >, ++/// map!( ++/// escaped_transform!(call!(alpha), '\\', ++/// alt!( ++/// tag!("\\") => { |_| &b"\\"[..] } ++/// | tag!("\"") => { |_| &b"\""[..] } ++/// | tag!("n") => { |_| &b"\n"[..] } ++/// ) ++/// ), to_s ++/// ) ++/// ); ++/// assert_eq!(transform(&b"ab\\\"cd"[..]), Done(&b""[..], String::from("ab\"cd"))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! escaped_transform ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( ++ { ++ escaped_transform1!($i, $submac!($($args)*), $control_char, $($rest)*) ++ } ++ ); ++ ++ ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( ++ escaped_transform1!($i, call!($f), $control_char, $($rest)*) ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! escaped_transform1 ( ++ ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( ++ { ++ escaped_transform_impl!($i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) ++ } ++ ); ++ ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( ++ escaped_transform_impl!($i, $submac1!($($args)*), $control_char, call!($g)) ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! escaped_transform_impl ( ++ ($i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $transform:ident!( $($args2:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ let cl = || { ++ use $crate::HexDisplay; ++ let mut index = 0; ++ let mut res = Vec::new(); ++ ++ while index < $i.len() { ++ if let $crate::IResult::Done(i,o) = $normal!(&$i[index..], $($args)*) { ++ res.extend(o.iter().cloned()); ++ if i.is_empty() { ++ return $crate::IResult::Done(&$i[$i.input_len()..], res) ++ } else { ++ index = $i.offset(i); ++ } ++ } else if $i[index] == $control_char as u8 { ++ if index + 1 >= $i.len() { ++ return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::EscapedTransform,&$i[index..])); ++ } else { ++ match $transform!(&$i[index+1..], $($args2)*) { ++ $crate::IResult::Done(i,o) => { ++ res.extend(o.iter().cloned()); ++ if i.is_empty() { ++ return $crate::IResult::Done(&$i[$i.input_len()..], res) ++ } else { ++ index = $i.offset(i); ++ } ++ }, ++ $crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i), ++ $crate::IResult::Error(e) => return $crate::IResult::Error(e) ++ } ++ } ++ } else { ++ if index == 0 { ++ return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::EscapedTransform,&$i[index..])) ++ } else { ++ return $crate::IResult::Done(&$i[index..], res) ++ } ++ } ++ } ++ $crate::IResult::Done(&$i[index..], res) ++ }; ++ match cl() { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => { ++ return $crate::IResult::Error($crate::Err::NodePosition($crate::ErrorKind::EscapedTransform, $i, Box::new(e))) ++ } ++ } ++ } ++ ) ++); ++ ++/// `take_while!(T -> bool) => &[T] -> IResult<&[T], &[T]>` ++/// returns the longest list of bytes until the provided function fails. ++/// ++/// The argument is either a function `T -> bool` or a macro returning a `bool`. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::is_alphanumeric; ++/// # fn main() { ++/// named!( alpha, take_while!( is_alphanumeric ) ); ++/// ++/// let r = alpha(&b"abcd\nefgh"[..]); ++/// assert_eq!(r, Done(&b"\nefgh"[..], &b"abcd"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! take_while ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $input.iter().position(|c| !$submac!(*c, $($args)*)) { ++ Some(n) => { ++ let res:$crate::IResult<_,_> = $crate::IResult::Done(&$input[n..], &$input[..n]); ++ res ++ }, ++ None => { ++ $crate::IResult::Done(&$input[($input).len()..], $input) ++ } ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_while!($input, call!($f)); ++ ); ++); ++ ++/// `take_while1!(&[T] -> bool) => &[T] -> IResult<&[T], &[T]>` ++/// returns the longest (non empty) list of bytes until the provided function fails. ++/// ++/// The argument is either a function `&[T] -> bool` or a macro returning a `bool ++#[macro_export] ++macro_rules! take_while1 ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ if ($input).input_len() == 0 { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1,$input)) ++ } else { ++ match $input.iter().position(|c| !$submac!(*c, $($args)*)) { ++ Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1,$input)), ++ Some(n) => { ++ $crate::IResult::Done(&$input[n..], &$input[..n]) ++ }, ++ None => { ++ $crate::IResult::Done(&$input[($input).len()..], $input) ++ } ++ } ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_while1!($input, call!($f)); ++ ); ++); ++ ++/// `take_till!(T -> bool) => &[T] -> IResult<&[T], &[T]>` ++/// returns the longest list of bytes until the provided function succeeds ++/// ++/// The argument is either a function `&[T] -> bool` or a macro returning a `bool ++#[macro_export] ++macro_rules! take_till ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ match $input.iter().position(|c| $submac!(c, $($args)*)) { ++ Some(n) => $crate::IResult::Done(&$input[n..], &$input[..n]), ++ None => $crate::IResult::Done(&$input[($input).input_len()..], $input) ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_till!($input, call!($f)); ++ ); ++); ++ ++/// `take!(nb) => &[T] -> IResult<&[T], &[T]>` ++/// generates a parser consuming the specified number of bytes ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// // Desmond parser ++/// named!(take5, take!( 5 ) ); ++/// ++/// let a = b"abcdefgh"; ++/// ++/// assert_eq!(take5(&a[..]), Done(&b"fgh"[..], &b"abcde"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! take ( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res: $crate::IResult<_,_> = if $i.len() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ $crate::IResult::Done(&$i[cnt..],&$i[0..cnt]) ++ }; ++ res ++ } ++ ); ++); ++ ++/// `take!(nb) => &[T] -> IResult<&[T], &str>` ++/// same as take! but returning a &str ++#[macro_export] ++macro_rules! take_str ( ++ ( $i:expr, $size:expr ) => ( map_res!($i, take!($size), ::std::str::from_utf8) ); ++); ++ ++/// `take_until_and_consume!(tag) => &[T] -> IResult<&[T], &[T]>` ++/// generates a parser consuming bytes until the specified byte sequence is found, and consumes it ++#[macro_export] ++macro_rules! take_until_and_consume( ++ ($i:expr, $inp:expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ take_until_and_consume_bytes!($i, bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! take_until_and_consume_bytes ( ++ ($i:expr, $bytes:expr) => ( ++ { ++ let res: $crate::IResult<_,_> = if $bytes.len() > $i.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($bytes.len())) ++ } else { ++ let mut index = 0; ++ let mut parsed = false; ++ ++ for idx in 0..$i.len() { ++ if idx + $bytes.len() > $i.len() { ++ index = idx; ++ break; ++ } ++ if &$i[idx..idx + $bytes.len()] == $bytes { ++ parsed = true; ++ index = idx; ++ break; ++ } ++ } ++ ++ if parsed { ++ $crate::IResult::Done(&$i[(index + $bytes.len())..], &$i[0..index]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilAndConsume,$i)) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `take_until!(tag) => &[T] -> IResult<&[T], &[T]>` ++/// consumes data until it finds the specified tag ++#[macro_export] ++macro_rules! take_until( ++ ($i:expr, $inp:expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ take_until_bytes!($i, bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! take_until_bytes( ++ ($i:expr, $bytes:expr) => ( ++ { ++ let res: $crate::IResult<_,_> = if $bytes.len() > $i.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($bytes.len())) ++ } else { ++ let mut index = 0; ++ let mut parsed = false; ++ ++ for idx in 0..$i.len() { ++ if idx + $bytes.len() > $i.len() { ++ index = idx; ++ break; ++ } ++ if &$i[idx..idx+$bytes.len()] == $bytes { ++ parsed = true; ++ index = idx; ++ break; ++ } ++ } ++ ++ if parsed { ++ $crate::IResult::Done(&$i[index..], &$i[0..index]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntil,$i)) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `take_until_either_and_consume!(tag) => &[T] -> IResult<&[T], &[T]>` ++/// consumes data until it finds any of the specified characters, and consume it ++#[macro_export] ++macro_rules! take_until_either_and_consume( ++ ($i:expr, $inp:expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ take_until_either_and_consume_bytes!($i, bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! take_until_either_and_consume_bytes( ++ ($i:expr, $bytes:expr) => ( ++ { ++ let res: $crate::IResult<_,_> = if 1 > $i.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size(1)) ++ } else { ++ let mut index = 0; ++ let mut parsed = false; ++ ++ for idx in 0..$i.len() { ++ if idx + 1 > $i.len() { ++ index = idx; ++ break; ++ } ++ for &t in $bytes.iter() { ++ if $i[idx] == t { ++ parsed = true; ++ index = idx; ++ break; ++ } ++ } ++ if parsed { break; } ++ } ++ ++ if parsed { ++ $crate::IResult::Done(&$i[(index+1)..], &$i[0..index]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilEitherAndConsume,$i)) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `take_until_either!(tag) => &[T] -> IResult<&[T], &[T]>` ++#[macro_export] ++macro_rules! take_until_either( ++ ($i:expr, $inp:expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ take_until_either_bytes!($i, bytes) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! take_until_either_bytes( ++ ($i:expr, $bytes:expr) => ( ++ { ++ let res: $crate::IResult<_,_> = if 1 > $i.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size(1)) ++ } else { ++ let mut index = 0; ++ let mut parsed = false; ++ ++ for idx in 0..$i.len() { ++ if idx + 1 > $i.len() { ++ index = idx; ++ break; ++ } ++ for &t in $bytes.iter() { ++ if $i[idx] == t { ++ parsed = true; ++ index = idx; ++ break; ++ } ++ } ++ if parsed { break; } ++ } ++ ++ if parsed { ++ $crate::IResult::Done(&$i[index..], &$i[0..index]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilEither,$i)) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `length_bytes!(&[T] -> IResult<&[T], nb>) => &[T] -> IResult<&[T], &[T]> ++/// gets a number from the first parser, then extracts that many bytes from the ++/// remaining stream ++#[macro_export] ++macro_rules! length_bytes( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1,nb) => { ++ let nb = nb as usize; ++ let length_remaining = i1.len(); ++ if length_remaining < nb { ++ $crate::IResult::Incomplete($crate::Needed::Size(nb - length_remaining)) ++ } else { ++ $crate::IResult::Done(&i1[nb..], &i1[..nb]) ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ length_bytes!($i, call!($f)) ++ ) ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::Needed; ++ use internal::IResult::*; ++ use internal::Err::*; ++ use util::ErrorKind; ++ use nom::{alpha, digit, hex_digit, oct_digit, alphanumeric, space, multispace}; ++ ++ #[test] ++ fn is_a() { ++ named!(a_or_b, is_a!(&b"ab"[..])); ++ ++ let a = &b"abcd"[..]; ++ assert_eq!(a_or_b(a), Done(&b"cd"[..], &b"ab"[..])); ++ ++ let b = &b"bcde"[..]; ++ assert_eq!(a_or_b(b), Done(&b"cde"[..], &b"b"[..])); ++ ++ let c = &b"cdef"[..]; ++ assert_eq!(a_or_b(c), Error(Position(ErrorKind::IsA,c))); ++ ++ let d = &b"bacdef"[..]; ++ assert_eq!(a_or_b(d), Done(&b"cdef"[..], &b"ba"[..])); ++ } ++ ++ #[test] ++ fn is_not() { ++ named!(a_or_b, is_not!(&b"ab"[..])); ++ ++ let a = &b"cdab"[..]; ++ assert_eq!(a_or_b(a), Done(&b"ab"[..], &b"cd"[..])); ++ ++ let b = &b"cbde"[..]; ++ assert_eq!(a_or_b(b), Done(&b"bde"[..], &b"c"[..])); ++ ++ let c = &b"abab"[..]; ++ assert_eq!(a_or_b(c), Error(Position(ErrorKind::IsNot,c))); ++ ++ let d = &b"cdefba"[..]; ++ assert_eq!(a_or_b(d), Done(&b"ba"[..], &b"cdef"[..])); ++ ++ let e = &b"e"[..]; ++ assert_eq!(a_or_b(e), Done(&b""[..], &b"e"[..])); ++ ++ let f = &b"fghi"[..]; ++ assert_eq!(a_or_b(f), Done(&b""[..], &b"fghi"[..])); ++ } ++ ++ #[test] ++ fn escaping() { ++ named!(esc, escaped!(call!(alpha), '\\', is_a_bytes!(&b"\"n\\"[..]))); ++ assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], &b"abcd"[..])); ++ assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], &b"ab\\\"cd"[..])); ++ assert_eq!(esc(&b"\\\"abcd"[..]), Done(&b""[..], &b"\\\"abcd"[..])); ++ assert_eq!(esc(&b"\\n"[..]), Done(&b""[..], &b"\\n"[..])); ++ assert_eq!(esc(&b"ab\\\"12"[..]), Done(&b"12"[..], &b"ab\\\""[..])); ++ assert_eq!(esc(&b"AB\\"[..]), Error(NodePosition(ErrorKind::Escaped, &b"AB\\"[..], Box::new(Position(ErrorKind::Escaped, &b"\\"[..]))))); ++ assert_eq!(esc(&b"AB\\A"[..]), Error(NodePosition(ErrorKind::Escaped, &b"AB\\A"[..], Box::new(Position(ErrorKind::IsA, &b"A"[..]))))); ++ } ++ ++ fn to_s(i:Vec) -> String { ++ String::from_utf8_lossy(&i).into_owned() ++ } ++ ++ #[test] ++ fn escape_transform() { ++ use std::str; ++ ++ named!(esc< String >, map!(escaped_transform!(alpha, '\\', ++ alt!( ++ tag!("\\") => { |_| &b"\\"[..] } ++ | tag!("\"") => { |_| &b"\""[..] } ++ | tag!("n") => { |_| &b"\n"[..] } ++ )), to_s) ++ ); ++ ++ assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], String::from("abcd"))); ++ assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], String::from("ab\"cd"))); ++ assert_eq!(esc(&b"\\\"abcd"[..]), Done(&b""[..], String::from("\"abcd"))); ++ assert_eq!(esc(&b"\\n"[..]), Done(&b""[..], String::from("\n"))); ++ assert_eq!(esc(&b"ab\\\"12"[..]), Done(&b"12"[..], String::from("ab\""))); ++ assert_eq!(esc(&b"AB\\"[..]), Error(NodePosition(ErrorKind::EscapedTransform, &b"AB\\"[..], Box::new(Position(ErrorKind::EscapedTransform, &b"\\"[..]))))); ++ assert_eq!(esc(&b"AB\\A"[..]), Error(NodePosition(ErrorKind::EscapedTransform, &b"AB\\A"[..], Box::new(Position(ErrorKind::Alt, &b"A"[..]))))); ++ ++ let e = "è"; ++ let a = "à"; ++ println!("è: {:?} | à: {:?}", str::as_bytes(e), str::as_bytes(a)); ++ named!(esc2< String >, map!(escaped_transform!(call!(alpha), '&', ++ alt!( ++ tag!("egrave;") => { |_| str::as_bytes("è") } ++ | tag!("agrave;") => { |_| str::as_bytes("à") } ++ )), to_s) ++ ); ++ assert_eq!(esc2(&b"abèDEF"[..]), Done(&b""[..], String::from("abèDEF"))); ++ assert_eq!(esc2(&b"abèDàEF"[..]), Done(&b""[..], String::from("abèDàEF"))); ++ } ++ ++ #[test] ++ fn issue_84() { ++ let r0 = is_a!(&b"aaaaefgh"[..], "abcd"); ++ assert_eq!(r0, Done(&b"efgh"[..], &b"aaaa"[..])); ++ let r1 = is_a!(&b"aaaa"[..], "abcd"); ++ assert_eq!(r1, Done(&b""[..], &b"aaaa"[..])); ++ let r2 = is_a!(&b"1"[..], "123456789"); ++ assert_eq!(r2, Done(&b""[..], &b"1"[..])); ++ } ++ ++ #[test] ++ fn take_str_test() { ++ let a = b"omnomnom"; ++ ++ assert_eq!(take_str!(&a[..], 5), Done(&b"nom"[..], "omnom")); ++ assert_eq!(take_str!(&a[..], 9), Incomplete(Needed::Size(9))); ++ } ++ ++ #[test] ++ fn take_until_test() { ++ named!(x, take_until_and_consume!("efgh")); ++ let r = x(&b"abcdabcdefghijkl"[..]); ++ assert_eq!(r, Done(&b"ijkl"[..], &b"abcdabcd"[..])); ++ ++ println!("Done 1\n"); ++ ++ let r2 = x(&b"abcdabcdefgh"[..]); ++ assert_eq!(r2, Done(&b""[..], &b"abcdabcd"[..])); ++ ++ println!("Done 2\n"); ++ let r3 = x(&b"abcefg"[..]); ++ assert_eq!(r3, Error(Position(ErrorKind::TakeUntilAndConsume, &b"abcefg"[..]))); ++ ++ assert_eq!( ++ x(&b"ab"[..]), ++ Incomplete(Needed::Size(4)) ++ ); ++ } ++ ++ #[test] ++ fn take_until_either_incomplete() { ++ named!(x, take_until_either!("!.")); ++ assert_eq!( ++ x(&b"123"[..]), ++ Error(Position(ErrorKind::TakeUntilEither, &b"123"[..])) ++ ); ++ } ++ ++ #[test] ++ fn take_until_incomplete() { ++ named!(y, take_until!("end")); ++ assert_eq!( ++ y(&b"nd"[..]), ++ Incomplete(Needed::Size(3)) ++ ); ++ assert_eq!( ++ y(&b"123"[..]), ++ Error(Position(ErrorKind::TakeUntil, &b"123"[..])) ++ ); ++ } ++ ++ #[test] ++ fn recognize() { ++ named!(x, recognize!(delimited!(tag!("")))); ++ let r = x(&b" aaa"[..]); ++ assert_eq!(r, Done(&b" aaa"[..], &b""[..])); ++ ++ let empty = &b""[..]; ++ ++ named!(ya, recognize!(alpha)); ++ let ra = ya(&b"abc"[..]); ++ assert_eq!(ra, Done(empty, &b"abc"[..])); ++ ++ named!(yd, recognize!(digit)); ++ let rd = yd(&b"123"[..]); ++ assert_eq!(rd, Done(empty, &b"123"[..])); ++ ++ named!(yhd, recognize!(hex_digit)); ++ let rhd = yhd(&b"123abcDEF"[..]); ++ assert_eq!(rhd, Done(empty, &b"123abcDEF"[..])); ++ ++ named!(yod, recognize!(oct_digit)); ++ let rod = yod(&b"1234567"[..]); ++ assert_eq!(rod, Done(empty, &b"1234567"[..])); ++ ++ named!(yan, recognize!(alphanumeric)); ++ let ran = yan(&b"123abc"[..]); ++ assert_eq!(ran, Done(empty, &b"123abc"[..])); ++ ++ named!(ys, recognize!(space)); ++ let rs = ys(&b" \t"[..]); ++ assert_eq!(rs, Done(empty, &b" \t"[..])); ++ ++ named!(yms, recognize!(multispace)); ++ let rms = yms(&b" \t\r\n"[..]); ++ assert_eq!(rms, Done(empty, &b" \t\r\n"[..])); ++ } ++ ++ #[test] ++ fn take_while() { ++ use nom::is_alphabetic; ++ named!(f, take_while!(is_alphabetic)); ++ let a = b""; ++ let b = b"abcd"; ++ let c = b"abcd123"; ++ let d = b"123"; ++ ++ assert_eq!(f(&a[..]), Done(&a[..], &a[..])); ++ assert_eq!(f(&b[..]), Done(&a[..], &b[..])); ++ assert_eq!(f(&c[..]), Done(&d[..], &b[..])); ++ assert_eq!(f(&d[..]), Done(&d[..], &a[..])); ++ } ++ ++ #[test] ++ fn take_while1() { ++ use nom::is_alphabetic; ++ named!(f, take_while1!(is_alphabetic)); ++ let a = b""; ++ let b = b"abcd"; ++ let c = b"abcd123"; ++ let d = b"123"; ++ ++ assert_eq!(f(&a[..]), Error(Position(ErrorKind::TakeWhile1, &b""[..]))); ++ assert_eq!(f(&b[..]), Done(&a[..], &b[..])); ++ assert_eq!(f(&c[..]), Done(&b"123"[..], &b[..])); ++ assert_eq!(f(&d[..]), Error(Position(ErrorKind::TakeWhile1, &d[..]))); ++ } ++ ++ #[cfg(feature = "nightly")] ++ use test::Bencher; ++ ++ #[cfg(feature = "nightly")] ++ #[bench] ++ fn take_while_bench(b: &mut Bencher) { ++ use nom::is_alphabetic; ++ named!(f, take_while!(is_alphabetic)); ++ b.iter(|| { ++ f(&b"abcdefghijklABCDEejfrfrjgro12aa"[..]) ++ }); ++ } ++ ++ #[test] ++ fn recognize_take_while() { ++ use nom::is_alphanumeric; ++ named!(x, take_while!(is_alphanumeric)); ++ named!(y, recognize!(x)); ++ assert_eq!(x(&b"ab"[..]), Done(&[][..], &b"ab"[..])); ++ println!("X: {:?}", x(&b"ab"[..])); ++ assert_eq!(y(&b"ab"[..]), Done(&[][..], &b"ab"[..])); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/character.rs third_party/rust/nom-1.2.4/src/character.rs +new file mode 100644 +index 000000000000..781065b35270 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/character.rs +@@ -0,0 +1,184 @@ ++/// Character level parsers ++ ++use internal::{IResult,Needed,Err}; ++use util::ErrorKind; ++ ++/// matches one of the provided characters ++#[macro_export] ++macro_rules! one_of ( ++ ($i:expr, $inp: expr) => ( ++ { ++ if $i.is_empty() { ++ $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) ++ } else { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ one_of_bytes!($i, bytes) ++ } ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! one_of_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ if $i.is_empty() { ++ $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) ++ } else { ++ let mut found = false; ++ ++ for &i in $bytes { ++ if i == $i[0] { ++ found = true; ++ break; ++ } ++ } ++ ++ if found { ++ $crate::IResult::Done(&$i[1..], $i[0] as char) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::OneOf, $i)) ++ } ++ } ++ } ++ ); ++); ++ ++/// matches anything but the provided characters ++#[macro_export] ++macro_rules! none_of ( ++ ($i:expr, $inp: expr) => ( ++ { ++ if $i.is_empty() { ++ $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) ++ } else { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ none_of_bytes!($i, bytes) ++ } ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! none_of_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ if $i.is_empty() { ++ $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) ++ } else { ++ let mut found = false; ++ ++ for &i in $bytes { ++ if i == $i[0] { ++ found = true; ++ break; ++ } ++ } ++ ++ if !found { ++ $crate::IResult::Done(&$i[1..], $i[0] as char) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::NoneOf, $i)) ++ } ++ } ++ } ++ ); ++); ++ ++/// matches one character: `char!(char) => &[u8] -> IResult<&[u8], char> ++#[macro_export] ++macro_rules! char ( ++ ($i:expr, $c: expr) => ( ++ { ++ if $i.is_empty() { ++ let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1)); ++ res ++ } else { ++ if $i[0] == $c as u8 { ++ $crate::IResult::Done(&$i[1..], $i[0] as char) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Char, $i)) ++ } ++ } ++ } ++ ); ++); ++ ++named!(pub newline, char!('\n')); ++ ++pub fn crlf(input:&[u8]) -> IResult<&[u8], char> { ++ if input.len() < 2 { ++ IResult::Incomplete(Needed::Size(2)) ++ } else { ++ if &input[0..2] == &b"\r\n"[..] { ++ IResult::Done(&input[2..], '\n') ++ } else { ++ IResult::Error(Err::Position(ErrorKind::CrLf, input)) ++ } ++ } ++} ++ ++named!(pub eol, alt!(crlf | newline)); ++named!(pub tab, char!('\t')); ++ ++pub fn anychar(input:&[u8]) -> IResult<&[u8], char> { ++ if input.is_empty() { ++ IResult::Incomplete(Needed::Size(1)) ++ } else { ++ IResult::Done(&input[1..], input[0] as char) ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use internal::IResult::*; ++ use internal::Err::*; ++ use util::ErrorKind; ++ ++ #[test] ++ fn one_of() { ++ named!(f, one_of!("ab")); ++ ++ let a = &b"abcd"[..]; ++ assert_eq!(f(a), Done(&b"bcd"[..], 'a')); ++ ++ let b = &b"cde"[..]; ++ assert_eq!(f(b), Error(Position(ErrorKind::OneOf, b))); ++ } ++ ++ #[test] ++ fn none_of() { ++ named!(f, none_of!("ab")); ++ ++ let a = &b"abcd"[..]; ++ assert_eq!(f(a), Error(Position(ErrorKind::NoneOf, a))); ++ ++ let b = &b"cde"[..]; ++ assert_eq!(f(b), Done(&b"de"[..], 'c')); ++ } ++ ++ #[test] ++ fn char() { ++ named!(f, char!('c')); ++ ++ let a = &b"abcd"[..]; ++ assert_eq!(f(a), Error(Position(ErrorKind::Char, a))); ++ ++ let b = &b"cde"[..]; ++ assert_eq!(f(b), Done(&b"de"[..], 'c')); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/internal.rs third_party/rust/nom-1.2.4/src/internal.rs +new file mode 100644 +index 000000000000..deb39a86654d +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/internal.rs +@@ -0,0 +1,347 @@ ++//! Basic types to build the parsers ++ ++use self::IResult::*; ++use self::Needed::*; ++use util::ErrorKind; ++ ++#[cfg(feature = "core")] ++use std::prelude::v1::*; ++use std::boxed::Box; ++ ++/// Contains the error that a parser can return ++/// ++/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data. ++/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32) ++#[derive(Debug,PartialEq,Eq,Clone)] ++pub enum Err{ ++ /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E ++ Code(ErrorKind), ++ /// An error code, and the next error ++ Node(ErrorKind, Box>), ++ /// An error code, and the input position ++ Position(ErrorKind, P), ++ /// An error code, the input position and the next error ++ NodePosition(ErrorKind, P, Box>) ++} ++ ++/// Contains information on needed data if a parser returned `Incomplete` ++#[derive(Debug,PartialEq,Eq,Clone,Copy)] ++pub enum Needed { ++ /// needs more data, but we do not know how much ++ Unknown, ++ /// contains the required data size ++ Size(usize) ++} ++ ++impl Needed { ++ pub fn is_known(&self) -> bool { ++ *self != Unknown ++ } ++ ++ /// Maps a `Needed` to `Needed` by appling a function to a contained `Size` value. ++ #[inline] ++ pub fn map usize>(self, f: F) -> Needed { ++ match self { ++ Unknown => Unknown, ++ Size(n) => Size(f(n)), ++ } ++ } ++} ++ ++/// Holds the result of parsing functions ++/// ++/// It depends on I, the input type, O, the output type, and E, the error type (by default u32) ++/// ++#[derive(Debug,PartialEq,Eq,Clone)] ++pub enum IResult { ++ /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data ++ Done(I,O), ++ /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree ++ Error(Err), ++ /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown ++ Incomplete(Needed) ++} ++ ++impl IResult { ++ pub fn is_done(&self) -> bool { ++ match *self { ++ Done(_,_) => true, ++ _ => false ++ } ++ } ++ ++ pub fn is_err(&self) -> bool { ++ match *self { ++ Error(_) => true, ++ _ => false ++ } ++ } ++ ++ pub fn is_incomplete(&self) -> bool { ++ match *self { ++ Incomplete(_) => true, ++ _ => false ++ } ++ } ++ ++ /// Maps a `IResult` to `IResult` by appling a function ++ /// to a contained `Done` value, leaving `Error` and `Incomplete` value ++ /// untouched. ++ #[inline] ++ pub fn map N>(self, f: F) -> IResult { ++ match self { ++ Done(i, o) => Done(i, f(o)), ++ Error(e) => Error(e), ++ Incomplete(n) => Incomplete(n), ++ } ++ } ++ ++ /// Maps a `IResult` to `IResult` by appling a function ++ /// to a contained `Incomplete` value, leaving `Done` and `Error` value ++ /// untouched. ++ #[inline] ++ pub fn map_inc(self, f: F) -> IResult ++ where F: FnOnce(Needed) -> Needed { ++ match self { ++ Error(e) => Error(e), ++ Incomplete(n) => Incomplete(f(n)), ++ Done(i, o) => Done(i, o), ++ } ++ } ++ ++ /// Maps a `IResult` to `IResult` by appling a function ++ /// to a contained `Error` value, leaving `Done` and `Incomplete` value ++ /// untouched. ++ #[inline] ++ pub fn map_err(self, f: F) -> IResult ++ where F: FnOnce(Err) -> Err { ++ match self { ++ Error(e) => Error(f(e)), ++ Incomplete(n) => Incomplete(n), ++ Done(i, o) => Done(i, o), ++ } ++ } ++ ++ /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not ++ /// `Done`. ++ pub fn unwrap(self) -> (I, O) { ++ match self { ++ Done(i, o) => (i, o), ++ Incomplete(_) => panic!("unwrap() called on an IResult that is Incomplete"), ++ Error(_) => panic!("unwrap() called on an IResult that is Error") ++ } ++ } ++ ++ /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not ++ /// `Done`. ++ pub fn unwrap_inc(self) -> Needed { ++ match self { ++ Incomplete(n) => n, ++ Done(_, _) => panic!("unwrap_inc() called on an IResult that is Done"), ++ Error(_) => panic!("unwrap_inc() called on an IResult that is Error") ++ } ++ } ++ ++ /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not ++ /// `Done`. ++ pub fn unwrap_err(self) -> Err { ++ match self { ++ Error(e) => e, ++ Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"), ++ Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"), ++ } ++ } ++} ++ ++pub trait GetInput { ++ fn remaining_input(&self) -> Option; ++} ++ ++pub trait GetOutput { ++ fn output(&self) -> Option; ++} ++ ++impl<'a,I,O,E> GetInput<&'a[I]> for IResult<&'a[I],O,E> { ++ fn remaining_input(&self) -> Option<&'a[I]> { ++ match *self { ++ Done(ref i,_) => Some(*i), ++ _ => None ++ } ++ } ++} ++ ++impl GetInput<()> for IResult<(),O,E> { ++ fn remaining_input(&self) -> Option<()> { ++ match *self { ++ Done((),_) => Some(()), ++ _ => None ++ } ++ } ++} ++ ++impl<'a,O,E> GetInput<&'a str> for IResult<&'a str,O,E> { ++ fn remaining_input(&self) -> Option<&'a str> { ++ match *self { ++ Done(ref i,_) => Some(*i), ++ _ => None ++ } ++ } ++} ++ ++impl<'a,I,O,E> GetOutput<&'a[O]> for IResult { ++ fn output(&self) -> Option<&'a[O]> { ++ match *self { ++ Done(_, ref o) => Some(*o), ++ _ => None ++ } ++ } ++} ++ ++impl GetOutput<()> for IResult { ++ fn output(&self) -> Option<()> { ++ match *self { ++ Done(_,()) => Some(()), ++ _ => None ++ } ++ } ++} ++ ++impl<'a,I,E> GetOutput<&'a str> for IResult { ++ fn output(&self) -> Option<&'a str> { ++ match *self { ++ Done(_,ref o) => Some(*o), ++ _ => None ++ } ++ } ++} ++ ++#[cfg(not(feature = "core"))] ++use std::any::Any; ++#[cfg(not(feature = "core"))] ++use std::{error,fmt}; ++#[cfg(not(feature = "core"))] ++use std::fmt::Debug; ++#[cfg(not(feature = "core"))] ++impl error::Error for Err { ++ fn description(&self) -> &str { ++ let kind = match *self { ++ Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e ++ }; ++ kind.description() ++ } ++} ++ ++#[cfg(not(feature = "core"))] ++impl fmt::Display for Err { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ match *self { ++ Err::Code(ref e) | Err::Node(ref e, _) => { ++ write!(f, "{:?}", e) ++ }, ++ Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => { ++ write!(f, "{:?}:{:?}", p, e) ++ } ++ } ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use util::ErrorKind; ++ ++ const REST: [u8; 0] = []; ++ const DONE: IResult<&'static [u8], u32> = IResult::Done(&REST, 5); ++ const ERROR: IResult<&'static [u8], u32> = IResult::Error(Err::Code(ErrorKind::Tag)); ++ const INCOMPLETE: IResult<&'static [u8], u32> = IResult::Incomplete(Needed::Unknown); ++ ++ #[test] ++ fn needed_map() { ++ let unknown = Needed::Unknown; ++ let size = Needed::Size(5); ++ ++ assert_eq!(size.map(|x| x * 2), Needed::Size(10)); ++ assert_eq!(unknown.map(|x| x * 2), Needed::Unknown); ++ } ++ ++ #[test] ++ fn iresult_map() { ++ assert_eq!(DONE.map(|x| x * 2), IResult::Done(&b""[..], 10)); ++ assert_eq!(ERROR.map(|x| x * 2), IResult::Error(Err::Code(ErrorKind::Tag))); ++ assert_eq!(INCOMPLETE.map(|x| x * 2), IResult::Incomplete(Needed::Unknown)); ++ } ++ ++ #[test] ++ fn iresult_map_inc() { ++ let inc_unknown: IResult<&[u8], u32> = IResult::Incomplete(Needed::Unknown); ++ let inc_size: IResult<&[u8], u32> = IResult::Incomplete(Needed::Size(5)); ++ ++ assert_eq!(DONE.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Done(&b""[..], 5)); ++ assert_eq!(ERROR.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Error(Err::Code(ErrorKind::Tag))); ++ assert_eq!(inc_unknown.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Unknown)); ++ assert_eq!(inc_size.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Size(6))); ++ } ++ ++ #[test] ++ fn iresult_map_err() { ++ #[derive(Clone, Copy, Debug, PartialEq, Eq)] ++ struct Error(u32); ++ ++ let error_kind = Err::Code(ErrorKind::Custom(Error(5))); ++ ++ assert_eq!(DONE.map_err(|_| error_kind.clone()), IResult::Done(&b""[..], 5)); ++ assert_eq!(ERROR.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Error(error_kind.clone())); ++ assert_eq!(INCOMPLETE.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Incomplete(Needed::Unknown)); ++ } ++ ++ #[test] ++ fn iresult_unwrap_on_done() { ++ assert_eq!(DONE.unwrap(), (&b""[..], 5)); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_unwrap_on_err() { ++ ERROR.unwrap(); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_unwrap_on_inc() { ++ INCOMPLETE.unwrap(); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_unwrap_err_on_done() { ++ DONE.unwrap_err(); ++ } ++ ++ #[test] ++ fn iresult_unwrap_err_on_err() { ++ assert_eq!(ERROR.unwrap_err(), Err::Code(ErrorKind::Tag)); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_unwrap_err_on_inc() { ++ INCOMPLETE.unwrap_err(); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_unwrap_inc_on_done() { ++ DONE.unwrap_inc(); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_unwrap_inc_on_err() { ++ ERROR.unwrap_inc(); ++ } ++ ++ #[test] ++ fn iresult_unwrap_inc_on_inc() { ++ assert_eq!(INCOMPLETE.unwrap_inc(), Needed::Unknown); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/lib.rs third_party/rust/nom-1.2.4/src/lib.rs +new file mode 100644 +index 000000000000..11b475d59517 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/lib.rs +@@ -0,0 +1,151 @@ ++//! nom, eating data byte by byte ++//! ++//! nom is a parser combinator library with a focus on safe parsing, ++//! streaming patterns, and as much as possible zero copy. ++//! ++//! The code is available on [Github](https://github.com/Geal/nom) ++//! ++//! # Example ++//! ++//! ``` ++//! #[macro_use] ++//! extern crate nom; ++//! ++//! use nom::{IResult,digit}; ++//! use nom::IResult::*; ++//! ++//! // Parser definition ++//! ++//! use std::str; ++//! use std::str::FromStr; ++//! ++//! named!(parens, delimited!( ++//! char!('('), ++//! expr, ++//! char!(')') ++//! ) ++//! ); ++//! ++//! named!(i64_digit, ++//! map_res!( ++//! map_res!( ++//! digit, ++//! str::from_utf8 ++//! ), ++//! FromStr::from_str ++//! ) ++//! ); ++//! ++//! // We transform an integer string into a i64 ++//! // we look for a digit suite, and try to convert it. ++//! // if either str::from_utf8 or FromStr::from_str fail, ++//! // the parser will fail ++//! named!(factor, ++//! alt!( ++//! i64_digit ++//! | parens ++//! ) ++//! ); ++//! ++//! // we define acc as mutable to update its value whenever a new term is found ++//! named!(term , ++//! chain!( ++//! mut acc: factor ~ ++//! many0!( ++//! alt!( ++//! tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) | ++//! tap!(div: preceded!(tag!("/"), factor) => acc = acc / div) ++//! ) ++//! ), ++//! || { return acc } ++//! ) ++//! ); ++//! ++//! named!(expr , ++//! chain!( ++//! mut acc: term ~ ++//! many0!( ++//! alt!( ++//! tap!(add: preceded!(tag!("+"), term) => acc = acc + add) | ++//! tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub) ++//! ) ++//! ), ++//! || { return acc } ++//! ) ++//! ); ++//! ++//! fn main() { ++//! assert_eq!(expr(b"1+2"), IResult::Done(&b""[..], 3)); ++//! assert_eq!(expr(b"12+6-4+3"), IResult::Done(&b""[..], 17)); ++//! assert_eq!(expr(b"1+2*3+4"), IResult::Done(&b""[..], 11)); ++//! ++//! assert_eq!(expr(b"(2)"), IResult::Done(&b""[..], 2)); ++//! assert_eq!(expr(b"2*(3+4)"), IResult::Done(&b""[..], 14)); ++//! assert_eq!(expr(b"2*2/(5-1)+3"), IResult::Done(&b""[..], 4)); ++//! } ++//! ``` ++#![cfg_attr(feature = "core", feature(no_std))] ++#![cfg_attr(feature = "core", feature(collections))] ++#![cfg_attr(feature = "core", no_std)] ++#![cfg_attr(feature = "nightly", feature(test))] ++#![cfg_attr(feature = "nightly", feature(const_fn))] ++ ++#[cfg(feature = "core")] ++extern crate collections; ++#[cfg(feature = "regexp")] ++extern crate regex; ++#[cfg(feature = "regexp_macros")] ++#[macro_use] extern crate lazy_static; ++#[cfg(feature = "nightly")] ++extern crate test; ++ ++#[cfg(feature = "core")] ++mod std { ++#[macro_use] ++ pub use core::{fmt, iter, option, ops, slice, mem}; ++ pub use collections::{boxed, vec, string}; ++ pub mod prelude { ++ pub use core::prelude as v1; ++ } ++} ++ ++pub use self::util::*; ++pub use self::internal::*; ++pub use self::macros::*; ++pub use self::methods::*; ++pub use self::bytes::*; ++pub use self::bits::*; ++ ++pub use self::nom::*; ++pub use self::character::*; ++ ++#[cfg(feature = "regexp")] ++pub use self::regexp::*; ++ ++#[cfg(not(feature = "core"))] ++#[cfg(feature = "stream")] ++pub use self::stream::*; ++ ++#[cfg(not(feature = "core"))] ++pub use self::str::*; ++ ++#[macro_use] mod util; ++mod internal; ++#[macro_use] mod macros; ++#[macro_use] mod methods; ++#[macro_use] mod bytes; ++#[macro_use] mod bits; ++ ++#[macro_use] mod nom; ++#[macro_use] mod character; ++ ++#[cfg(feature = "regexp")] ++#[macro_use] mod regexp; ++ ++#[macro_use] ++#[cfg(not(feature = "core"))] ++#[cfg(feature = "stream")] ++mod stream; ++ ++#[cfg(not(feature = "core"))] ++mod str; +diff --git third_party/rust/nom-1.2.4/src/macros.rs third_party/rust/nom-1.2.4/src/macros.rs +new file mode 100644 +index 000000000000..3e346a94f522 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/macros.rs +@@ -0,0 +1,3561 @@ ++//! Macro combinators ++//! ++//! Macros are used to make combination easier, ++//! since they often do not depend on the type ++//! of the data they manipulate or return. ++//! ++//! There is a trick to make them easier to assemble, ++//! combinators are defined like this: ++//! ++//! ```ignore ++//! macro_rules! tag ( ++//! ($i:expr, $inp: expr) => ( ++//! { ++//! ... ++//! } ++//! ); ++//! ); ++//! ``` ++//! ++//! But when used in other combinators, are Used ++//! like this: ++//! ++//! ```ignore ++//! named!(my_function, tag!("abcd")); ++//! ``` ++//! ++//! Internally, other combinators will rewrite ++//! that call to pass the input as first argument: ++//! ++//! ```ignore ++//! macro_rules! named ( ++//! ($name:ident, $submac:ident!( $($args:tt)* )) => ( ++//! fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<'a,&[u8], &[u8]> { ++//! $submac!(i, $($args)*) ++//! } ++//! ); ++//! ); ++//! ``` ++//! ++//! If you want to call a combinator directly, you can ++//! do it like this: ++//! ++//! ```ignore ++//! let res = { tag!(input, "abcd"); } ++//! ``` ++//! ++//! Combinators must have a specific variant for ++//! non-macro arguments. Example: passing a function ++//! to take_while! instead of another combinator. ++//! ++//! ```ignore ++//! macro_rules! take_while( ++//! ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++//! { ++//! ... ++//! } ++//! ); ++//! ++//! // wrap the function in a macro to pass it to the main implementation ++//! ($input:expr, $f:expr) => ( ++//! take_while!($input, call!($f)); ++//! ); ++//! ); ++//! ++ ++/// Wraps a parser in a closure ++#[macro_export] ++macro_rules! closure ( ++ ($ty:ty, $submac:ident!( $($args:tt)* )) => ( ++ |i: $ty| { $submac!(i, $($args)*) } ++ ); ++ ($submac:ident!( $($args:tt)* )) => ( ++ |i| { $submac!(i, $($args)*) } ++ ); ++); ++ ++/// Makes a function from a parser combination ++/// ++/// The type can be set up if the compiler needs ++/// more information ++/// ++/// ```ignore ++/// named!(my_function( &[u8] ) -> &[u8], tag!("abcd")); ++/// // first type parameter is input, second is output ++/// named!(my_function<&[u8], &[u8]>, tag!("abcd")); ++/// // will have &[u8] as input type, &[u8] as output type ++/// named!(my_function, tag!("abcd")); ++/// // will use &[u8] as input type (use this if the compiler ++/// // complains about lifetime issues ++/// named!(my_function<&[u8]>, tag!("abcd")); ++/// //prefix them with 'pub' to make the functions public ++/// named!(pub my_function, tag!("abcd")); ++/// ``` ++#[macro_export] ++macro_rules! named ( ++ ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: $i ) -> $crate::IResult<$i,$o,u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name<'a>( i: &'a[u8] ) -> $crate::IResult<&'a [u8], $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($name:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ (pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ (pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ (pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ (pub $name:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++); ++ ++/// Used to wrap common expressions and function as macros ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult; ++/// # fn main() { ++/// fn take_wrapper(input: &[u8], i: u8) -> IResult<&[u8],&[u8]> { take!(input, i * 10) } ++/// ++/// // will make a parser taking 20 bytes ++/// named!(parser, apply!(take_wrapper, 2)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! call ( ++ ($i:expr, $fun:expr) => ( $fun( $i ) ); ++ ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) ); ++); ++ ++/// emulate function currying: `apply!(my_function, arg1, arg2, ...)` becomes `my_function(input, arg1, arg2, ...)` ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult; ++/// # fn main() { ++/// fn take_wrapper(input: &[u8], i: u8) -> IResult<&[u8],&[u8]> { take!(input, i * 10) } ++/// ++/// // will make a parser taking 20 bytes ++/// named!(parser, apply!(take_wrapper, 2)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! apply ( ++ ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) ); ++); ++ ++/// Prevents backtracking if the child parser fails ++/// ++/// This parser will do an early return instead of sending ++/// its result to the parent parser. ++/// ++/// If another `error!` combinator is present in the parent ++/// chain, the error will be wrapped and another early ++/// return will be made. ++/// ++/// This makes it easy to build report on which parser failed, ++/// where it failed in the input, and the chain of parsers ++/// that led it there. ++/// ++/// Additionally, the error chain contains number identifiers ++/// that can be matched to provide useful error messages. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use std::collections; ++/// # use nom::IResult::Error; ++/// # use nom::Err::{Position,NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(err_test, alt!( ++/// tag!("abcd") | ++/// preceded!(tag!("efgh"), error!(ErrorKind::Custom(42), ++/// chain!( ++/// tag!("ijkl") ~ ++/// res: error!(ErrorKind::Custom(128), tag!("mnop")) , ++/// || { res } ++/// ) ++/// ) ++/// ) ++/// )); ++/// let a = &b"efghblah"[..]; ++/// let b = &b"efghijklblah"[..]; ++/// let c = &b"efghijklmnop"[..]; ++/// ++/// let blah = &b"blah"[..]; ++/// ++/// let res_a = err_test(a); ++/// let res_b = err_test(b); ++/// let res_c = err_test(c); ++/// assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), blah, Box::new(Position(ErrorKind::Tag, blah))))); ++/// assert_eq!(res_b, Error(NodePosition(ErrorKind::Custom(42), &b"ijklblah"[..], ++/// Box::new(NodePosition(ErrorKind::Custom(128), blah, Box::new(Position(ErrorKind::Tag, blah)))))) ++/// ); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! error ( ++ ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let cl = || { ++ $submac!($i, $($args)*) ++ }; ++ ++ match cl() { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => { ++ return $crate::IResult::Error($crate::Err::NodePosition($code, $i, Box::new(e))) ++ } ++ } ++ } ++ ); ++ ($i:expr, $code:expr, $f:expr) => ( ++ error!($i, $code, call!($f)); ++ ); ++); ++ ++/// Add an error if the child parser fails ++/// ++/// While error! does an early return and avoids backtracking, ++/// add_error! backtracks normally. It just provides more context ++/// for an error ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use std::collections; ++/// # use nom::IResult::Error; ++/// # use nom::Err::{Position,NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(err_test, add_error!(ErrorKind::Custom(42), tag!("abcd"))); ++/// ++/// let a = &b"efghblah"[..]; ++/// let res_a = err_test(a); ++/// assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), a, Box::new(Position(ErrorKind::Tag, a))))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! add_error ( ++ ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => { ++ $crate::IResult::Error($crate::Err::NodePosition($code, $i, Box::new(e))) ++ } ++ } ++ } ++ ); ++ ($i:expr, $code:expr, $f:expr) => ( ++ add_error!($i, $code, call!($f)); ++ ); ++); ++ ++ ++/// translate parser result from IResult to IResult with a custom type ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use std::collections; ++/// # use nom::IResult::Error; ++/// # use nom::Err::{Position,NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// // will add a Custom(42) error to the error chain ++/// named!(err_test, add_error!(ErrorKind::Custom(42), tag!("abcd"))); ++/// // Convert to IREsult<&[u8], &[u8], &str> ++/// named!(parser<&[u8], &[u8], &str>, add_error!(ErrorKind::Custom("custom error message"), fix_error!(&str, err_test))); ++/// ++/// let a = &b"efghblah"[..]; ++/// let res_a = parser(a); ++/// assert_eq!(res_a, Error(NodePosition( ErrorKind::Custom("custom error message"), a, Box::new(Position(ErrorKind::Fix, a))))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fix_error ( ++ ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => { ++ let err = match e { ++ $crate::Err::Code($crate::ErrorKind::Custom(_)) | ++ $crate::Err::Node($crate::ErrorKind::Custom(_), _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Code(e) ++ }, ++ $crate::Err::Position($crate::ErrorKind::Custom(_), p) | ++ $crate::Err::NodePosition($crate::ErrorKind::Custom(_), p, _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Position(e, p) ++ }, ++ $crate::Err::Code(_) | ++ $crate::Err::Node(_, _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Code(e) ++ }, ++ $crate::Err::Position(_, p) | ++ $crate::Err::NodePosition(_, p, _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Position(e, p) ++ }, ++ }; ++ $crate::IResult::Error(err) ++ } ++ } ++ } ++ ); ++ ($i:expr, $t:ty, $f:expr) => ( ++ fix_error!($i, $t, call!($f)); ++ ); ++); ++ ++/// replaces a `Incomplete` returned by the child parser ++/// with an `Error` ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use std::collections; ++/// # use nom::IResult::Error; ++/// # use nom::Err::{Position,NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(take_5, complete!(take!(5))); ++/// ++/// let a = &b"abcd"[..]; ++/// let res_a = take_5(a); ++/// assert_eq!(res_a, Error(Position(ErrorKind::Complete, a))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! complete ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(_) => { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Complete, $i)) ++ }, ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ complete!($i, call!($f)); ++ ); ++); ++ ++/// A bit like `std::try!`, this macro will return the remaining input and parsed value if the child parser returned `Done`, ++/// and will do an early return for `Error` and `Incomplete` ++/// this can provide more flexibility than `chain!` if needed ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::{be_u8,ErrorKind}; ++/// ++/// fn take_add(input:&[u8], size: u8) -> IResult<&[u8],&[u8]> { ++/// let (i1, sz) = try_parse!(input, be_u8); ++/// let (i2, length) = try_parse!(i1, expr_opt!(size.checked_add(sz))); ++/// let (i3, data) = try_parse!(i2, take!(length)); ++/// return Done(i3, data); ++/// } ++/// # fn main() { ++/// let arr1 = [1, 2, 3, 4, 5]; ++/// let r1 = take_add(&arr1[..], 1); ++/// assert_eq!(r1, Done(&[4,5][..], &[2,3][..])); ++/// ++/// let arr2 = [0xFE, 2, 3, 4, 5]; ++/// // size is overflowing ++/// let r1 = take_add(&arr2[..], 42); ++/// assert_eq!(r1, Error(Position(ErrorKind::ExprOpt,&[2,3,4,5][..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! try_parse ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => (i,o), ++ $crate::IResult::Error(e) => return $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i) ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ try_parse!($i, call!($f)) ++ ); ++); ++ ++/// `flat_map!(R -> IResult, S -> IResult) => R -> IResult` ++/// ++/// combines a parser R -> IResult and ++/// a parser S -> IResult to return another ++/// parser R -> IResult ++#[macro_export] ++macro_rules! flat_map( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), ++ $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { ++ $crate::IResult::Error(e) => { ++ let err = match e { ++ $crate::Err::Code(k) | $crate::Err::Node(k, _) | $crate::Err::Position(k, _) | $crate::Err::NodePosition(k, _, _) => { ++ $crate::Err::Position(k, $i) ++ } ++ }; ++ $crate::IResult::Error(err) ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(ref i2)) => $crate::IResult::Incomplete($crate::Needed::Size(*i2)), ++ $crate::IResult::Done(_, o2) => $crate::IResult::Done(i, o2) ++ } ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ flat_map!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ flat_map!($i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ flat_map!($i, call!($f), $submac!($($args)*)); ++ ); ++); ++ ++/// `map!(I -> IResult, O -> P) => I -> IResult` ++/// maps a function on the result of a parser ++#[macro_export] ++macro_rules! map( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ map_impl!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ map_impl!($i, $submac!($($args)*), $submac2!($($args2)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ map_impl!($i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ map_impl!($i, call!($f), $submac!($($args)*)); ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! map_impl( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $submac2!(o, $($args2)*)) ++ } ++ } ++ ); ++); ++ ++/// `map_res!(I -> IResult, O -> Result

) => I -> IResult` ++/// maps a function returning a Result on the output of a parser ++#[macro_export] ++macro_rules! map_res ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ map_res_impl!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ map_res_impl!($i, $submac!($($args)*), $submac2!($($args2)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ map_res_impl!($i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ map_res_impl!($i, call!($f), $submac!($($args)*)); ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! map_res_impl ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), ++ $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { ++ Ok(output) => $crate::IResult::Done(i, output), ++ Err(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::MapRes, $i)) ++ } ++ } ++ } ++ ); ++); ++ ++ ++/// `map_opt!(I -> IResult, O -> Option

) => I -> IResult` ++/// maps a function returning an Option on the output of a parser ++#[macro_export] ++macro_rules! map_opt ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ map_opt_impl!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ map_opt_impl!($i, $submac!($($args)*), $submac2!($($args2)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ map_opt_impl!($i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ map_opt_impl!($i, call!($f), $submac!($($args)*)); ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! map_opt_impl ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), ++ $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { ++ ::std::option::Option::Some(output) => $crate::IResult::Done(i, output), ++ ::std::option::Option::None => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::MapOpt, $i)) ++ } ++ } ++ } ++ ); ++); ++ ++/// `value!(T, R -> IResult ) => R -> IResult` ++/// ++/// or `value!(T) => R -> IResult` ++/// ++/// If the child parser was successful, return the value. ++/// If no child parser is provided, always return the value ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(x, value!(42, delimited!(tag!("")))); ++/// named!(y, delimited!(tag!(""))); ++/// let r = x(&b" aaa"[..]); ++/// assert_eq!(r, Done(&b" aaa"[..], 42)); ++/// ++/// let r2 = y(&b" aaa"[..]); ++/// assert_eq!(r2, Done(&b" aaa"[..], 42)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! value ( ++ ($i:expr, $res:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,_) => { ++ $crate::IResult::Done(i, $res) ++ }, ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } ++ ); ++ ($i:expr, $res:expr, $f:expr) => ( ++ value!($i, $res, call!($f)) ++ ); ++ ($i:expr, $res:expr) => ( ++ $crate::IResult::Done($i, $res) ++ ); ++); ++ ++/// `expr_res!(Result) => I -> IResult` ++/// evaluate an expression that returns a Result and returns a IResult::Done(I,T) if Ok ++/// ++/// See expr_opt for an example ++#[macro_export] ++macro_rules! expr_res ( ++ ($i:expr, $e:expr) => ( ++ { ++ match $e { ++ Ok(output) => $crate::IResult::Done($i, output), ++ Err(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ExprRes, $i)) ++ } ++ } ++ ); ++); ++ ++/// `expr_opt!(Option) => I -> IResult` ++/// evaluate an expression that returns a Option and returns a IResult::Done(I,T) if Some ++/// ++/// Useful when doing computations in a chain ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::{be_u8,ErrorKind}; ++/// ++/// fn take_add(input:&[u8], size: u8) -> IResult<&[u8],&[u8]> { ++/// chain!(input, ++/// sz: be_u8 ~ ++/// length: expr_opt!(size.checked_add(sz)) ~ // checking for integer overflow (returns an Option) ++/// data: take!(length) , ++/// ||{ data } ++/// ) ++/// } ++/// # fn main() { ++/// let arr1 = [1, 2, 3, 4, 5]; ++/// let r1 = take_add(&arr1[..], 1); ++/// assert_eq!(r1, Done(&[4,5][..], &[2,3][..])); ++/// ++/// let arr2 = [0xFE, 2, 3, 4, 5]; ++/// // size is overflowing ++/// let r1 = take_add(&arr2[..], 42); ++/// assert_eq!(r1, Error(Position(ErrorKind::ExprOpt,&[2,3,4,5][..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! expr_opt ( ++ ($i:expr, $e:expr) => ( ++ { ++ match $e { ++ ::std::option::Option::Some(output) => $crate::IResult::Done($i, output), ++ ::std::option::Option::None => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ExprOpt, $i)) ++ } ++ } ++ ); ++); ++ ++/// `chain!(I->IResult ~ I->IResult ~ ... I->IResult , || { return O } ) => I -> IResult` ++/// chains parsers and assemble the results through a closure ++/// ++/// The input type `I` must implement `nom::InputLength`. ++/// ++/// This combinator will count how much data is consumed by every child parser and take it into account if ++/// there is not enough data ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// #[derive(PartialEq,Eq,Debug)] ++/// struct B { ++/// a: u8, ++/// b: Option ++/// } ++/// ++/// named!(y, tag!("efgh")); ++/// ++/// fn ret_int(i:&[u8]) -> IResult<&[u8], u8> { Done(i, 1) } ++/// named!(ret_y<&[u8], u8>, map!(y, |_| 1)); // return 1 if the "efgh" tag is found ++/// ++/// named!(z<&[u8], B>, ++/// chain!( ++/// tag!("abcd") ~ // the '~' character is used as separator ++/// aa: ret_int ~ // the result of that parser will be used in the closure ++/// tag!("abcd")? ~ // this parser is optional ++/// bb: ret_y? , // the result of that parser is an option ++/// // the last parser in the chain is followed by a ',' ++/// ||{B{a: aa, b: bb}} ++/// ) ++/// ); ++/// ++/// # fn main() { ++/// // the first "abcd" tag is not present, we have an error ++/// let r1 = z(&b"efgh"[..]); ++/// assert_eq!(r1, Error(Position(ErrorKind::Tag,&b"efgh"[..]))); ++/// ++/// // everything is present, everything is parsed ++/// let r2 = z(&b"abcdabcdefgh"[..]); ++/// assert_eq!(r2, Done(&b""[..], B{a: 1, b: Some(1)})); ++/// ++/// // the second "abcd" tag is optional ++/// let r3 = z(&b"abcdefgh"[..]); ++/// assert_eq!(r3, Done(&b""[..], B{a: 1, b: Some(1)})); ++/// ++/// // the result of ret_y is optional, as seen in the B structure ++/// let r4 = z(&b"abcdabcdwxyz"[..]); ++/// assert_eq!(r4, Done(&b"wxyz"[..], B{a: 1, b: None})); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! chain ( ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ chaining_parser!($i, 0usize, $($rest)*) ++ } ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! chaining_parser ( ++ ($i:expr, $consumed:expr, $e:ident ~ $($rest:tt)*) => ( ++ chaining_parser!($i, $consumed, call!($e) ~ $($rest)*); ++ ); ++ ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ~ $($rest:tt)*) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,_) => { ++ chaining_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), $($rest)*) ++ } ++ } ++ } ++); ++ ++ ($i:expr, $consumed:expr, $e:ident ? ~ $($rest:tt)*) => ( ++ chaining_parser!($i, $consumed, call!($e) ? ~ $($rest)*); ++ ); ++ ++ ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ? ~ $($rest:tt)*) => ( ++ { ++ let res = $submac!($i, $($args)*); ++ if let $crate::IResult::Incomplete(inc) = res { ++ match inc { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ } ++ } else { ++ let input = if let $crate::IResult::Done(i,_) = res { ++ i ++ } else { ++ $i ++ }; ++ chaining_parser!(input, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input)), $($rest)*) ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $e:ident ~ $($rest:tt)*) => ( ++ chaining_parser!($i, $consumed, $field: call!($e) ~ $($rest)*); ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ~ $($rest:tt)*) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ let $field = o; ++ chaining_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), $($rest)*) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $e:ident ~ $($rest:tt)*) => ( ++ chaining_parser!($i, $consumed, mut $field: call!($e) ~ $($rest)*); ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) ~ $($rest:tt)*) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ let mut $field = o; ++ chaining_parser!(i, $consumed + $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i), $($rest)*) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $e:ident ? ~ $($rest:tt)*) => ( ++ chaining_parser!($i, $consumed, $field : call!($e) ? ~ $($rest)*); ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ? ~ $($rest:tt)*) => ( ++ { ++ let res = $submac!($i, $($args)*); ++ if let $crate::IResult::Incomplete(inc) = res { ++ match inc { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ } ++ } else { ++ let ($field,input) = if let $crate::IResult::Done(i,o) = res { ++ (::std::option::Option::Some(o),i) ++ } else { ++ (::std::option::Option::None,$i) ++ }; ++ chaining_parser!(input, $consumed + $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input), $($rest)*) ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $e:ident ? ~ $($rest:tt)*) => ( ++ chaining_parser!($i, $consumed, mut $field : call!($e) ? ~ $($rest)*); ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) ? ~ $($rest:tt)*) => ( ++ { ++ let res = $submac!($i, $($args)*); ++ if let $crate::IResult::Incomplete(inc) = res { ++ match inc { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ } ++ } else { ++ let (mut $field,input) = if let $crate::IResult::Done(i,o) = res { ++ (::std::option::Option::Some(o),i) ++ } else { ++ (::std::option::Option::None,$i) ++ }; ++ chaining_parser!(input, $consumed + $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input), $($rest)*) ++ } ++ } ++ ); ++ ++ // ending the chain ++ ($i:expr, $consumed:expr, $e:ident, $assemble:expr) => ( ++ chaining_parser!($i, $consumed, call!($e), $assemble); ++ ); ++ ++ ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ), $assemble:expr) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,_) => { ++ $crate::IResult::Done(i, $assemble()) ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, $e:ident ?, $assemble:expr) => ( ++ chaining_parser!($i, $consumed, call!($e) ?, $assemble); ++ ); ++ ++ ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ?, $assemble:expr) => ({ ++ let res = $submac!($i, $($args)*); ++ if let $crate::IResult::Incomplete(inc) = res { ++ match inc { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ } ++ } else { ++ let input = if let $crate::IResult::Done(i,_) = res { ++ i ++ } else { ++ $i ++ }; ++ $crate::IResult::Done(input, $assemble()) ++ } ++ }); ++ ++ ($i:expr, $consumed:expr, $field:ident : $e:ident, $assemble:expr) => ( ++ chaining_parser!($i, $consumed, $field: call!($e), $assemble); ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ), $assemble:expr) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ let $field = o; ++ $crate::IResult::Done(i, $assemble()) ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $e:ident, $assemble:expr) => ( ++ chaining_parser!($i, $consumed, mut $field: call!($e), $assemble); ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ), $assemble:expr) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ let mut $field = o; ++ $crate::IResult::Done(i, $assemble()) ++ } ++ } ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $e:ident ? , $assemble:expr) => ( ++ chaining_parser!($i, $consumed, $field : call!($e) ? , $assemble); ++ ); ++ ++ ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ? , $assemble:expr) => ({ ++ let res = $submac!($i, $($args)*); ++ if let $crate::IResult::Incomplete(inc) = res { ++ match inc { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ } ++ } else { ++ let ($field,input) = if let $crate::IResult::Done(i,o) = res { ++ (::std::option::Option::Some(o), i) ++ } else { ++ (::std::option::Option::None, $i) ++ }; ++ $crate::IResult::Done(input, $assemble()) ++ } ++ }); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $e:ident ? , $assemble:expr) => ( ++ chaining_parser!($i, $consumed, $field : call!($e) ? , $assemble); ++ ); ++ ++ ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) ? , $assemble:expr) => ({ ++ let res = $submac!($i, $($args)*); ++ if let $crate::IResult::Incomplete(inc) = res { ++ match inc { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ } ++ } else { ++ let (mut $field,input) = if let $crate::IResult::Done(i,o) = res { ++ (::std::option::Option::Some(o), i) ++ } else { ++ (::std::option::Option::None, $i) ++ }; ++ $crate::IResult::Done(input, $assemble()) ++ } ++ }); ++ ++ ($i:expr, $consumed:expr, $assemble:expr) => ( ++ $crate::IResult::Done($i, $assemble()) ++ ) ++); ++ ++ ++/// `tuple!(I->IResult, I->IResult, ... I->IResult) => I -> IResult` ++/// chains parsers and assemble the sub results in a tuple. ++/// ++/// The input type `I` must implement `nom::InputLength`. ++/// ++/// This combinator will count how much data is consumed by every child parser and take it into account if ++/// there is not enough data ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # use nom::be_u16; ++/// // the return type depends of the children parsers ++/// named!(parser<&[u8], (u16, &[u8], &[u8]) >, ++/// tuple!( ++/// be_u16 , ++/// take!(3), ++/// tag!("fg") ++/// ) ++/// ); ++/// ++/// # fn main() { ++/// assert_eq!( ++/// parser(&b"abcdefgh"[..]), ++/// Done( ++/// &b"h"[..], ++/// (0x6162u16, &b"cde"[..], &b"fg"[..]) ++/// ) ++/// ); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! tuple ( ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ tuple_parser!($i, 0usize, (), $($rest)*) ++ } ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! tuple_parser ( ++ ($i:expr, $consumed:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => ( ++ tuple_parser!($i, $consumed, ($($parsed),*), call!($e), $($rest)*); ++ ); ++ ($i:expr, $consumed:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ tuple_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), (o), $($rest)*) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ tuple_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), ($($parsed)* , o), $($rest)*) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:tt),*), $e:ident) => ( ++ tuple_parser!($i, $consumed, ($($parsed),*), call!($e)); ++ ); ++ ($i:expr, $consumed:expr, (), $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ $crate::IResult::Done(i, (o)) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ $crate::IResult::Done(i, ($($parsed),* , o)) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:expr),*)) => ( ++ { ++ $crate::IResult::Done($i, ($($parsed),*)) ++ } ++ ); ++); ++/// `alt!(I -> IResult | I -> IResult | ... | I -> IResult ) => I -> IResult` ++/// try a list of parsers, return the result of the first successful one ++/// ++/// If one of the parser returns Incomplete, alt will return Incomplete, to retry ++/// once you get more input. Note that it is better for performance to know the ++/// minimum size of data you need before you get into alt. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!( test, alt!( tag!( "abcd" ) | tag!( "efgh" ) ) ); ++/// let r1 = test(b"abcdefgh"); ++/// assert_eq!(r1, Done(&b"efgh"[..], &b"abcd"[..])); ++/// let r2 = test(&b"efghijkl"[..]); ++/// assert_eq!(r2, Done(&b"ijkl"[..], &b"efgh"[..])); ++/// # } ++/// ``` ++/// ++/// There is another syntax for alt allowing a block to manipulate the result: ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// #[derive(Debug,PartialEq,Eq)] ++/// enum Tagged { ++/// Abcd, ++/// Efgh, ++/// Took(usize) ++/// } ++/// named!(test, alt!( ++/// tag!("abcd") => { |_| Tagged::Abcd } ++/// | tag!("efgh") => { |_| Tagged::Efgh } ++/// | take!(5) => { |res: &[u8]| Tagged::Took(res.len()) } // the closure takes the result as argument if the parser is successful ++/// )); ++/// let r1 = test(b"abcdefgh"); ++/// assert_eq!(r1, Done(&b"efgh"[..], Tagged::Abcd)); ++/// let r2 = test(&b"efghijkl"[..]); ++/// assert_eq!(r2, Done(&b"ijkl"[..], Tagged::Efgh)); ++/// let r3 = test(&b"mnopqrst"[..]); ++/// assert_eq!(r3, Done(&b"rst"[..], Tagged::Took(5))); ++/// # } ++/// ``` ++/// ++/// **BE CAREFUL** there is a case where the behaviour of `alt!` can be confusing: ++/// ++/// when the alternatives have different lengths, like this case: ++/// ++/// ```ignore ++/// named!( test, alt!( tag!( "abcd" ) | tag!( "ef" ) | tag!( "ghi" ) | tag!( "kl" ) ) ); ++/// ``` ++/// ++/// With this parser, if you pass `"abcd"` as input, the first alternative parses it correctly, ++/// but if you pass `"efg"`, the first alternative will return `Incomplete`, since it needs an input ++/// of 4 bytes. This behaviour of `alt!` is expected: if you get a partial input that isn't matched ++/// by the first alternative, but would match if the input was complete, you want `alt!` to indicate ++/// that it cannot decide with limited information. ++/// ++/// There are two ways to fix this behaviour. The first one consists in ordering the alternatives ++/// by size, like this: ++/// ++/// ```ignore ++/// named!( test, alt!( tag!( "ef" ) | tag!( "kl") | tag!( "ghi" ) | tag!( "abcd" ) ) ); ++/// ``` ++/// ++/// With this solution, the largest alternative will be tested last. ++/// ++/// The other solution uses the `complete!` combinator, which transforms an `Incomplete` in an ++/// `Error`. If one of the alternatives returns `Incomplete` but is wrapped by `complete!`, ++/// `alt!` will try the next alternative. This is useful when you know that ++/// you will not get partial input: ++/// ++/// ```ignore ++/// named!( test, ++/// alt!( ++/// complete!( tag!( "abcd" ) ) | ++/// complete!( tag!( "ef" ) ) | ++/// complete!( tag!( "ghi" ) ) | ++/// complete!( tag!( "kl" ) ) ++/// ) ++/// ); ++/// ``` ++/// ++/// If you want the `complete!` combinator to be applied to all rules then use the convenience ++/// `alt_complete!` macro (see below). ++/// ++/// This behaviour of `alt!` can get especially confusing if multiple alternatives have different ++/// sizes but a common prefix, like this: ++/// ++/// ```ignore ++/// named!( test, alt!( tag!( "abcd" ) | tag!( "ab" ) | tag!( "ef" ) ) ); ++/// ``` ++/// ++/// in that case, if you order by size, passing `"abcd"` as input will always be matched by the ++/// smallest parser, so the solution using `complete!` is better suited. ++/// ++/// You can also nest multiple `alt!`, like this: ++/// ++/// ```ignore ++/// named!( test, ++/// alt!( ++/// preceded!( ++/// tag!("ab"), ++/// alt!( ++/// tag!( "cd" ) | ++/// eof ++/// ) ++/// ) ++/// | tag!( "ef" ) ++/// ) ++/// ); ++/// ``` ++/// ++/// `preceded!` will first parse `"ab"` then, if successful, try the alternatives "cd", ++/// or empty input (End Of File). If none of them work, `preceded!` will fail and ++/// "ef" will be tested. ++/// ++#[macro_export] ++macro_rules! alt ( ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ alt_parser!($i, $($rest)*) ++ } ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! alt_parser ( ++ ($i:expr, $e:ident | $($rest:tt)*) => ( ++ alt_parser!($i, call!($e) | $($rest)*); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( ++ { ++ let res = $subrule!($i, $($args)*); ++ match res { ++ $crate::IResult::Done(_,_) => res, ++ $crate::IResult::Incomplete(_) => res, ++ _ => alt_parser!($i, $($rest)*) ++ } ++ } ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( ++ { ++ match $subrule!( $i, $($args)* ) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(_) => { ++ alt_parser!($i, $($rest)*) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => ( ++ alt_parser!($i, call!($e) => { $gen } | $($rest)*); ++ ); ++ ++ ($i:expr, $e:ident => { $gen:expr }) => ( ++ alt_parser!($i, call!($e) => { $gen }); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( ++ { ++ match $subrule!( $i, $($args)* ) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(_) => { ++ alt_parser!($i) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $e:ident) => ( ++ alt_parser!($i, call!($e)); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)*)) => ( ++ { ++ match $subrule!( $i, $($args)* ) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,o), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(_) => { ++ alt_parser!($i) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr) => ( ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Alt,$i)) ++ ); ++); ++ ++/// This is a combination of the `alt!` and `complete!` combinators. Rather ++/// than returning `Incomplete` on partial input, `alt_complete!` will try the ++/// next alternative in the chain. You should use this only if you know you ++/// will not receive partial input for the rules you're trying to match (this ++/// is almost always the case for parsing programming languages). ++#[macro_export] ++macro_rules! alt_complete ( ++ // Recursive rules (must include `complete!` around the head) ++ ++ ($i:expr, $e:ident | $($rest:tt)*) => ( ++ alt_complete!($i, complete!(call!($e)) | $($rest)*); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( ++ { ++ let res = complete!($i, $subrule!($($args)*)); ++ match res { ++ $crate::IResult::Done(_,_) => res, ++ _ => alt_complete!($i, $($rest)*), ++ } ++ } ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( ++ { ++ match complete!($i, $subrule!($($args)*)) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ _ => alt_complete!($i, $($rest)*), ++ } ++ } ++ ); ++ ++ ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => ( ++ alt_complete!($i, complete!(call!($e)) => { $gen } | $($rest)*); ++ ); ++ ++ // Tail (non-recursive) rules ++ ++ ($i:expr, $e:ident => { $gen:expr }) => ( ++ alt_complete!($i, call!($e) => { $gen }); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( ++ alt_parser!($i, $subrule!($($args)*) => { $gen }) ++ ); ++ ++ ($i:expr, $e:ident) => ( ++ alt_complete!($i, call!($e)); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)*)) => ( ++ alt_parser!($i, $subrule!($($args)*)) ++ ); ++); ++ ++/// `switch!(I -> IResult, P => I -> IResult | ... | P => I -> IResult ) => I -> IResult` ++/// choose the next parser depending on the result of the first one, if successful, ++/// and returns the result of the second parser ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # use nom::Err::{Position, NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => tag!("XYZ") | ++/// b"efgh" => tag!("123") ++/// ) ++/// ); ++/// ++/// let a = b"abcdXYZ123"; ++/// let b = b"abcdef"; ++/// let c = b"efgh123"; ++/// let d = b"blah"; ++/// ++/// assert_eq!(sw(&a[..]), Done(&b"123"[..], &b"XYZ"[..])); ++/// assert_eq!(sw(&b[..]), Error(NodePosition(ErrorKind::Switch, &b"abcdef"[..], Box::new(Position(ErrorKind::Tag, &b"ef"[..]))))); ++/// assert_eq!(sw(&c[..]), Done(&b""[..], &b"123"[..])); ++/// assert_eq!(sw(&d[..]), Error(Position(ErrorKind::Switch, &b"blah"[..]))); ++/// # } ++/// ``` ++/// ++/// Due to limitations in Rust macros, it is not possible to have simple functions on the right hand ++/// side of pattern, like this: ++/// ++/// ```ignore ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => tag!("XYZ") | ++/// b"efgh" => tag!("123") ++/// ) ++/// ); ++/// ``` ++/// ++/// If you want to pass your own functions instead, you can use the `call!` combinator as follows: ++/// ++/// ```ignore ++/// named!(xyz, tag!("XYZ")); ++/// named!(num, tag!("123")); ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => call!(xyz) | ++/// b"efgh" => call!(num) ++/// ) ++/// ); ++/// ``` ++/// ++#[macro_export] ++macro_rules! switch ( ++ ($i:expr, $submac:ident!( $($args:tt)*), $($rest:tt)*) => ( ++ { ++ switch_impl!($i, $submac!($($args)*), $($rest)*) ++ } ++ ); ++ ($i:expr, $e:ident, $($rest:tt)*) => ( ++ { ++ switch_impl!($i, call!($e), $($rest)*) ++ } ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! switch_impl ( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error($crate::Err::NodePosition( ++ $crate::ErrorKind::Switch, $i, ::std::boxed::Box::new(e) ++ )), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ match o { ++ $($p => match $subrule!(i, $($args2)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error($crate::Err::NodePosition( ++ $crate::ErrorKind::Switch, $i, ::std::boxed::Box::new(e) ++ )), ++ a => a, ++ }),*, ++ _ => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Switch,$i)) ++ } ++ } ++ } ++ } ++ ); ++); ++/// `opt!(I -> IResult) => I -> IResult>` ++/// make the underlying parser optional ++/// ++/// returns an Option of the returned type. This parser returns `Some(result)` if the child parser ++/// succeeds,`None` if it fails, and `Incomplete` if it did not have enough data to decide ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!( o<&[u8], Option<&[u8]> >, opt!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdef"; ++/// let b = b"bcdefg"; ++/// assert_eq!(o(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++/// assert_eq!(o(&b[..]), Done(&b"bcdefg"[..], None)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! opt( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), ++ $crate::IResult::Error(_) => $crate::IResult::Done($i, ::std::option::Option::None), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ opt!($i, call!($f)); ++ ); ++); ++ ++/// `opt_res!(I -> IResult) => I -> IResult>` ++/// make the underlying parser optional ++/// ++/// returns a Result, with Err containing the parsing error ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!( o<&[u8], Result<&[u8], nom::Err<&[u8]> > >, opt_res!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdef"; ++/// let b = b"bcdefg"; ++/// assert_eq!(o(&a[..]), Done(&b"ef"[..], Ok(&b"abcd"[..]))); ++/// assert_eq!(o(&b[..]), Done(&b"bcdefg"[..], Err(Position(ErrorKind::Tag, &b[..])))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! opt_res ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, Ok(o)), ++ $crate::IResult::Error(e) => $crate::IResult::Done($i, Err(e)), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ opt_res!($i, call!($f)); ++ ); ++); ++ ++/// `cond_with_error!(bool, I -> IResult) => I -> IResult>` ++/// Conditional combinator ++/// ++/// Wraps another parser and calls it if the ++/// condition is met. This combinator returns ++/// an Option of the return type of the child ++/// parser. ++/// ++/// This is especially useful if a parser depends ++/// on the value return by a preceding parser in ++/// a `chain!`. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::IResult; ++/// # fn main() { ++/// let b = true; ++/// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b, tag!("abcd") )) ++/// ); ++/// ++/// let a = b"abcdef"; ++/// assert_eq!(f(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++/// ++/// let b2 = false; ++/// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b2, tag!("abcd") )) ++/// ); ++/// assert_eq!(f2(&a[..]), Done(&b"abcdef"[..], None)); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! cond_with_error( ++ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ if $cond { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } else { ++ $crate::IResult::Done($i, ::std::option::Option::None) ++ } ++ } ++ ); ++ ($i:expr, $cond:expr, $f:expr) => ( ++ cond!($i, $cond, call!($f)); ++ ); ++); ++ ++/// `cond!(bool, I -> IResult) => I -> IResult>` ++/// Conditional combinator ++/// ++/// Wraps another parser and calls it if the ++/// condition is met. This combinator returns ++/// an Option of the return type of the child ++/// parser. ++/// ++/// This is especially useful if a parser depends ++/// on the value return by a preceding parser in ++/// a `chain!`. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::IResult; ++/// # fn main() { ++/// let b = true; ++/// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b, tag!("abcd") )) ++/// ); ++/// ++/// let a = b"abcdef"; ++/// assert_eq!(f(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++/// ++/// let b2 = false; ++/// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b2, tag!("abcd") )) ++/// ); ++/// assert_eq!(f2(&a[..]), Done(&b"abcdef"[..], None)); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! cond( ++ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ if $cond { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), ++ $crate::IResult::Error(_) => $crate::IResult::Done($i, ::std::option::Option::None), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } else { ++ $crate::IResult::Done($i, ::std::option::Option::None) ++ } ++ } ++ ); ++ ($i:expr, $cond:expr, $f:expr) => ( ++ cond!($i, $cond, call!($f)); ++ ); ++); ++ ++/// `cond_reduce!(bool, I -> IResult) => I -> IResult` ++/// Conditional combinator with error ++/// ++/// Wraps another parser and calls it if the ++/// condition is met. This combinator returns ++/// an error if the condition is false ++/// ++/// This is especially useful if a parser depends ++/// on the value return by a preceding parser in ++/// a `chain!`. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # use nom::{Err,ErrorKind}; ++/// # fn main() { ++/// let b = true; ++/// let f = closure!(&'static[u8], ++/// cond_reduce!( b, tag!("abcd") ) ++/// ); ++/// ++/// let a = b"abcdef"; ++/// assert_eq!(f(&a[..]), Done(&b"ef"[..], &b"abcd"[..])); ++/// ++/// let b2 = false; ++/// let f2 = closure!(&'static[u8], ++/// cond_reduce!( b2, tag!("abcd") ) ++/// ); ++/// assert_eq!(f2(&a[..]), Error(Err::Position(ErrorKind::CondReduce, &a[..]))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! cond_reduce( ++ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ if $cond { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::CondReduce, $i)) ++ } ++ } ++ ); ++ ($i:expr, $cond:expr, $f:expr) => ( ++ cond_reduce!($i, $cond, call!($f)); ++ ); ++); ++ ++/// `peek!(I -> IResult) => I -> IResult` ++/// returns a result without consuming the input ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(ptag, peek!( tag!( "abcd" ) ) ); ++/// ++/// let r = ptag(&b"abcdefgh"[..]); ++/// assert_eq!(r, Done(&b"abcdefgh"[..], &b"abcd"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! peek( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(_,o) => $crate::IResult::Done($i, o), ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ peek!($i, call!($f)); ++ ); ++); ++ ++/// `not!(I -> IResult) => I -> IResult` ++/// returns a result only if the embedded parser returns Error or Incomplete ++/// does not consume the input ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # use nom::Err::{Position}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(not_e, chain!( ++/// res: tag!("abc") ~ ++/// not!(char!('e')), ++/// || { res })); ++/// ++/// let r = not_e(&b"abcd"[..]); ++/// assert_eq!(r, Done(&b"d"[..], &b"abc"[..])); ++/// ++/// let r2 = not_e(&b"abce"[..]); ++/// assert_eq!(r2, Error(Position(ErrorKind::Not, &b"e"[..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! not( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(_, _) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Not, $i)), ++ $crate::IResult::Error(_) => $crate::IResult::Done($i, &($i)[..0]), ++ $crate::IResult::Incomplete(_) => $crate::IResult::Done($i, &($i)[..0]) ++ } ++ } ++ ); ++); ++ ++/// `tap!(name: I -> IResult => { block }) => I -> IResult` ++/// allows access to the parser's result without affecting it ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use std::str; ++/// # fn main() { ++/// named!(ptag, tap!(res: tag!( "abcd" ) => { println!("recognized {}", str::from_utf8(res).unwrap()) } ) ); ++/// ++/// let r = ptag(&b"abcdefgh"[..]); ++/// assert_eq!(r, Done(&b"efgh"[..], &b"abcd"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! tap ( ++ ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ let $name = o; ++ $e; ++ $crate::IResult::Done(i, $name) ++ }, ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) ++ } ++ } ++ ); ++ ($i:expr, $name: ident: $f:expr => $e:expr) => ( ++ tap!($i, $name: call!($f) => $e); ++ ); ++); ++ ++/// `pair!(I -> IResult, I -> IResult) => I -> IResult` ++/// pair(X,Y), returns (x,y) ++/// ++#[macro_export] ++macro_rules! pair( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ pair!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ pair!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ pair!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `separated_pair!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` ++/// separated_pair(X,sep,Y) returns (x,y) ++#[macro_export] ++macro_rules! separated_pair( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( ++ { ++ match tuple_parser!($i, 0usize, (), $submac!($($args)*), $($rest)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1, (o1, _, o2)) => { ++ $crate::IResult::Done(i1, (o1, o2)) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $f:expr, $($rest:tt)+) => ( ++ separated_pair!($i, call!($f), $($rest)*); ++ ); ++); ++ ++/// `preceded!(I -> IResult, I -> IResult) => I -> IResult` ++/// preceded(opening, X) returns X ++#[macro_export] ++macro_rules! preceded( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (_,o)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ preceded!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ preceded!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ preceded!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `terminated!(I -> IResult, I -> IResult) => I -> IResult` ++/// terminated(X, closing) returns X ++#[macro_export] ++macro_rules! terminated( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (o,_)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ terminated!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ terminated!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ terminated!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `delimited!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` ++/// delimited(opening, X, closing) returns X ++#[macro_export] ++macro_rules! delimited( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( ++ { ++ match tuple_parser!($i, 0usize, (), $submac!($($args)*), $($rest)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1, (_, o, _)) => { ++ $crate::IResult::Done(i1, o) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $f:expr, $($rest:tt)+) => ( ++ delimited!($i, call!($f), $($rest)*); ++ ); ++); ++ ++/// `separated_list!(I -> IResult, I -> IResult) => I -> IResult>` ++/// separated_list(sep, X) returns Vec ++#[macro_export] ++macro_rules! separated_list( ++ ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( ++ { ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i; ++ ++ // get the first element ++ match $submac!(input, $($args2)*) { ++ $crate::IResult::Error(_) => $crate::IResult::Done(input, ::std::vec::Vec::new()), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i,o) => { ++ if i.len() == input.len() { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::SeparatedList,input)) ++ } else { ++ res.push(o); ++ input = i; ++ ++ loop { ++ // get the separator first ++ if let $crate::IResult::Done(i2,_) = $sep!(input, $($args)*) { ++ if i2.len() == input.len() { ++ break; ++ } ++ ++ // get the element next ++ if let $crate::IResult::Done(i3,o3) = $submac!(i2, $($args2)*) { ++ if i3.len() == i2.len() { ++ break; ++ } ++ res.push(o3); ++ input = i3; ++ } else { ++ break; ++ } ++ } else { ++ break; ++ } ++ } ++ $crate::IResult::Done(input, res) ++ } ++ }, ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_list!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_list!($i, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ separated_list!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `separated_nonempty_list!(I -> IResult, I -> IResult) => I -> IResult>` ++/// separated_nonempty_list(sep, X) returns Vec ++#[macro_export] ++macro_rules! separated_nonempty_list( ++ ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( ++ { ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i; ++ ++ // get the first element ++ match $submac!(input, $($args2)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i,o) => { ++ if i.len() == input.len() { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::SeparatedNonEmptyList,input)) ++ } else { ++ res.push(o); ++ input = i; ++ ++ loop { ++ if let $crate::IResult::Done(i2,_) = $sep!(input, $($args)*) { ++ if i2.len() == input.len() { ++ break; ++ } ++ ++ if let $crate::IResult::Done(i3,o3) = $submac!(i2, $($args2)*) { ++ if i3.len() == i2.len() { ++ break; ++ } ++ res.push(o3); ++ input = i3; ++ } else { ++ break; ++ } ++ } else { ++ break; ++ } ++ } ++ $crate::IResult::Done(input, res) ++ } ++ }, ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_nonempty_list!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_nonempty_list!($i, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ separated_nonempty_list!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `many0!(I -> IResult) => I -> IResult>` ++/// Applies the parser 0 or more times and returns the list of results in a Vec ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, many0!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Done(&b"azerty"[..], Vec::new())); ++/// # } ++/// ``` ++/// 0 or more ++#[macro_export] ++macro_rules! many0( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ ++ let ret; ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i; ++ ++ loop { ++ if input.input_len() == 0 { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let size = i + ($i).input_len() - input.input_len(); ++ ret = $crate::IResult::Incomplete($crate::Needed::Size(size)); break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ // loop trip must always consume (otherwise infinite loops) ++ if i == input { ++ ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many0,input)); break; ++ } ++ ++ res.push(o); ++ input = i; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ many0!($i, call!($f)); ++ ); ++); ++ ++/// `many1!(I -> IResult) => I -> IResult>` ++/// Applies the parser 1 or more times and returns the list of results in a Vec ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, many1!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Error(Position(ErrorKind::Many1,&b[..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! many1( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many1,$i)), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1,o1) => { ++ if i1.input_len() == 0 { ++ $crate::IResult::Done(i1,vec![o1]) ++ } else { ++ ++ let mut res = ::std::vec::Vec::with_capacity(4); ++ res.push(o1); ++ let mut input = i1; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; ++ loop { ++ if input.input_len() == 0 { ++ break; ++ } ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(_) => { ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ res.push(o); ++ input = i; ++ } ++ } ++ } ++ ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, res) ++ } ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ many1!($i, call!($f)); ++ ); ++); ++ ++/// `many_m_n!(usize, usize, I -> IResult) => I -> IResult>` ++/// Applies the parser between m and n times (n included) and returns the list of results in a Vec ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdefgh"; ++/// let b = b"abcdabcdefgh"; ++/// let c = b"abcdabcdabcdabcdabcdefgh"; ++/// ++/// assert_eq!(multi(&a[..]),Error(Position(ErrorKind::ManyMN,&a[..]))); ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&b[..]), Done(&b"efgh"[..], res)); ++/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&c[..]), Done(&b"abcdefgh"[..], res2)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! many_m_n( ++ ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ let mut res = ::std::vec::Vec::with_capacity($m); ++ let mut input = $i; ++ let mut count: usize = 0; ++ let mut err = false; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; ++ loop { ++ if count == $n { break } ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Done(i, o) => { ++ // do not allow parsers that do not consume input (causes infinite loops) ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ res.push(o); ++ input = i; ++ count += 1; ++ } ++ $crate::IResult::Error(_) => { ++ err = true; ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); ++ break; ++ }, ++ } ++ if input.input_len() == 0 { ++ break; ++ } ++ } ++ ++ if count < $m { ++ if err { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ManyMN,$i)) ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Incomplete($crate::Needed::Unknown) ++ } ++ } ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, res) ++ } ++ } ++ } ++ ); ++ ($i:expr, $m:expr, $n: expr, $f:expr) => ( ++ many_m_n!($i, $m, $n, call!($f)); ++ ); ++); ++ ++/// `count!(I -> IResult, nb) => I -> IResult>` ++/// Applies the child parser a specified number of times ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(counter< Vec<&[u8]> >, count!( tag!( "abcd" ), 2 ) ); ++/// ++/// let a = b"abcdabcdabcdef"; ++/// let b = b"abcdefgh"; ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// ++/// assert_eq!(counter(&a[..]), Done(&b"abcdef"[..], res)); ++/// assert_eq!(counter(&b[..]), Error(Position(ErrorKind::Count, &b[..]))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! count( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $count: expr) => ( ++ { ++ let ret; ++ let mut input = $i; ++ let mut res = ::std::vec::Vec::with_capacity($count); ++ ++ loop { ++ if res.len() == $count { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ res.push(o); ++ input = i; ++ }, ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Count,$i)); break; ++ }, ++ $crate::IResult::Incomplete(_) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr, $count: expr) => ( ++ count!($i, call!($f), $count); ++ ); ++); ++ ++/// `count_fixed!(O, I -> IResult, nb) => I -> IResult` ++/// Applies the child parser a fixed number of times and returns a fixed size array ++/// The type must be specified and it must be `Copy` ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(counter< [&[u8]; 2] >, count_fixed!( &[u8], tag!( "abcd" ), 2 ) ); ++/// // can omit the type specifier if returning slices ++/// // named!(counter< [&[u8]; 2] >, count_fixed!( tag!( "abcd" ), 2 ) ); ++/// ++/// let a = b"abcdabcdabcdef"; ++/// let b = b"abcdefgh"; ++/// let res = [&b"abcd"[..], &b"abcd"[..]]; ++/// ++/// assert_eq!(counter(&a[..]), Done(&b"abcdef"[..], res)); ++/// assert_eq!(counter(&b[..]), Error(Position(ErrorKind::Count, &b[..]))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! count_fixed ( ++ ($i:expr, $typ:ty, $submac:ident!( $($args:tt)* ), $count: expr) => ( ++ { ++ let ret; ++ let mut input = $i; ++ // `$typ` must be Copy, and thus having no destructor, this is panic safe ++ let mut res: [$typ; $count] = unsafe{[::std::mem::uninitialized(); $count as usize]}; ++ let mut cnt: usize = 0; ++ ++ loop { ++ if cnt == $count { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ res[cnt] = o; ++ cnt += 1; ++ input = i; ++ }, ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Count,$i)); break; ++ }, ++ $crate::IResult::Incomplete(_) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $typ: ty, $f:ident, $count: expr) => ( ++ count_fixed!($i, $typ, call!($f), $count); ++ ); ++); ++ ++/// `length_value!(I -> IResult, I -> IResult) => I -> IResult>` ++/// gets a number from the first parser, then applies the second parser that many times ++#[macro_export] ++macro_rules! length_value( ++ ($i:expr, $f:expr, $g:expr) => ( ++ { ++ match $f($i) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(inum, onum) => { ++ let ret; ++ let length_token = $i.len() - inum.len(); ++ let mut input = inum; ++ let mut res = ::std::vec::Vec::new(); ++ ++ loop { ++ if res.len() == onum as usize { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $g(input) { ++ $crate::IResult::Done(iparse, oparse) => { ++ res.push(oparse); ++ input = iparse; ++ }, ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::LengthValue,$i)); break; ++ }, ++ $crate::IResult::Incomplete(a) => { ++ ret = match a { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(length) => $crate::IResult::Incomplete($crate::Needed::Size(length_token + onum as usize * length)) ++ }; ++ break; ++ } ++ } ++ } ++ ++ ret ++ } ++ } ++ } ++ ); ++ ($i:expr, $f:expr, $g:expr, $length:expr) => ( ++ { ++ match $f($i) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(inum, onum) => { ++ let ret; ++ let length_token = $i.len() - inum.len(); ++ let mut input = inum; ++ let mut res = ::std::vec::Vec::new(); ++ ++ loop { ++ if res.len() == onum as usize { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $g(input) { ++ $crate::IResult::Done(iparse, oparse) => { ++ res.push(oparse); ++ input = iparse; ++ }, ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::LengthValue,$i)); break; ++ }, ++ $crate::IResult::Incomplete(a) => { ++ ret = match a { ++ $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::Needed::Size(_) => $crate::IResult::Incomplete($crate::Needed::Size(length_token + onum as usize * $length)) ++ }; ++ break; ++ } ++ } ++ } ++ ++ ret ++ } ++ } ++ } ++ ); ++); ++ ++/// `fold_many0!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` ++/// Applies the parser 0 or more times and folds the list of return values ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, fold_many0!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { ++/// acc.push(item); ++/// acc ++/// })); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Done(&b"azerty"[..], Vec::new())); ++/// # } ++/// ``` ++/// 0 or more ++#[macro_export] ++macro_rules! fold_many0( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++ { ++ use $crate::InputLength; ++ let ret; ++ let f = $f; ++ let mut res = $init; ++ let mut input = $i; ++ ++ loop { ++ if input.input_len() == 0 { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let size = i + ($i).input_len() - input.input_len(); ++ ret = $crate::IResult::Incomplete($crate::Needed::Size(size)); break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ // loop trip must always consume (otherwise infinite loops) ++ if i == input { ++ ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many0,input)); break; ++ } ++ ++ res = f(res, o); ++ input = i; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( ++ fold_many0!($i, call!($f), $init, $fold_f); ++ ); ++); ++ ++/// `fold_many1!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` ++/// Applies the parser 1 or more times and folds the list of return values ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, fold_many1!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { ++/// acc.push(item); ++/// acc ++/// })); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Error(Position(ErrorKind::Many1,&b[..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fold_many1( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++ { ++ use $crate::InputLength; ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many1,$i)), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1,o1) => { ++ let acc = $init; ++ let f = $f; ++ if i1.len() == 0 { ++ let acc = f(acc, o1); ++ $crate::IResult::Done(i1,acc) ++ } else { ++ let mut acc = f(acc, o1); ++ let mut input = i1; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; ++ loop { ++ if input.input_len() == 0 { ++ break; ++ } ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(_) => { ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ acc = f(acc, o); ++ input = i; ++ } ++ } ++ } ++ ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, acc) ++ } ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( ++ fold_many1!($i, call!($f), $init, $fold_f); ++ ); ++); ++ ++/// `fold_many_m_n!(usize, usize, I -> IResult, R, Fn(R, O) -> R) => I -> IResult` ++/// Applies the parser between m and n times (n included) and folds the list of return value ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, fold_many_m_n!(2, 4, tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { ++/// acc.push(item); ++/// acc ++/// })); ++/// ++/// let a = b"abcdefgh"; ++/// let b = b"abcdabcdefgh"; ++/// let c = b"abcdabcdabcdabcdabcdefgh"; ++/// ++/// assert_eq!(multi(&a[..]),Error(Position(ErrorKind::ManyMN,&a[..]))); ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&b[..]), Done(&b"efgh"[..], res)); ++/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&c[..]), Done(&b"abcdefgh"[..], res2)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fold_many_m_n( ++ ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++ { ++ use $crate::InputLength; ++ let mut acc = $init; ++ let f = $f; ++ let mut input = $i; ++ let mut count: usize = 0; ++ let mut err = false; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; ++ loop { ++ if count == $n { break } ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Done(i, o) => { ++ // do not allow parsers that do not consume input (causes infinite loops) ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ acc = f(acc, o); ++ input = i; ++ count += 1; ++ } ++ $crate::IResult::Error(_) => { ++ err = true; ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); ++ break; ++ }, ++ } ++ if input.input_len() == 0 { ++ break; ++ } ++ } ++ ++ if count < $m { ++ if err { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ManyMN,$i)) ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Incomplete($crate::Needed::Unknown) ++ } ++ } ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, acc) ++ } ++ } ++ } ++ ); ++ ($i:expr, $m:expr, $n: expr, $f:expr, $init:expr, $fold_f:expr) => ( ++ fold_many_m_n!($i, $m, $n, call!($f), $init, $fold_f); ++ ); ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::{Needed,IResult,Err}; ++ use internal::IResult::*; ++ use internal::Err::*; ++ use util::ErrorKind; ++ ++ // reproduce the tag and take macros, because of module import order ++ macro_rules! tag ( ++ ($i:expr, $inp: expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ ++ tag_bytes!($i,bytes) ++ } ++ ); ++ ); ++ ++ macro_rules! tag_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ use std::cmp::min; ++ let len = $i.len(); ++ let blen = $bytes.len(); ++ let m = min(len, blen); ++ let reduced = &$i[..m]; ++ let b = &$bytes[..m]; ++ ++ let res: $crate::IResult<_,_> = if reduced != b { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Tag, $i)) ++ } else if m < blen { ++ $crate::IResult::Incomplete($crate::Needed::Size(blen)) ++ } else { ++ $crate::IResult::Done(&$i[blen..], reduced) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ macro_rules! take( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res:$crate::IResult<&[u8],&[u8]> = if $i.len() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ $crate::IResult::Done(&$i[cnt..],&$i[0..cnt]) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ ++ mod pub_named_mod { ++ named!(pub tst, tag!("abcd")); ++ } ++ ++ #[test] ++ fn pub_named_test() { ++ let a = &b"abcd"[..]; ++ let res = pub_named_mod::tst(a); ++ assert_eq!(res, Done(&b""[..], a)); ++ } ++ ++ #[test] ++ fn apply_test() { ++ fn sum2(a:u8, b:u8) -> u8 { a + b } ++ fn sum3(a:u8, b:u8, c:u8) -> u8 { a + b + c } ++ let a = apply!(1, sum2, 2); ++ let b = apply!(1, sum3, 2, 3); ++ ++ assert_eq!(a, 3); ++ assert_eq!(b, 6); ++ } ++ ++ #[derive(PartialEq,Eq,Debug)] ++ struct B { ++ a: u8, ++ b: u8 ++ } ++ ++ #[test] ++ fn chain2() { ++ fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; ++ fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Done(i,2) }; ++ ++ named!(chain_parser<&[u8],B>, ++ chain!( ++ tag!("abcd") ~ ++ tag!("abcd")? ~ ++ aa: ret_int1 ~ ++ tag!("efgh") ~ ++ bb: ret_int2 ~ ++ tag!("efgh") , ++ ||{B{a: aa, b: bb}} ++ ) ++ ); ++ ++ assert_eq!(chain_parser(&b"abcdabcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); ++ assert_eq!(chain_parser(&b"abcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); ++ assert_eq!(chain_parser(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(chain_parser(&b"abcdefghef"[..]), Incomplete(Needed::Size(12))); ++ } ++ ++ #[test] ++ fn nested_chain() { ++ fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; ++ fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Done(i,2) }; ++ ++ named!(chain_parser<&[u8],B>, ++ chain!( ++ chain!( ++ tag!("abcd") ~ ++ tag!("abcd")? , ++ || {} ++ ) ~ ++ aa: ret_int1 ~ ++ tag!("efgh") ~ ++ bb: ret_int2 ~ ++ tag!("efgh") , ++ ||{B{a: aa, b: bb}} ++ ) ++ ); ++ ++ assert_eq!(chain_parser(&b"abcdabcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); ++ assert_eq!(chain_parser(&b"abcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); ++ assert_eq!(chain_parser(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(chain_parser(&b"abcdefghef"[..]), Incomplete(Needed::Size(12))); ++ } ++ ++ #[derive(PartialEq,Eq,Debug)] ++ struct C { ++ a: u8, ++ b: Option ++ } ++ ++ #[test] ++ fn chain_mut() { ++ fn ret_b1_2(i:&[u8]) -> IResult<&[u8], B> { Done(i,B{a:1,b:2}) }; ++ named!(f<&[u8],B>, ++ chain!( ++ tag!("abcd") ~ ++ tag!("abcd")? ~ ++ tag!("efgh") ~ ++ mut bb: ret_b1_2 ~ ++ tag!("efgh") , ++ ||{ ++ bb.b = 3; ++ bb ++ } ++ ) ++ ); ++ ++ let r = f(&b"abcdabcdefghefghX"[..]); ++ assert_eq!(r, Done(&b"X"[..], B{a: 1, b: 3})); ++ } ++ ++ #[test] ++ fn chain_opt() { ++ named!(y, tag!("efgh")); ++ fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; ++ named!(ret_y<&[u8], u8>, map!(y, |_| 2)); ++ ++ named!(chain_parser<&[u8],C>, ++ chain!( ++ tag!("abcd") ~ ++ aa: ret_int1 ~ ++ bb: ret_y? , ++ ||{C{a: aa, b: bb}} ++ ) ++ ); ++ ++ assert_eq!(chain_parser(&b"abcdefghX"[..]), Done(&b"X"[..], C{a: 1, b: Some(2)})); ++ assert_eq!(chain_parser(&b"abcdWXYZ"[..]), Done(&b"WXYZ"[..], C{a: 1, b: None})); ++ assert_eq!(chain_parser(&b"abcdX"[..]), Done(&b"X"[..], C{ a: 1, b: None })); ++ assert_eq!(chain_parser(&b"abcdef"[..]), Incomplete(Needed::Size(8))); ++ } ++ ++ use util::{error_to_list, add_error_pattern, print_error}; ++ ++ fn error_to_string

(e: &Err

) -> &'static str { ++ let v:Vec = error_to_list(e); ++ // do it this way if you can use slice patterns ++ /* ++ match &v[..] { ++ [ErrorKind::Custom(42), ErrorKind::Tag] => "missing `ijkl` tag", ++ [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] => "missing `mnop` tag after `ijkl`", ++ _ => "unrecognized error" ++ } ++ */ ++ if &v[..] == [ErrorKind::Custom(42),ErrorKind::Tag] { ++ "missing `ijkl` tag" ++ } else if &v[..] == [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] { ++ "missing `mnop` tag after `ijkl`" ++ } else { ++ "unrecognized error" ++ } ++ } ++ ++ // do it this way if you can use box patterns ++ /*use std::str; ++ fn error_to_string(e:Err) -> String ++ match e { ++ NodePosition(ErrorKind::Custom(42), i1, box Position(ErrorKind::Tag, i2)) => { ++ format!("missing `ijkl` tag, found '{}' instead", str::from_utf8(i2).unwrap()) ++ }, ++ NodePosition(ErrorKind::Custom(42), i1, box NodePosition(ErrorKind::Custom(128), i2, box Position(ErrorKind::Tag, i3))) => { ++ format!("missing `mnop` tag after `ijkl`, found '{}' instead", str::from_utf8(i3).unwrap()) ++ }, ++ _ => "unrecognized error".to_string() ++ } ++ }*/ ++ use std::collections; ++ #[test] ++ fn err() { ++ named!(err_test, alt!( ++ tag!("abcd") | ++ preceded!(tag!("efgh"), error!(ErrorKind::Custom(42), ++ chain!( ++ tag!("ijkl") ~ ++ res: error!(ErrorKind::Custom(128), tag!("mnop")) , ++ || { res } ++ ) ++ ) ++ ) ++ )); ++ let a = &b"efghblah"[..]; ++ let b = &b"efghijklblah"[..]; ++ let c = &b"efghijklmnop"[..]; ++ ++ let blah = &b"blah"[..]; ++ ++ let res_a = err_test(a); ++ let res_b = err_test(b); ++ let res_c = err_test(c); ++ assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), blah, Box::new(Position(ErrorKind::Tag, blah))))); ++ assert_eq!(res_b, Error(NodePosition(ErrorKind::Custom(42), &b"ijklblah"[..], Box::new(NodePosition(ErrorKind::Custom(128), blah, Box::new(Position(ErrorKind::Tag, blah))))))); ++ assert_eq!(res_c, Done(&b""[..], &b"mnop"[..])); ++ ++ // Merr-like error matching ++ let mut err_map = collections::HashMap::new(); ++ assert!(add_error_pattern(&mut err_map, err_test(&b"efghpouet"[..]), "missing `ijkl` tag")); ++ assert!(add_error_pattern(&mut err_map, err_test(&b"efghijklpouet"[..]), "missing `mnop` tag after `ijkl`")); ++ ++ let res_a2 = res_a.clone(); ++ match res_a { ++ Error(e) => { ++ assert_eq!(error_to_list(&e), [ErrorKind::Custom(42), ErrorKind::Tag]); ++ assert_eq!(error_to_string(&e), "missing `ijkl` tag"); ++ assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `ijkl` tag")); ++ }, ++ _ => panic!() ++ }; ++ ++ let res_b2 = res_b.clone(); ++ match res_b { ++ Error(e) => { ++ assert_eq!(error_to_list(&e), [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag]); ++ assert_eq!(error_to_string(&e), "missing `mnop` tag after `ijkl`"); ++ assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `mnop` tag after `ijkl`")); ++ }, ++ _ => panic!() ++ }; ++ ++ print_error(a, res_a2); ++ print_error(b, res_b2); ++ } ++ ++ #[test] ++ fn add_err() { ++ named!(err_test, ++ preceded!(tag!("efgh"), add_error!(ErrorKind::Custom(42), ++ chain!( ++ tag!("ijkl") ~ ++ res: add_error!(ErrorKind::Custom(128), tag!("mnop")) , ++ || { res } ++ ) ++ ) ++ )); ++ let a = &b"efghblah"[..]; ++ let b = &b"efghijklblah"[..]; ++ let c = &b"efghijklmnop"[..]; ++ ++ let blah = &b"blah"[..]; ++ ++ let res_a = err_test(a); ++ let res_b = err_test(b); ++ let res_c = err_test(c); ++ assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), blah, Box::new(Position(ErrorKind::Tag, blah))))); ++ assert_eq!(res_b, Error(NodePosition(ErrorKind::Custom(42), &b"ijklblah"[..], Box::new(NodePosition(ErrorKind::Custom(128), blah, Box::new(Position(ErrorKind::Tag, blah))))))); ++ assert_eq!(res_c, Done(&b""[..], &b"mnop"[..])); ++ } ++ ++ #[test] ++ fn complete() { ++ named!(err_test, ++ chain!( ++ tag!("ijkl") ~ ++ res: complete!(tag!("mnop")) , ++ || { res } ++ ) ++ ); ++ let a = &b"ijklmn"[..]; ++ ++ let res_a = err_test(a); ++ assert_eq!(res_a, Error(Position(ErrorKind::Complete, &b"mn"[..]))); ++ } ++ #[test] ++ fn alt() { ++ fn work(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ Done(&b""[..], input) ++ } ++ ++ #[allow(unused_variables)] ++ fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8],&'static str> { ++ Error(Code(ErrorKind::Custom("abcd"))) ++ } ++ ++ fn work2(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ Done(input, &b""[..]) ++ } ++ ++ fn alt1(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | dont_work) ++ } ++ fn alt2(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | work) ++ } ++ fn alt3(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | dont_work | work2 | dont_work) ++ } ++ //named!(alt1, alt!(dont_work | dont_work)); ++ //named!(alt2, alt!(dont_work | work)); ++ //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work)); ++ ++ let a = &b"abcd"[..]; ++ assert_eq!(alt1(a), Error(Position(ErrorKind::Alt, a))); ++ assert_eq!(alt2(a), Done(&b""[..], a)); ++ assert_eq!(alt3(a), Done(a, &b""[..])); ++ ++ named!(alt4, alt!(tag!("abcd") | tag!("efgh"))); ++ let b = &b"efgh"[..]; ++ assert_eq!(alt4(a), Done(&b""[..], a)); ++ assert_eq!(alt4(b), Done(&b""[..], b)); ++ ++ // test the alternative syntax ++ named!(alt5, alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true })); ++ assert_eq!(alt5(a), Done(&b""[..], false)); ++ assert_eq!(alt5(b), Done(&b""[..], true)); ++ ++ } ++ ++ #[test] ++ fn alt_incomplete() { ++ named!(alt1, alt!(tag!("a") | tag!("bc") | tag!("def"))); ++ ++ let a = &b""[..]; ++ assert_eq!(alt1(a), Incomplete(Needed::Size(1))); ++ let a = &b"b"[..]; ++ assert_eq!(alt1(a), Incomplete(Needed::Size(2))); ++ let a = &b"bcd"[..]; ++ assert_eq!(alt1(a), Done(&b"d"[..], &b"bc"[..])); ++ let a = &b"cde"[..]; ++ assert_eq!(alt1(a), Error(Position(ErrorKind::Alt, a))); ++ let a = &b"de"[..]; ++ assert_eq!(alt1(a), Incomplete(Needed::Size(3))); ++ let a = &b"defg"[..]; ++ assert_eq!(alt1(a), Done(&b"g"[..], &b"def"[..])); ++ } ++ ++ #[test] ++ fn alt_complete() { ++ named!(ac<&[u8], &[u8]>, ++ alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl")) ++ ); ++ ++ let a = &b""[..]; ++ assert_eq!(ac(a), Incomplete(Needed::Size(2))); ++ let a = &b"ef"[..]; ++ assert_eq!(ac(a), Done(&b""[..], &b"ef"[..])); ++ let a = &b"cde"[..]; ++ assert_eq!(ac(a), Error(Position(ErrorKind::Alt, a))); ++ } ++ ++ #[test] ++ fn switch() { ++ named!(sw, ++ switch!(take!(4), ++ b"abcd" => take!(2) | ++ b"efgh" => take!(4) ++ ) ++ ); ++ ++ let a = &b"abcdefgh"[..]; ++ assert_eq!(sw(a), Done(&b"gh"[..], &b"ef"[..])); ++ ++ let b = &b"efghijkl"[..]; ++ assert_eq!(sw(b), Done(&b""[..], &b"ijkl"[..])); ++ let c = &b"afghijkl"[..]; ++ assert_eq!(sw(c), Error(Position(ErrorKind::Switch, &b"afghijkl"[..]))); ++ } ++ ++ #[test] ++ fn opt() { ++ named!(opt_abcd<&[u8],Option<&[u8]> >, opt!(tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"bcdefg"[..]; ++ let c = &b"ab"[..]; ++ assert_eq!(opt_abcd(a), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++ assert_eq!(opt_abcd(b), Done(&b"bcdefg"[..], None)); ++ assert_eq!(opt_abcd(c), Incomplete(Needed::Size(4))); ++ } ++ ++ #[test] ++ fn opt_res() { ++ named!(opt_res_abcd<&[u8], Result<&[u8], Err<&[u8]>> >, opt_res!(tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"bcdefg"[..]; ++ let c = &b"ab"[..]; ++ assert_eq!(opt_res_abcd(a), Done(&b"ef"[..], Ok(&b"abcd"[..]))); ++ assert_eq!(opt_res_abcd(b), Done(&b"bcdefg"[..], Err(Position(ErrorKind::Tag, b)))); ++ assert_eq!(opt_res_abcd(c), Incomplete(Needed::Size(4))); ++ } ++ ++ #[test] ++ fn cond() { ++ let f_true: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( true, tag!("abcd") ) )); ++ let f_false: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( false, tag!("abcd") ) )); ++ //let f_false = closure!(&'static [u8], cond!( false, tag!("abcd") ) ); ++ ++ assert_eq!(f_true(&b"abcdef"[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++ assert_eq!(f_true(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(f_true(&b"xxx"[..]), Done(&b"xxx"[..], None)); ++ ++ assert_eq!(f_false(&b"abcdef"[..]), Done(&b"abcdef"[..], None)); ++ assert_eq!(f_false(&b"ab"[..]), Done(&b"ab"[..], None)); ++ assert_eq!(f_false(&b"xxx"[..]), Done(&b"xxx"[..], None)); ++ } ++ ++ #[test] ++ fn cond_wrapping() { ++ // Test that cond!() will wrap a given identifier in the call!() macro. ++ named!( tag_abcd, tag!("abcd") ); ++ let f_true: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( true, tag_abcd ) )); ++ let f_false: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( false, tag_abcd ) )); ++ //let f_false = closure!(&'static [u8], cond!( b2, tag!("abcd") ) ); ++ ++ assert_eq!(f_true(&b"abcdef"[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++ assert_eq!(f_true(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(f_true(&b"xxx"[..]), Done(&b"xxx"[..], None)); ++ ++ assert_eq!(f_false(&b"abcdef"[..]), Done(&b"abcdef"[..], None)); ++ assert_eq!(f_false(&b"ab"[..]), Done(&b"ab"[..], None)); ++ assert_eq!(f_false(&b"xxx"[..]), Done(&b"xxx"[..], None)); ++ } ++ ++ #[test] ++ fn peek() { ++ named!(peek_tag<&[u8],&[u8]>, peek!(tag!("abcd"))); ++ ++ assert_eq!(peek_tag(&b"abcdef"[..]), Done(&b"abcdef"[..], &b"abcd"[..])); ++ assert_eq!(peek_tag(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(peek_tag(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn pair() { ++ named!( tag_abc, tag!("abc") ); ++ named!( tag_def, tag!("def") ); ++ named!( pair_abc_def<&[u8],(&[u8], &[u8])>, pair!(tag_abc, tag_def) ); ++ ++ assert_eq!(pair_abc_def(&b"abcdefghijkl"[..]), Done(&b"ghijkl"[..], (&b"abc"[..], &b"def"[..]))); ++ assert_eq!(pair_abc_def(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(pair_abc_def(&b"abcd"[..]), Incomplete(Needed::Size(6))); ++ assert_eq!(pair_abc_def(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(pair_abc_def(&b"xxxdef"[..]), Error(Position(ErrorKind::Tag, &b"xxxdef"[..]))); ++ assert_eq!(pair_abc_def(&b"abcxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn separated_pair() { ++ named!( tag_abc, tag!("abc") ); ++ named!( tag_def, tag!("def") ); ++ named!( tag_separator, tag!(",") ); ++ named!( sep_pair_abc_def<&[u8],(&[u8], &[u8])>, separated_pair!(tag_abc, tag_separator, tag_def) ); ++ ++ assert_eq!(sep_pair_abc_def(&b"abc,defghijkl"[..]), Done(&b"ghijkl"[..], (&b"abc"[..], &b"def"[..]))); ++ assert_eq!(sep_pair_abc_def(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(sep_pair_abc_def(&b"abc,d"[..]), Incomplete(Needed::Size(7))); ++ assert_eq!(sep_pair_abc_def(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(sep_pair_abc_def(&b"xxx,def"[..]), Error(Position(ErrorKind::Tag, &b"xxx,def"[..]))); ++ assert_eq!(sep_pair_abc_def(&b"abc,xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn preceded() { ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_efgh, tag!("efgh") ); ++ named!( preceded_abcd_efgh<&[u8], &[u8]>, preceded!(tag_abcd, tag_efgh) ); ++ ++ assert_eq!(preceded_abcd_efgh(&b"abcdefghijkl"[..]), Done(&b"ijkl"[..], &b"efgh"[..])); ++ assert_eq!(preceded_abcd_efgh(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(preceded_abcd_efgh(&b"abcde"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(preceded_abcd_efgh(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(preceded_abcd_efgh(&b"xxxxdef"[..]), Error(Position(ErrorKind::Tag, &b"xxxxdef"[..]))); ++ assert_eq!(preceded_abcd_efgh(&b"abcdxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn terminated() { ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_efgh, tag!("efgh") ); ++ named!( terminated_abcd_efgh<&[u8], &[u8]>, terminated!(tag_abcd, tag_efgh) ); ++ ++ assert_eq!(terminated_abcd_efgh(&b"abcdefghijkl"[..]), Done(&b"ijkl"[..], &b"abcd"[..])); ++ assert_eq!(terminated_abcd_efgh(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(terminated_abcd_efgh(&b"abcde"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(terminated_abcd_efgh(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(terminated_abcd_efgh(&b"xxxxdef"[..]), Error(Position(ErrorKind::Tag, &b"xxxxdef"[..]))); ++ assert_eq!(terminated_abcd_efgh(&b"abcdxxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxxx"[..]))); ++ } ++ ++ #[test] ++ fn delimited() { ++ named!( tag_abc, tag!("abc") ); ++ named!( tag_def, tag!("def") ); ++ named!( tag_ghi, tag!("ghi") ); ++ named!( delimited_abc_def_ghi<&[u8], &[u8]>, delimited!(tag_abc, tag_def, tag_ghi) ); ++ ++ assert_eq!(delimited_abc_def_ghi(&b"abcdefghijkl"[..]), Done(&b"jkl"[..], &b"def"[..])); ++ assert_eq!(delimited_abc_def_ghi(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcde"[..]), Incomplete(Needed::Size(6))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcdefgh"[..]), Incomplete(Needed::Size(9))); ++ assert_eq!(delimited_abc_def_ghi(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(delimited_abc_def_ghi(&b"xxxdefghi"[..]), Error(Position(ErrorKind::Tag, &b"xxxdefghi"[..]))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcxxxghi"[..]), Error(Position(ErrorKind::Tag, &b"xxxghi"[..]))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcdefxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn separated_list() { ++ named!(multi<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!("abcd"))); ++ named!(multi_empty<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!(""))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcd,abcdef"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b",,abc"[..]; ++ let e = &b"abcd,abcd,ef"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"ef"[..], res2)); ++ assert_eq!(multi(c), Done(&b"azerty"[..], Vec::new())); ++ assert_eq!(multi_empty(d), Error(Position(ErrorKind::SeparatedList, d))); ++ //let res3 = vec![&b""[..], &b""[..], &b""[..]]; ++ //assert_eq!(multi_empty(d), Done(&b"abc"[..], res3)); ++ let res4 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(e), Done(&b",ef"[..], res4)); ++ } ++ ++ #[test] ++ fn separated_nonempty_list() { ++ named!(multi<&[u8],Vec<&[u8]> >, separated_nonempty_list!(tag!(","), tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcd,abcdef"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b"abcd,abcd,ef"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"ef"[..], res2)); ++ assert_eq!(multi(c), Error(Position(ErrorKind::Tag,c))); ++ let res3 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(d), Done(&b",ef"[..], res3)); ++ } ++ ++ #[test] ++ fn many0() { ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_empty, tag!("") ); ++ named!( multi<&[u8],Vec<&[u8]> >, many0!(tag_abcd) ); ++ named!( multi_empty<&[u8],Vec<&[u8]> >, many0!(tag_empty) ); ++ ++ assert_eq!(multi(&b"abcdef"[..]), Done(&b"ef"[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b"abcdabcdefgh"[..]), Done(&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])); ++ assert_eq!(multi(&b"azerty"[..]), Done(&b"azerty"[..], Vec::new())); ++ assert_eq!(multi(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(multi(&b"abcd"[..]), Done(&b""[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b""[..]), Done(&b""[..], Vec::new())); ++ assert_eq!(multi_empty(&b"abcdef"[..]), Error(Position(ErrorKind::Many0, &b"abcdef"[..]))); ++ } ++ ++ #[cfg(feature = "nightly")] ++ use test::Bencher; ++ ++ #[cfg(feature = "nightly")] ++ #[bench] ++ fn many0_bench(b: &mut Bencher) { ++ named!(multi<&[u8],Vec<&[u8]> >, many0!(tag!("abcd"))); ++ b.iter(|| { ++ multi(&b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"[..]) ++ }); ++ } ++ ++ #[test] ++ fn many1() { ++ named!(multi<&[u8],Vec<&[u8]> >, many1!(tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcdabcdefgh"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b"abcdab"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res2)); ++ assert_eq!(multi(c), Error(Position(ErrorKind::Many1,c))); ++ assert_eq!(multi(d), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ fn infinite_many() { ++ fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { ++ println!("input: {:?}", input); ++ Error(Position(ErrorKind::Custom(0),input)) ++ } ++ ++ // should not go into an infinite loop ++ named!(multi0<&[u8],Vec<&[u8]> >, many0!(tst)); ++ let a = &b"abcdef"[..]; ++ assert_eq!(multi0(a), Done(a, Vec::new())); ++ ++ named!(multi1<&[u8],Vec<&[u8]> >, many1!(tst)); ++ let a = &b"abcdef"[..]; ++ assert_eq!(multi1(a), Error(Position(ErrorKind::Many1,a))); ++ } ++ ++ #[test] ++ fn many_m_n() { ++ named!(multi<&[u8],Vec<&[u8]> >, many_m_n!(2, 4, tag!("Abcd"))); ++ ++ let a = &b"Abcdef"[..]; ++ let b = &b"AbcdAbcdefgh"[..]; ++ let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; ++ let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; ++ let e = &b"AbcdAb"[..]; ++ ++ assert_eq!(multi(a), Error(Err::Position(ErrorKind::ManyMN,a))); ++ let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res1)); ++ let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(c), Done(&b"efgh"[..], res2)); ++ let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(d), Done(&b"Abcdefgh"[..], res3)); ++ assert_eq!(multi(e), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ fn count() { ++ const TIMES: usize = 2; ++ named!( tag_abc, tag!("abc") ); ++ named!( cnt_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) ); ++ ++ assert_eq!(cnt_2(&b"abcabcabcdef"[..]), Done(&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]])); ++ assert_eq!(cnt_2(&b"ab"[..]), Incomplete(Needed::Unknown)); ++ assert_eq!(cnt_2(&b"abcab"[..]), Incomplete(Needed::Unknown)); ++ assert_eq!(cnt_2(&b"xxx"[..]), Error(Position(ErrorKind::Count, &b"xxx"[..]))); ++ assert_eq!(cnt_2(&b"xxxabcabcdef"[..]), Error(Position(ErrorKind::Count, &b"xxxabcabcdef"[..]))); ++ assert_eq!(cnt_2(&b"abcxxxabcdef"[..]), Error(Position(ErrorKind::Count, &b"abcxxxabcdef"[..]))); ++ } ++ ++ #[test] ++ fn count_zero() { ++ const TIMES: usize = 0; ++ named!( tag_abc, tag!("abc") ); ++ named!( counter_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) ); ++ ++ let done = &b"abcabcabcdef"[..]; ++ let parsed_done = Vec::new(); ++ let rest = done; ++ let incomplete_1 = &b"ab"[..]; ++ let parsed_incompl_1 = Vec::new(); ++ let incomplete_2 = &b"abcab"[..]; ++ let parsed_incompl_2 = Vec::new(); ++ let error = &b"xxx"[..]; ++ let error_remain = &b"xxx"[..]; ++ let parsed_err = Vec::new(); ++ let error_1 = &b"xxxabcabcdef"[..]; ++ let parsed_err_1 = Vec::new(); ++ let error_1_remain = &b"xxxabcabcdef"[..]; ++ let error_2 = &b"abcxxxabcdef"[..]; ++ let parsed_err_2 = Vec::new(); ++ let error_2_remain = &b"abcxxxabcdef"[..]; ++ ++ assert_eq!(counter_2(done), Done(rest, parsed_done)); ++ assert_eq!(counter_2(incomplete_1), Done(incomplete_1, parsed_incompl_1)); ++ assert_eq!(counter_2(incomplete_2), Done(incomplete_2, parsed_incompl_2)); ++ assert_eq!(counter_2(error), Done(error_remain, parsed_err)); ++ assert_eq!(counter_2(error_1), Done(error_1_remain, parsed_err_1)); ++ assert_eq!(counter_2(error_2), Done(error_2_remain, parsed_err_2)); ++ } ++ ++ #[test] ++ fn count_fixed() { ++ const TIMES: usize = 2; ++ named!( tag_abc, tag!("abc") ); ++ named!( cnt_2<&[u8], [&[u8]; TIMES] >, count_fixed!(&[u8], tag_abc, TIMES ) ); ++ ++ assert_eq!(cnt_2(&b"abcabcabcdef"[..]), Done(&b"abcdef"[..], [&b"abc"[..], &b"abc"[..]])); ++ assert_eq!(cnt_2(&b"ab"[..]), Incomplete(Needed::Unknown)); ++ assert_eq!(cnt_2(&b"abcab"[..]), Incomplete(Needed::Unknown)); ++ assert_eq!(cnt_2(&b"xxx"[..]), Error(Position(ErrorKind::Count, &b"xxx"[..]))); ++ assert_eq!(cnt_2(&b"xxxabcabcdef"[..]), Error(Position(ErrorKind::Count, &b"xxxabcabcdef"[..]))); ++ assert_eq!(cnt_2(&b"abcxxxabcdef"[..]), Error(Position(ErrorKind::Count, &b"abcxxxabcdef"[..]))); ++ } ++ ++ use nom::{le_u16,eof}; ++ #[allow(dead_code)] ++ pub fn compile_count_fixed(input: &[u8]) -> IResult<&[u8], ()> { ++ chain!(input, ++ tag!("abcd") ~ ++ count_fixed!( u16, le_u16, 4 ) ~ ++ eof , ++ || { () } ++ ) ++ } ++ ++ #[test] ++ fn count_fixed_no_type() { ++ const TIMES: usize = 2; ++ named!( tag_abc, tag!("abc") ); ++ named!( counter_2<&[u8], [&[u8]; TIMES], () >, count_fixed!(&[u8], tag_abc, TIMES ) ); ++ ++ let done = &b"abcabcabcdef"[..]; ++ let parsed_main = [&b"abc"[..], &b"abc"[..]]; ++ let rest = &b"abcdef"[..]; ++ let incomplete_1 = &b"ab"[..]; ++ let incomplete_2 = &b"abcab"[..]; ++ let error = &b"xxx"[..]; ++ let error_1 = &b"xxxabcabcdef"[..]; ++ let error_1_remain = &b"xxxabcabcdef"[..]; ++ let error_2 = &b"abcxxxabcdef"[..]; ++ let error_2_remain = &b"abcxxxabcdef"[..]; ++ ++ assert_eq!(counter_2(done), Done(rest, parsed_main)); ++ assert_eq!(counter_2(incomplete_1), Incomplete(Needed::Unknown)); ++ assert_eq!(counter_2(incomplete_2), Incomplete(Needed::Unknown)); ++ assert_eq!(counter_2(error), Error(Position(ErrorKind::Count, error))); ++ assert_eq!(counter_2(error_1), Error(Position(ErrorKind::Count, error_1_remain))); ++ assert_eq!(counter_2(error_2), Error(Position(ErrorKind::Count, error_2_remain))); ++ } ++ ++ use nom::{be_u8,be_u16}; ++ #[test] ++ fn length_value_test() { ++ named!(length_value_1<&[u8], Vec >, length_value!(be_u8, be_u16)); ++ named!(length_value_2<&[u8], Vec >, length_value!(be_u8, be_u16, 2)); ++ ++ let i1 = vec![0, 5, 6]; ++ assert_eq!(length_value_1(&i1), IResult::Done(&i1[1..], vec![])); ++ assert_eq!(length_value_2(&i1), IResult::Done(&i1[1..], vec![])); ++ ++ let i2 = vec![1, 5, 6, 3]; ++ assert_eq!(length_value_1(&i2), IResult::Done(&i2[3..], vec![1286])); ++ assert_eq!(length_value_2(&i2), IResult::Done(&i2[3..], vec![1286])); ++ ++ let i3 = vec![2, 5, 6, 3, 4, 5, 7]; ++ assert_eq!(length_value_1(&i3), IResult::Done(&i3[5..], vec![1286, 772])); ++ assert_eq!(length_value_2(&i3), IResult::Done(&i3[5..], vec![1286, 772])); ++ ++ let i4 = vec![2, 5, 6, 3]; ++ assert_eq!(length_value_1(&i4), IResult::Incomplete(Needed::Size(5))); ++ assert_eq!(length_value_2(&i4), IResult::Incomplete(Needed::Size(5))); ++ ++ let i5 = vec![3, 5, 6, 3, 4, 5]; ++ assert_eq!(length_value_1(&i5), IResult::Incomplete(Needed::Size(7))); ++ assert_eq!(length_value_2(&i5), IResult::Incomplete(Needed::Size(7))); ++ } ++ ++ #[test] ++ fn fold_many0() { ++ fn fold_into_vec(mut acc: Vec, item: T) -> Vec { ++ acc.push(item); ++ acc ++ }; ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_empty, tag!("") ); ++ named!( multi<&[u8],Vec<&[u8]> >, fold_many0!(tag_abcd, Vec::new(), fold_into_vec) ); ++ named!( multi_empty<&[u8],Vec<&[u8]> >, fold_many0!(tag_empty, Vec::new(), fold_into_vec) ); ++ ++ assert_eq!(multi(&b"abcdef"[..]), Done(&b"ef"[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b"abcdabcdefgh"[..]), Done(&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])); ++ assert_eq!(multi(&b"azerty"[..]), Done(&b"azerty"[..], Vec::new())); ++ assert_eq!(multi(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(multi(&b"abcd"[..]), Done(&b""[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b""[..]), Done(&b""[..], Vec::new())); ++ assert_eq!(multi_empty(&b"abcdef"[..]), Error(Position(ErrorKind::Many0, &b"abcdef"[..]))); ++ } ++ ++ #[test] ++ fn fold_many1() { ++ fn fold_into_vec(mut acc: Vec, item: T) -> Vec { ++ acc.push(item); ++ acc ++ }; ++ named!(multi<&[u8],Vec<&[u8]> >, fold_many1!(tag!("abcd"), Vec::new(), fold_into_vec)); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcdabcdefgh"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b"abcdab"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res2)); ++ assert_eq!(multi(c), Error(Position(ErrorKind::Many1,c))); ++ assert_eq!(multi(d), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ fn fold_many_m_n() { ++ fn fold_into_vec(mut acc: Vec, item: T) -> Vec { ++ acc.push(item); ++ acc ++ }; ++ named!(multi<&[u8],Vec<&[u8]> >, fold_many_m_n!(2, 4, tag!("Abcd"), Vec::new(), fold_into_vec)); ++ ++ let a = &b"Abcdef"[..]; ++ let b = &b"AbcdAbcdefgh"[..]; ++ let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; ++ let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; ++ let e = &b"AbcdAb"[..]; ++ ++ assert_eq!(multi(a), Error(Err::Position(ErrorKind::ManyMN,a))); ++ let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res1)); ++ let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(c), Done(&b"efgh"[..], res2)); ++ let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(d), Done(&b"Abcdefgh"[..], res3)); ++ assert_eq!(multi(e), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ fn chain_incomplete() { ++ let res = chain!(&b"abcdefgh"[..], ++ a: take!(4) ~ ++ b: take!(8), ++ ||{(a,b )} ++ ); ++ ++ assert_eq!(res, IResult::Incomplete(Needed::Size(12))); ++ } ++ ++ #[test] ++ fn tuple_test() { ++ named!(tuple_3<&[u8], (u16, &[u8], &[u8]) >, ++ tuple!( be_u16 , take!(3), tag!("fg") ) ); ++ ++ assert_eq!(tuple_3(&b"abcdefgh"[..]), Done(&b"h"[..], (0x6162u16, &b"cde"[..], &b"fg"[..]))); ++ assert_eq!(tuple_3(&b"abcd"[..]), Incomplete(Needed::Size(5))); ++ assert_eq!(tuple_3(&b"abcde"[..]), Incomplete(Needed::Size(7))); ++ assert_eq!(tuple_3(&b"abcdejk"[..]), Error(Position(ErrorKind::Tag, &b"jk"[..]))); ++ } ++ ++ #[test] ++ fn not() { ++ named!(not_aaa, not!(tag!("aaa"))); ++ assert_eq!(not_aaa(&b"aaa"[..]), Error(Position(ErrorKind::Not, &b"aaa"[..]))); ++ assert_eq!(not_aaa(&b"aa"[..]), Done(&b"aa"[..], &b""[..])); ++ assert_eq!(not_aaa(&b"abcd"[..]), Done(&b"abcd"[..], &b""[..])); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/methods.rs third_party/rust/nom-1.2.4/src/methods.rs +new file mode 100644 +index 000000000000..22868541a96c +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/methods.rs +@@ -0,0 +1,480 @@ ++//! Method macro combinators ++//! ++//! These macros make parsers as methods of structs ++//! and that can take methods of structs to call ++//! as parsers. ++//! ++//! There is a trick to make them easier to assemble, ++//! combinators are defined like this: ++//! ++//! ```ignore ++//! macro_rules! tag ( ++//! ($i:expr, $inp: expr) => ( ++//! { ++//! ... ++//! } ++//! ); ++//! ); ++//! ``` ++//! ++//! But when used as methods in other combinators, are used ++//! like this: ++//! ++//! ```ignore ++//! method!(my_function >, self, tag!("abcd")); ++//! ``` ++//! ++//! Internally, other combinators will rewrite ++//! that call to pass the input as second argument: ++//! ++//! ```ignore ++//! macro_rules! method ( ++//! ($name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++//! fn $name( $self_: $a, i: &[u8] ) -> $crate::IResult<&[u8], &[u8]> { ++//! $submac!(i, $($args)*) ++//! } ++//! ); ++//! ); ++//! ``` ++//! ++//! The `method!` macro is similar to the `named!` macro in the macros module. ++//! While `named!` will create a parser function, `method!` will create a parser ++//! method on the struct it is defined in. ++//! ++//! Compared to the `named!` macro there are a few differences in how they are ++//! invoked. A `method!` invocation always has to have the type of `self` ++//! declared and it can't be a reference due to Rust's borrow lifetime ++//! restrictions: ++//! ```ignore ++//! // -`self`'s type- ++//! method!(method_name< Parser<'a> >, ...); ++//! ``` ++//! `self`'s type always comes first. ++//! The next difference is you have to input the self struct. Due to Rust's ++//! macro hygiene the macro can't declare it on it's own. ++//! ```ignore ++//! // -self- ++//! method!(method_name, &'a str, &'a str>, self, ...); ++//! ``` ++//! When making a parsing struct with parsing methods, due to the static borrow ++//! checker,calling any parsing methods on self (or any other parsing struct) ++//! will cause self to be moved for the rest of the method.To get around this ++//! restriction all self is moved into the called method and then the called ++//! method will return self to the caller. ++//! ++//! To call a method on self you need to use the `call_m!` macro. For example: ++//! ```ignore ++//! struct<'a> Parser<'a> { ++//! parsed: &'a str, ++//! } ++//! impl<'a> Parser<'a> { ++//! // Constructor omitted for brevity ++//! method!(take4, &'a str, &'a str>, self, take!(4)); ++//! method!(caller, &'a str, &'a str>, self, call_m!(self.take4)); ++//! } ++//! ``` ++//! More complicated combinations still mostly look the same as their `named!` ++//! counterparts: ++//! ```ignore ++//! method!(pub simple_chain<&mut Parser<'a>, &'a str, &'a str>, self, ++//! chain!( ++//! call_m!(self.tag_abc) ~ ++//! call_m!(self.tag_def) ~ ++//! call_m!(self.tag_ghi) ~ ++//! last: call_m!(self.simple_peek) , ++//! ||{sb.parsed = last; last} ++//! ) ++//! ); ++//! ``` ++//! The three additions to method definitions to remember are: ++//! 1. Specify `self`'s type ++//! 2. Pass `self` to the macro ++//! 4. Call parser methods using the `call_m!` macro. ++ ++/// Makes a method from a parser combination ++/// ++/// The must be set up because the compiler needs ++/// the information ++/// ++/// ```ignore ++/// method!(my_function >( &[u8] ) -> &[u8], tag!("abcd")); ++/// // first type parameter is `self`'s type, second is input, third is output ++/// method!(my_function, &[u8], &[u8]>, tag!("abcd")); ++/// //prefix them with 'pub' to make the methods public ++/// method!(pub my_function,&[u8], &[u8]>, tag!("abcd")); ++/// ``` ++#[macro_export] ++macro_rules! method ( ++ // Non-public immutable self ++ ($name:ident<$a:ty>( $i:ty ) -> $o:ty, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name<'a>( $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ // Public immutable self ++ (pub $name:ident<$a:ty>( $i:ty ) -> $o:ty, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( $self_: $a,i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name<'a>( $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ // Non-public mutable self ++ ($name:ident<$a:ty>( $i:ty ) -> $o:ty, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty,$i:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name<'a>( mut $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ ($name:ident<$a:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ // Public mutable self ++ (pub $name:ident<$a:ty>( $i:ty ) -> $o:ty, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty,$i:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( mut $self_: $a,i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name<'a>( mut $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++ (pub $name:ident<$a:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { ++ let result = $submac!(i, $($args)*); ++ ($self_, result) ++ } ++ ); ++); ++ ++/// Used to called methods then move self back into self ++#[macro_export] ++macro_rules! call_m ( ++ ($i:expr, $self_:ident.$method:ident) => ( ++ { ++ let (tmp, res) = $self_.$method($i); ++ $self_ = tmp; ++ res ++ } ++ ); ++ ($i:expr, $self_:ident.$method:ident, $($args:expr),* ) => ( ++ { ++ let (tmp, res) = $self_.$method($i, $($args),*); ++ $self_ = tmp; ++ res ++ } ++ ); ++); ++ ++ ++/// emulate function currying for method calls on structs ++/// `apply!(self.my_function, arg1, arg2, ...)` becomes `self.my_function(input, arg1, arg2, ...)` ++/// ++/// Supports up to 6 arguments ++#[macro_export] ++macro_rules! apply_m ( ++ ($i:expr, $self_:ident.$method:ident, $($args:expr),* ) => ( { let (tmp, res) = $self_.$method( $i, $($args),* ); $self_ = tmp; res } ); ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::IResult::*; ++ ++ // reproduce the tag_s and take_s macros, because of module import order ++ macro_rules! tag_s ( ++ ($i:expr, $tag: expr) => ( ++ { ++ let res: $crate::IResult<_,_> = if $tag.len() > $i.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($tag.len())) ++ //} else if &$i[0..$tag.len()] == $tag { ++ } else if ($i).starts_with($tag) { ++ $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagStr, $i)) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ macro_rules! take_s ( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res: $crate::IResult<_,_> = if $i.chars().count() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ let mut offset = $i.len(); ++ let mut count = 0; ++ for (o, _) in $i.char_indices() { ++ if count == cnt { ++ offset = o; ++ break; ++ } ++ count += 1; ++ } ++ $crate::IResult::Done(&$i[offset..], &$i[..offset]) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ struct Parser<'a> { ++ bcd: &'a str, ++ } ++ ++ impl<'a> Parser<'a> { ++ pub fn new() -> Parser<'a> { ++ Parser{bcd: ""} ++ } ++ ++ method!(tag_abc, &'a str, &'a str>, self, tag_s!("áβç")); ++ method!(tag_bcd >(&'a str) -> &'a str, self, tag_s!("βçδ")); ++ method!(pub tag_hij >(&'a str) -> &'a str, self, tag_s!("λïJ")); ++ method!(pub tag_ijk, &'a str, &'a str>, self, tag_s!("ïJƙ")); ++ method!(take3, &'a str, &'a str>, self, take_s!(3)); ++ method!(pub simple_call, &'a str, &'a str>, mut self, ++ call_m!(self.tag_abc) ++ ); ++ method!(pub simple_peek, &'a str, &'a str>, mut self, ++ peek!(call_m!(self.take3)) ++ ); ++ method!(pub simple_chain, &'a str, &'a str>, mut self, ++ chain!( ++ bcd: call_m!(self.tag_bcd) ~ ++ last: call_m!(self.simple_peek) , ++ ||{self.bcd = bcd; last} ++ ) ++ ); ++ fn tag_stuff(mut self: Parser<'a>, input: &'a str, something: &'a str) -> (Parser<'a>, ::IResult<&'a str, &'a str>) { ++ self.bcd = something; ++ let(tmp, res) = self.tag_abc(input); ++ self = tmp; ++ (self, res) ++ } ++ method!(use_apply, &'a str, &'a str>, mut self, apply_m!(self.tag_stuff, "βçδ")); ++ } ++ ++ #[test] ++ fn test_method_call_abc() { ++ let p = Parser::new(); ++ let input: &str = "áβçδèƒϱλïJƙ"; ++ let consumed: &str = "áβç"; ++ let leftover: &str = "δèƒϱλïJƙ"; ++ let(_, res) = p.tag_abc(input); ++ match res { ++ Done(extra, output) => { assert!(extra == leftover, "`Parser.tag_abc` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.tag_abc` doesnt return the string it consumed \ ++ on success. Expected `{}`, got `{}`.", consumed, output); ++ }, ++ other => panic!("`Parser.tag_abc` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ #[test] ++ fn test_method_call_bcd() { ++ let p = Parser::new(); ++ let input: &str = "βçδèƒϱλïJƙ"; ++ let consumed: &str = "βçδ"; ++ let leftover: &str = "èƒϱλïJƙ"; ++ let(_, res) = p.tag_bcd(input); ++ match res { ++ Done(extra, output) => { assert!(extra == leftover, "`Parser.tag_bcd` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.tag_bcd` doesn't return the string it consumed \ ++ on success. Expected `{}`, got `{}`.", consumed, output); ++ }, ++ other => panic!("`Parser.tag_bcd` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ #[test] ++ fn test_method_call_hij() { ++ let p = Parser::new(); ++ let input: &str = "λïJƙℓ₥ñôƥ9řƨ"; ++ let consumed: &str = "λïJ"; ++ let leftover: &str = "ƙℓ₥ñôƥ9řƨ"; ++ let(_, res) = p.tag_hij(input); ++ match res { ++ Done(extra, output) => { assert!(extra == leftover, "`Parser.tag_hij` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.tag_hij` doesn't return the string it consumed \ ++ on success. Expected `{}`, got `{}`.", consumed, output); ++ }, ++ other => panic!("`Parser.tag_hij` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ #[test] ++ fn test_method_call_ijk() { ++ let p = Parser::new(); ++ let input: &str = "ïJƙℓ₥ñôƥ9řƨ"; ++ let consumed: &str = "ïJƙ"; ++ let leftover: &str = "ℓ₥ñôƥ9řƨ"; ++ let(_, res) = p.tag_ijk(input); ++ match res { ++ Done(extra, output) => { assert!(extra == leftover, "`Parser.tag_ijk` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.tag_ijk` doesn't return the string it consumed \ ++ on success. Expected `{}`, got `{}`.", consumed, output); ++ }, ++ other => panic!("`Parser.tag_ijk` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ #[test] ++ fn test_method_simple_call() { ++ let p = Parser::new(); ++ let input: &str = "áβçδèƒϱλïJƙ"; ++ let consumed: &str = "áβç"; ++ let leftover: &str = "δèƒϱλïJƙ"; ++ let(_, res) = p.simple_call(input); ++ match res { ++ Done(extra, output) => { assert!(extra == leftover, "`Parser.simple_call` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.simple_call` doesn't return the string it consumed \ ++ on success. Expected `{}`, got `{}`.", consumed, output); ++ }, ++ other => panic!("`Parser.simple_call` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ #[test] ++ fn test_apply_m() { ++ let mut p = Parser::new(); ++ let input: &str = "áβçδèƒϱλïJƙ"; ++ let consumed: &str = "áβç"; ++ let leftover: &str = "δèƒϱλïJƙ"; ++ let(tmp, res) = p.use_apply(input); ++ p = tmp; ++ match res { ++ Done(extra, output) => { assert!(extra == leftover, "`Parser.use_apply` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.use_apply` doesn't return the string it was supposed to \ ++ on success. Expected `{}`, got `{}`.", leftover, output); ++ assert!(p.bcd == "βçδ", "Parser.use_apply didn't modify the parser field correctly: {}", p.bcd); ++ }, ++ other => panic!("`Parser.use_apply` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ #[test] ++ fn test_method_call_peek() { ++ let p = Parser::new(); ++ let input: &str = "ж¥ƺáβçδèƒϱλïJƙ"; ++ let consumed: &str = "ж¥ƺ"; ++ let(_, res) = p.simple_peek(input); ++ match res { ++ Done(extra, output) => { assert!(extra == input, "`Parser.simple_peek` consumed leftover input. leftover: {}", extra); ++ assert!(output == consumed, "`Parser.simple_peek` doesn't return the string it consumed \ ++ on success. Expected `{}`, got `{}`.", consumed, output); ++ }, ++ other => panic!("`Parser.simple_peek` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ #[test] ++ fn test_method_call_chain() { ++ let mut p = Parser::new(); ++ let input : &str = "βçδδèƒϱλïJƙℓ"; ++ let leftover : &str = "δèƒϱλïJƙℓ"; ++ let output : &str = "δèƒ"; ++ let(tmp, res) = p.simple_chain(input); ++ p = tmp; ++ match res { ++ Done(extra, out) => { assert!(extra == leftover, "`Parser.simple_chain` consumed leftover input. leftover: {}", extra); ++ assert!(out == output, "`Parser.simple_chain` doesn't return the string it was supposed to \ ++ on success. Expected `{}`, got `{}`.", output, out); ++ assert!(p.bcd == "βçδ", "Parser.simple_chain didn't modify the parser field correctly: {}", p.bcd); ++ }, ++ other => panic!("`Parser.simple_chain` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/nom.rs third_party/rust/nom-1.2.4/src/nom.rs +new file mode 100644 +index 000000000000..74bac5bfb0c4 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/nom.rs +@@ -0,0 +1,950 @@ ++//! Useful parser combinators ++//! ++//! A number of useful parser combinators have already been implemented. ++//! Some of them use macros, other are implemented through functions. ++//! Hopefully, the syntax will converge to onely one way in the future, ++//! but the macros system makes no promises. ++//! ++ ++#[cfg(feature = "core")] ++use std::prelude::v1::*; ++use std::boxed::Box; ++ ++use std::fmt::Debug; ++use internal::*; ++use internal::IResult::*; ++use internal::Err::*; ++use util::{ErrorKind,IterIndices,AsChar,InputLength}; ++use std::mem::transmute; ++ ++#[inline] ++pub fn tag_cl<'a,'b>(rec:&'a[u8]) -> Box IResult<&'b[u8], &'b[u8]> + 'a> { ++ Box::new(move |i: &'b[u8]| -> IResult<&'b[u8], &'b[u8]> { ++ if i.len() >= rec.len() && &i[0..rec.len()] == rec { ++ Done(&i[rec.len()..], &i[0..rec.len()]) ++ } else { ++ Error(Position(ErrorKind::TagClosure, i)) ++ } ++ }) ++} ++ ++#[cfg(not(feature = "core"))] ++#[inline] ++pub fn print(input: T) -> IResult { ++ println!("{:?}", input); ++ Done(input, ()) ++} ++ ++#[inline] ++pub fn begin(input: &[u8]) -> IResult<(), &[u8]> { ++ Done((), input) ++} ++ ++// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export ++// public methods ++//pub is_not!(line_ending b"\r\n") ++pub fn not_line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> { ++ for (idx, item) in input.iter().enumerate() { ++ for &i in b"\r\n".iter() { ++ if *item == i { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input.len()..], input) ++} ++ ++named!(tag_ln, tag!("\n")); ++ ++/// Recognizes a line feed ++#[inline] ++pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> { ++ tag_ln(input) ++} ++ ++#[inline] ++pub fn is_alphabetic(chr:u8) -> bool { ++ (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A) ++} ++ ++#[inline] ++pub fn is_digit(chr: u8) -> bool { ++ chr >= 0x30 && chr <= 0x39 ++} ++ ++#[inline] ++pub fn is_hex_digit(chr: u8) -> bool { ++ (chr >= 0x30 && chr <= 0x39) || ++ (chr >= 0x41 && chr <= 0x46) || ++ (chr >= 0x61 && chr <= 0x66) ++} ++ ++#[inline] ++pub fn is_oct_digit(chr: u8) -> bool { ++ chr >= 0x30 && chr <= 0x37 ++} ++ ++#[inline] ++pub fn is_alphanumeric(chr: u8) -> bool { ++ is_alphabetic(chr) || is_digit(chr) ++} ++ ++#[inline] ++pub fn is_space(chr:u8) -> bool { ++ chr == ' ' as u8 || chr == '\t' as u8 ++} ++ ++// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export ++//pub filter!(alpha is_alphabetic) ++//pub filter!(digit is_digit) ++//pub filter!(hex_digit is_hex_digit) ++//pub filter!(oct_digit is_oct_digit) ++//pub filter!(alphanumeric is_alphanumeric) ++ ++use std::ops::{Index,Range,RangeFrom}; ++/// Recognizes lowercase and uppercase alphabetic characters: a-zA-Z ++pub fn alpha<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::Alpha, input)) ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ if ! item.is_alpha() { ++ if idx == 0 { ++ return Error(Position(ErrorKind::Alpha, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++/// Recognizes numerical characters: 0-9 ++pub fn digit<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::Digit, input)) ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ if ! item.is_0_to_9() { ++ if idx == 0 { ++ return Error(Position(ErrorKind::Digit, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++/// Recognizes hexadecimal numerical characters: 0-9, A-F, a-f ++pub fn hex_digit<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::HexDigit, input)) ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ if ! item.is_hex_digit() { ++ if idx == 0 { ++ return Error(Position(ErrorKind::HexDigit, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++/// Recognizes octal characters: 0-7 ++pub fn oct_digit<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::OctDigit, input)) ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ if ! item.is_oct_digit() { ++ if idx == 0 { ++ return Error(Position(ErrorKind::OctDigit, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++/// Recognizes numerical and alphabetic characters: 0-9a-zA-Z ++pub fn alphanumeric<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::AlphaNumeric, input)); ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ if ! item.is_alphanum() { ++ if idx == 0 { ++ return Error(Position(ErrorKind::AlphaNumeric, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++/// Recognizes spaces and tabs ++pub fn space<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::Space, input)); ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ let chr = item.as_char(); ++ if ! (chr == ' ' || chr == '\t') { ++ if idx == 0 { ++ return Error(Position(ErrorKind::Space, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++/// Recognizes spaces, tabs, carriage returns and line feeds ++pub fn multispace<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: IterIndices+InputLength { ++ let input_length = input.input_len(); ++ if input_length == 0 { ++ return Error(Position(ErrorKind::MultiSpace, input)); ++ } ++ ++ for (idx, item) in input.iter_indices() { ++ let chr = item.as_char(); ++ if ! (chr == ' ' || chr == '\t' || chr == '\r' || chr == '\n') { ++ if idx == 0 { ++ return Error(Position(ErrorKind::MultiSpace, input)) ++ } else { ++ return Done(&input[idx..], &input[0..idx]) ++ } ++ } ++ } ++ Done(&input[input_length..], input) ++} ++ ++pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> { ++ if input.is_empty() { ++ return Incomplete(Needed::Unknown) ++ } ++ ++ let len = input[0] as usize; ++ ++ if input.len() >= len + 1 { ++ Done(&input[len+1..], &input[1..len+1]) ++ } else { ++ Incomplete(Needed::Size(1 + len)) ++ } ++} ++ ++pub fn length_value(input:&[u8]) -> IResult<&[u8], &[u8]> { ++ let input_len = input.len(); ++ if input_len == 0 { ++ return Error(Position(ErrorKind::LengthValueFn, input)) ++ } ++ ++ let len = input[0] as usize; ++ if input_len - 1 >= len { ++ IResult::Done(&input[len+1..], &input[1..len+1]) ++ } else { ++ IResult::Incomplete(Needed::Size(1+len)) ++ } ++} ++ ++/// Recognizes an unsigned 1 byte integer (equivalent to take!(1) ++#[inline] ++pub fn be_u8(i: &[u8]) -> IResult<&[u8], u8> { ++ if i.len() < 1 { ++ Incomplete(Needed::Size(1)) ++ } else { ++ Done(&i[1..], i[0]) ++ } ++} ++ ++/// Recognizes big endian unsigned 2 bytes integer ++#[inline] ++pub fn be_u16(i: &[u8]) -> IResult<&[u8], u16> { ++ if i.len() < 2 { ++ Incomplete(Needed::Size(2)) ++ } else { ++ let res = ((i[0] as u16) << 8) + i[1] as u16; ++ Done(&i[2..], res) ++ } ++} ++ ++/// Recognizes big endian unsigned 4 bytes integer ++#[inline] ++pub fn be_u32(i: &[u8]) -> IResult<&[u8], u32> { ++ if i.len() < 4 { ++ Incomplete(Needed::Size(4)) ++ } else { ++ let res = ((i[0] as u32) << 24) + ((i[1] as u32) << 16) + ((i[2] as u32) << 8) + i[3] as u32; ++ Done(&i[4..], res) ++ } ++} ++ ++/// Recognizes big endian unsigned 8 bytes integer ++#[inline] ++pub fn be_u64(i: &[u8]) -> IResult<&[u8], u64> { ++ if i.len() < 8 { ++ Incomplete(Needed::Size(8)) ++ } else { ++ let res = ((i[0] as u64) << 56) + ((i[1] as u64) << 48) + ((i[2] as u64) << 40) + ((i[3] as u64) << 32) + ++ ((i[4] as u64) << 24) + ((i[5] as u64) << 16) + ((i[6] as u64) << 8) + i[7] as u64; ++ Done(&i[8..], res) ++ } ++} ++ ++/// Recognizes a signed 1 byte integer (equivalent to take!(1) ++#[inline] ++pub fn be_i8(i:&[u8]) -> IResult<&[u8], i8> { ++ map!(i, be_u8, | x | { x as i8 }) ++} ++ ++/// Recognizes big endian signed 2 bytes integer ++#[inline] ++pub fn be_i16(i:&[u8]) -> IResult<&[u8], i16> { ++ map!(i, be_u16, | x | { x as i16 }) ++} ++ ++/// Recognizes big endian signed 4 bytes integer ++#[inline] ++pub fn be_i32(i:&[u8]) -> IResult<&[u8], i32> { ++ map!(i, be_u32, | x | { x as i32 }) ++} ++ ++/// Recognizes big endian signed 8 bytes integer ++#[inline] ++pub fn be_i64(i:&[u8]) -> IResult<&[u8], i64> { ++ map!(i, be_u64, | x | { x as i64 }) ++} ++ ++/// Recognizes an unsigned 1 byte integer (equivalent to take!(1) ++#[inline] ++pub fn le_u8(i: &[u8]) -> IResult<&[u8], u8> { ++ if i.len() < 1 { ++ Incomplete(Needed::Size(1)) ++ } else { ++ Done(&i[1..], i[0]) ++ } ++} ++ ++/// Recognizes little endian unsigned 2 bytes integer ++#[inline] ++pub fn le_u16(i: &[u8]) -> IResult<&[u8], u16> { ++ if i.len() < 2 { ++ Incomplete(Needed::Size(2)) ++ } else { ++ let res = ((i[1] as u16) << 8) + i[0] as u16; ++ Done(&i[2..], res) ++ } ++} ++ ++/// Recognizes little endian unsigned 4 bytes integer ++#[inline] ++pub fn le_u32(i: &[u8]) -> IResult<&[u8], u32> { ++ if i.len() < 4 { ++ Incomplete(Needed::Size(4)) ++ } else { ++ let res = ((i[3] as u32) << 24) + ((i[2] as u32) << 16) + ((i[1] as u32) << 8) + i[0] as u32; ++ Done(&i[4..], res) ++ } ++} ++ ++/// Recognizes little endian unsigned 8 bytes integer ++#[inline] ++pub fn le_u64(i: &[u8]) -> IResult<&[u8], u64> { ++ if i.len() < 8 { ++ Incomplete(Needed::Size(8)) ++ } else { ++ let res = ((i[7] as u64) << 56) + ((i[6] as u64) << 48) + ((i[5] as u64) << 40) + ((i[4] as u64) << 32) + ++ ((i[3] as u64) << 24) + ((i[2] as u64) << 16) + ((i[1] as u64) << 8) + i[0] as u64; ++ Done(&i[8..], res) ++ } ++} ++ ++/// Recognizes a signed 1 byte integer (equivalent to take!(1) ++#[inline] ++pub fn le_i8(i:&[u8]) -> IResult<&[u8], i8> { ++ map!(i, le_u8, | x | { x as i8 }) ++} ++ ++/// Recognizes little endian signed 2 bytes integer ++#[inline] ++pub fn le_i16(i:&[u8]) -> IResult<&[u8], i16> { ++ map!(i, le_u16, | x | { x as i16 }) ++} ++ ++/// Recognizes little endian signed 4 bytes integer ++#[inline] ++pub fn le_i32(i:&[u8]) -> IResult<&[u8], i32> { ++ map!(i, le_u32, | x | { x as i32 }) ++} ++ ++/// Recognizes little endian signed 8 bytes integer ++#[inline] ++pub fn le_i64(i:&[u8]) -> IResult<&[u8], i64> { ++ map!(i, le_u64, | x | { x as i64 }) ++} ++ ++/// if parameter is true, parse a big endian u16 integer, ++/// otherwise a little endian u16 integer ++#[macro_export] ++macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_u16($i) } else { $crate::le_u16($i) } } );); ++/// if parameter is true, parse a big endian u32 integer, ++/// otherwise a little endian u32 integer ++#[macro_export] ++macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_u32($i) } else { $crate::le_u32($i) } } );); ++/// if parameter is true, parse a big endian u64 integer, ++/// otherwise a little endian u64 integer ++#[macro_export] ++macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_u64($i) } else { $crate::le_u64($i) } } );); ++ ++/// if parameter is true, parse a big endian i16 integer, ++/// otherwise a little endian i16 integer ++#[macro_export] ++macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_i16($i) } else { $crate::le_i16($i) } } );); ++/// if parameter is true, parse a big endian i32 integer, ++/// otherwise a little endian i32 integer ++#[macro_export] ++macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_i32($i) } else { $crate::le_i32($i) } } );); ++/// if parameter is true, parse a big endian i64 integer, ++/// otherwise a little endian i64 integer ++#[macro_export] ++macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_i64($i) } else { $crate::le_i64($i) } } );); ++ ++/// Recognizes big endian 4 bytes floating point number ++#[inline] ++pub fn be_f32(input: &[u8]) -> IResult<&[u8], f32> { ++ match be_u32(input) { ++ Error(e) => Error(e), ++ Incomplete(e) => Incomplete(e), ++ Done(i,o) => { ++ unsafe { ++ Done(i, transmute::(o)) ++ } ++ } ++ } ++} ++ ++/// Recognizes big endian 8 bytes floating point number ++#[inline] ++pub fn be_f64(input: &[u8]) -> IResult<&[u8], f64> { ++ match be_u64(input) { ++ Error(e) => Error(e), ++ Incomplete(e) => Incomplete(e), ++ Done(i,o) => { ++ unsafe { ++ Done(i, transmute::(o)) ++ } ++ } ++ } ++} ++ ++/// Recognizes little endian 4 bytes floating point number ++#[inline] ++pub fn le_f32(input: &[u8]) -> IResult<&[u8], f32> { ++ match le_u32(input) { ++ Error(e) => Error(e), ++ Incomplete(e) => Incomplete(e), ++ Done(i,o) => { ++ unsafe { ++ Done(i, transmute::(o)) ++ } ++ } ++ } ++} ++ ++/// Recognizes little endian 8 bytes floating point number ++#[inline] ++pub fn le_f64(input: &[u8]) -> IResult<&[u8], f64> { ++ match le_u64(input) { ++ Error(e) => Error(e), ++ Incomplete(e) => Incomplete(e), ++ Done(i,o) => { ++ unsafe { ++ Done(i, transmute::(o)) ++ } ++ } ++ } ++} ++ ++/// Recognizes a hex-encoded integer ++#[inline] ++pub fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { ++ match is_a!(input, &b"0123456789abcdef"[..]) { ++ Error(e) => Error(e), ++ Incomplete(e) => Incomplete(e), ++ Done(i,o) => { ++ let mut res = 0u32; ++ ++ // Do not parse more than 8 characters for a u32 ++ let mut remaining = i; ++ let mut parsed = o; ++ if o.len() > 8 { ++ remaining = &input[8..]; ++ parsed = &input[..8]; ++ } ++ ++ for &e in parsed { ++ let digit = e as char; ++ let value = digit.to_digit(16).unwrap_or(0); ++ res = value + (res << 4); ++ } ++ Done(remaining, res) ++ } ++ } ++} ++ ++/// Recognizes empty input buffers ++/// ++/// useful to verify that the previous parsers used all of the input ++#[inline] ++//pub fn eof(input:&[u8]) -> IResult<&[u8], &[u8]> { ++pub fn eof<'a, T:?Sized>(input: &'a T) -> IResult<&'a T,&'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: InputLength { ++ if input.input_len() == 0 { ++ Done(input, input) ++ } else { ++ Error(Position(ErrorKind::Eof, input)) ++ } ++} ++ ++/// Recognizes non empty buffers ++#[inline] ++pub fn non_empty<'a, T:?Sized>(input: &'a T) -> IResult<&'a T,&'a T> where ++ T:Index, Output=T>+Index, Output=T>, ++ &'a T: InputLength { ++ if input.input_len() == 0 { ++ Error(Position(ErrorKind::NonEmpty, input)) ++ } else { ++ Done(&input[input.input_len()..], input) ++ } ++} ++ ++/// Return the remaining input. ++#[inline] ++pub fn rest(input: &[u8]) -> IResult<&[u8], &[u8]> { ++ IResult::Done(&input[input.len()..], input) ++} ++ ++/// Return the remaining input, for strings. ++#[inline] ++pub fn rest_s(input: &str) -> IResult<&str, &str> { ++ IResult::Done(&input[input.len()..], input) ++} ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use internal::{Needed,IResult}; ++ use internal::IResult::*; ++ use internal::Err::*; ++ use util::ErrorKind; ++ ++ #[test] ++ fn tag_closure() { ++ let x = tag_cl(&b"abcd"[..]); ++ let r = x(&b"abcdabcdefgh"[..]); ++ assert_eq!(r, Done(&b"abcdefgh"[..], &b"abcd"[..])); ++ ++ let r2 = x(&b"abcefgh"[..]); ++ assert_eq!(r2, Error(Position(ErrorKind::TagClosure, &b"abcefgh"[..]))); ++ } ++ ++ #[test] ++ fn character() { ++ let empty: &[u8] = b""; ++ let a: &[u8] = b"abcd"; ++ let b: &[u8] = b"1234"; ++ let c: &[u8] = b"a123"; ++ let d: &[u8] = "azé12".as_bytes(); ++ let e: &[u8] = b" "; ++ assert_eq!(alpha(a), Done(empty, a)); ++ assert_eq!(alpha(b), Error(Position(ErrorKind::Alpha,b))); ++ assert_eq!(alpha(c), Done(&c[1..], &b"a"[..])); ++ assert_eq!(alpha(d), Done("é12".as_bytes(), &b"az"[..])); ++ assert_eq!(digit(a), Error(Position(ErrorKind::Digit,a))); ++ assert_eq!(digit(b), Done(empty, b)); ++ assert_eq!(digit(c), Error(Position(ErrorKind::Digit,c))); ++ assert_eq!(digit(d), Error(Position(ErrorKind::Digit,d))); ++ assert_eq!(hex_digit(a), Done(empty, a)); ++ assert_eq!(hex_digit(b), Done(empty, b)); ++ assert_eq!(hex_digit(c), Done(empty, c)); ++ assert_eq!(hex_digit(d), Done("zé12".as_bytes(), &b"a"[..])); ++ assert_eq!(hex_digit(e), Error(Position(ErrorKind::HexDigit,e))); ++ assert_eq!(oct_digit(a), Error(Position(ErrorKind::OctDigit,a))); ++ assert_eq!(oct_digit(b), Done(empty, b)); ++ assert_eq!(oct_digit(c), Error(Position(ErrorKind::OctDigit,c))); ++ assert_eq!(oct_digit(d), Error(Position(ErrorKind::OctDigit,d))); ++ assert_eq!(alphanumeric(a), Done(empty, a)); ++ assert_eq!(fix_error!(b,(), alphanumeric), Done(empty, b)); ++ assert_eq!(alphanumeric(c), Done(empty, c)); ++ assert_eq!(alphanumeric(d), Done("é12".as_bytes(), &b"az"[..])); ++ assert_eq!(space(e), Done(&b""[..], &b" "[..])); ++ } ++ ++ #[test] ++ fn character_s() { ++ let empty = ""; ++ let a = "abcd"; ++ let b = "1234"; ++ let c = "a123"; ++ let d = "azé12"; ++ let e = " "; ++ assert_eq!(alpha(a), Done(empty, a)); ++ assert_eq!(alpha(b), Error(Position(ErrorKind::Alpha,b))); ++ assert_eq!(alpha(c), Done(&c[1..], &"a"[..])); ++ assert_eq!(alpha(d), Done("12", &"azé"[..])); ++ assert_eq!(digit(a), Error(Position(ErrorKind::Digit,a))); ++ assert_eq!(digit(b), Done(empty, b)); ++ assert_eq!(digit(c), Error(Position(ErrorKind::Digit,c))); ++ assert_eq!(digit(d), Error(Position(ErrorKind::Digit,d))); ++ assert_eq!(hex_digit(a), Done(empty, a)); ++ assert_eq!(hex_digit(b), Done(empty, b)); ++ assert_eq!(hex_digit(c), Done(empty, c)); ++ assert_eq!(hex_digit(d), Done("zé12", &"a"[..])); ++ assert_eq!(hex_digit(e), Error(Position(ErrorKind::HexDigit,e))); ++ assert_eq!(oct_digit(a), Error(Position(ErrorKind::OctDigit,a))); ++ assert_eq!(oct_digit(b), Done(empty, b)); ++ assert_eq!(oct_digit(c), Error(Position(ErrorKind::OctDigit,c))); ++ assert_eq!(oct_digit(d), Error(Position(ErrorKind::OctDigit,d))); ++ assert_eq!(alphanumeric(a), Done(empty, a)); ++ assert_eq!(fix_error!(b,(), alphanumeric), Done(empty, b)); ++ assert_eq!(alphanumeric(c), Done(empty, c)); ++ assert_eq!(alphanumeric(d), Done("", &"azé12"[..])); ++ assert_eq!(space(e), Done(&""[..], &" "[..])); ++ } ++ ++ use util::HexDisplay; ++ #[test] ++ fn offset() { ++ let a = &b"abcd"[..]; ++ let b = &b"1234"[..]; ++ let c = &b"a123"[..]; ++ let d = &b" \t"[..]; ++ let e = &b" \t\r\n"[..]; ++ let f = &b"123abcDEF"[..]; ++ ++ match alpha(a) { ++ Done(i, _) => { assert_eq!(a.offset(i) + i.len(), a.len()); } ++ _ => { panic!("wrong return type in offset test for alpha") } ++ } ++ match digit(b) { ++ Done(i, _) => { assert_eq!(b.offset(i) + i.len(), b.len()); } ++ _ => { panic!("wrong return type in offset test for digit") } ++ } ++ match alphanumeric(c) { ++ Done(i, _) => { assert_eq!(c.offset(i) + i.len(), c.len()); } ++ _ => { panic!("wrong return type in offset test for alphanumeric") } ++ } ++ match space(d) { ++ Done(i, _) => { assert_eq!(d.offset(i) + i.len(), d.len()); } ++ _ => { panic!("wrong return type in offset test for space") } ++ } ++ match multispace(e) { ++ Done(i, _) => { assert_eq!(e.offset(i) + i.len(), e.len()); } ++ _ => { panic!("wrong return type in offset test for multispace") } ++ } ++ match hex_digit(f) { ++ Done(i, _) => { assert_eq!(f.offset(i) + i.len(), f.len()); } ++ _ => { panic!("wrong return type in offset test for hex_digit") } ++ } ++ match oct_digit(f) { ++ Done(i, _) => { assert_eq!(f.offset(i) + i.len(), f.len()); } ++ _ => { panic!("wrong return type in offset test for oct_digit") } ++ } ++ } ++ ++ #[test] ++ fn is_not() { ++ let a: &[u8] = b"ab12cd\nefgh"; ++ assert_eq!(not_line_ending(a), Done(&b"\nefgh"[..], &b"ab12cd"[..])); ++ ++ let b: &[u8] = b"ab12cd\nefgh\nijkl"; ++ assert_eq!(not_line_ending(b), Done(&b"\nefgh\nijkl"[..], &b"ab12cd"[..])); ++ ++ let c: &[u8] = b"ab12cd"; ++ assert_eq!(not_line_ending(c), Done(&b""[..], c)); ++ } ++ ++ #[test] ++ fn buffer_with_size() { ++ let i:Vec = vec![7,8]; ++ let o:Vec = vec![4,5,6]; ++ //let arr:[u8; 6usize] = [3, 4, 5, 6, 7, 8]; ++ let arr:[u8; 6usize] = [3, 4, 5, 6, 7, 8]; ++ let res = sized_buffer(&arr[..]); ++ assert_eq!(res, Done(&i[..], &o[..])) ++ } ++ ++ /*#[test] ++ fn t1() { ++ let v1:Vec = vec![1,2,3]; ++ let v2:Vec = vec![4,5,6]; ++ let d = Done(&v1[..], &v2[..]); ++ let res = d.flat_map(print); ++ assert_eq!(res, Done(&v2[..], ())); ++ }*/ ++ ++ #[test] ++ fn length_value_test() { ++ let i1 = vec![7,8]; ++ let o1 = vec![4, 5, 6]; ++ let arr1:[u8; 6usize] = [3, 4, 5, 6, 7, 8]; ++ let res1 = length_value(&arr1); ++ assert_eq!(Done(&i1[..], &o1[..]), res1); ++ ++ let i2:Vec = vec![4,5,6,7,8]; ++ let o2: &[u8] = b""; ++ let arr2:[u8; 6usize] = [0, 4, 5, 6, 7, 8]; ++ let res2 = length_value(&arr2); ++ assert_eq!(Done(&i2[..], o2), res2); ++ ++ let arr3:[u8; 7usize] = [8, 4, 5, 6, 7, 8, 9]; ++ let res3 = length_value(&arr3); ++ //FIXME: should be incomplete ++ assert_eq!(Incomplete(Needed::Size(9)), res3); ++ } ++ ++ #[test] ++ fn i8_tests() { ++ assert_eq!(be_i8(&[0x00]), Done(&b""[..], 0)); ++ assert_eq!(be_i8(&[0x7f]), Done(&b""[..], 127)); ++ assert_eq!(be_i8(&[0xff]), Done(&b""[..], -1)); ++ assert_eq!(be_i8(&[0x80]), Done(&b""[..], -128)); ++ } ++ ++ #[test] ++ fn i16_tests() { ++ assert_eq!(be_i16(&[0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(be_i16(&[0x7f, 0xff]), Done(&b""[..], 32767_i16)); ++ assert_eq!(be_i16(&[0xff, 0xff]), Done(&b""[..], -1)); ++ assert_eq!(be_i16(&[0x80, 0x00]), Done(&b""[..], -32768_i16)); ++ } ++ ++ #[test] ++ fn i32_tests() { ++ assert_eq!(be_i32(&[0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(be_i32(&[0x7f, 0xff, 0xff, 0xff]), Done(&b""[..], 2147483647_i32)); ++ assert_eq!(be_i32(&[0xff, 0xff, 0xff, 0xff]), Done(&b""[..], -1)); ++ assert_eq!(be_i32(&[0x80, 0x00, 0x00, 0x00]), Done(&b""[..], -2147483648_i32)); ++ } ++ ++ #[test] ++ fn i64_tests() { ++ assert_eq!(be_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(be_i64(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Done(&b""[..], 9223372036854775807_i64)); ++ assert_eq!(be_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Done(&b""[..], -1)); ++ assert_eq!(be_i64(&[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Done(&b""[..], -9223372036854775808_i64)); ++ } ++ ++ #[test] ++ fn le_i8_tests() { ++ assert_eq!(le_i8(&[0x00]), Done(&b""[..], 0)); ++ assert_eq!(le_i8(&[0x7f]), Done(&b""[..], 127)); ++ assert_eq!(le_i8(&[0xff]), Done(&b""[..], -1)); ++ assert_eq!(le_i8(&[0x80]), Done(&b""[..], -128)); ++ } ++ ++ #[test] ++ fn le_i16_tests() { ++ assert_eq!(le_i16(&[0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(le_i16(&[0xff, 0x7f]), Done(&b""[..], 32767_i16)); ++ assert_eq!(le_i16(&[0xff, 0xff]), Done(&b""[..], -1)); ++ assert_eq!(le_i16(&[0x00, 0x80]), Done(&b""[..], -32768_i16)); ++ } ++ ++ #[test] ++ fn le_i32_tests() { ++ assert_eq!(le_i32(&[0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(le_i32(&[0xff, 0xff, 0xff, 0x7f]), Done(&b""[..], 2147483647_i32)); ++ assert_eq!(le_i32(&[0xff, 0xff, 0xff, 0xff]), Done(&b""[..], -1)); ++ assert_eq!(le_i32(&[0x00, 0x00, 0x00, 0x80]), Done(&b""[..], -2147483648_i32)); ++ } ++ ++ #[test] ++ fn le_i64_tests() { ++ assert_eq!(le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), Done(&b""[..], 9223372036854775807_i64)); ++ assert_eq!(le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Done(&b""[..], -1)); ++ assert_eq!(le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), Done(&b""[..], -9223372036854775808_i64)); ++ } ++ ++ #[test] ++ fn be_f32_tests() { ++ assert_eq!(be_f32(&[0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0_f32)); ++ assert_eq!(be_f32(&[0x4d, 0x31, 0x1f, 0xd8]), Done(&b""[..], 185728392_f32)); ++ } ++ ++ #[test] ++ fn be_f64_tests() { ++ assert_eq!(be_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0_f64)); ++ assert_eq!(be_f64(&[0x41, 0xa6, 0x23, 0xfb, 0x10, 0x00, 0x00, 0x00]), Done(&b""[..], 185728392_f64)); ++ } ++ ++ #[test] ++ fn le_f32_tests() { ++ assert_eq!(le_f32(&[0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0_f32)); ++ assert_eq!(le_f32(&[0xd8, 0x1f, 0x31, 0x4d]), Done(&b""[..], 185728392_f32)); ++ } ++ ++ #[test] ++ fn le_f64_tests() { ++ assert_eq!(le_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0_f64)); ++ assert_eq!(le_f64(&[0x00, 0x00, 0x00, 0x10, 0xfb, 0x23, 0xa6, 0x41]), Done(&b""[..], 185728392_f64)); ++ } ++ ++ #[test] ++ fn hex_u32_tests() { ++ assert_eq!(hex_u32(&b""[..]), Done(&b""[..], 0)); ++ assert_eq!(hex_u32(&b"ff"[..]), Done(&b""[..], 255)); ++ assert_eq!(hex_u32(&b"1be2"[..]), Done(&b""[..], 7138)); ++ assert_eq!(hex_u32(&b"c5a31be2"[..]), Done(&b""[..], 3315801058)); ++ assert_eq!(hex_u32(&b"00c5a31be2"[..]), Done(&b"e2"[..], 12952347)); ++ assert_eq!(hex_u32(&b"c5a31be201"[..]), Done(&b"01"[..], 3315801058)); ++ assert_eq!(hex_u32(&b"ffffffff"[..]), Done(&b""[..], 4294967295)); ++ assert_eq!(hex_u32(&b"0x1be2"[..]), Done(&b"x1be2"[..], 0)); ++ } ++ ++ #[test] ++ fn end_of_input() { ++ let not_over = &b"Hello, world!"[..]; ++ let is_over = &b""[..]; ++ ++ let res_not_over = eof(not_over); ++ assert_eq!(res_not_over, Error(Position(ErrorKind::Eof, not_over))); ++ ++ let res_over = eof(is_over); ++ assert_eq!(res_over, Done(is_over, is_over)); ++ } ++ ++ #[test] ++ fn configurable_endianness() { ++ named!(be_tst16, u16!(true)); ++ named!(le_tst16, u16!(false)); ++ assert_eq!(be_tst16(&[0x80, 0x00]), Done(&b""[..], 32768_u16)); ++ assert_eq!(le_tst16(&[0x80, 0x00]), Done(&b""[..], 128_u16)); ++ ++ named!(be_tst32, u32!(true)); ++ named!(le_tst32, u32!(false)); ++ assert_eq!(be_tst32(&[0x12, 0x00, 0x60, 0x00]), Done(&b""[..], 302014464_u32)); ++ assert_eq!(le_tst32(&[0x12, 0x00, 0x60, 0x00]), Done(&b""[..], 6291474_u32)); ++ ++ named!(be_tst64, u64!(true)); ++ named!(le_tst64, u64!(false)); ++ assert_eq!(be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 1297142246100992000_u64)); ++ assert_eq!(le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 36028874334666770_u64)); ++ ++ named!(be_tsti16, i16!(true)); ++ named!(le_tsti16, i16!(false)); ++ assert_eq!(be_tsti16(&[0x00, 0x80]), Done(&b""[..], 128_i16)); ++ assert_eq!(le_tsti16(&[0x00, 0x80]), Done(&b""[..], -32768_i16)); ++ ++ named!(be_tsti32, i32!(true)); ++ named!(le_tsti32, i32!(false)); ++ assert_eq!(be_tsti32(&[0x00, 0x12, 0x60, 0x00]), Done(&b""[..], 1204224_i32)); ++ assert_eq!(le_tsti32(&[0x00, 0x12, 0x60, 0x00]), Done(&b""[..], 6296064_i32)); ++ ++ named!(be_tsti64, i64!(true)); ++ named!(le_tsti64, i64!(false)); ++ assert_eq!(be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 71881672479506432_i64)); ++ assert_eq!(le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 36028874334732032_i64)); ++ ++ } ++ ++ #[test] ++ fn manual_configurable_endianness_test() { ++ let x = 1; ++ let int_parse: Box IResult<&[u8], u16> > = if x == 2 { ++ Box::new(be_u16) ++ } else { ++ Box::new(le_u16) ++ }; ++ println!("{:?}", int_parse(&b"3"[..])); ++ assert_eq!(int_parse(&[0x80, 0x00]), Done(&b""[..], 128_u16)); ++ } ++ ++ #[allow(dead_code)] ++ fn custom_error(input: &[u8]) -> IResult<&[u8], &[u8], ()> { ++ fix_error!(input, (), alphanumeric) ++ } ++ ++ #[test] ++ fn hex_digit_test() { ++ let empty = &b""[..]; ++ ++ let i = &b"0123456789abcdefABCDEF"[..]; ++ assert_eq!(hex_digit(i), Done(empty, i)); ++ ++ let i = &b"g"[..]; ++ assert_eq!(hex_digit(i), Error(Position(ErrorKind::HexDigit,i))); ++ ++ let i = &b"G"[..]; ++ assert_eq!(hex_digit(i), Error(Position(ErrorKind::HexDigit,i))); ++ ++ assert!(is_hex_digit(b'0')); ++ assert!(is_hex_digit(b'9')); ++ assert!(is_hex_digit(b'a')); ++ assert!(is_hex_digit(b'f')); ++ assert!(is_hex_digit(b'A')); ++ assert!(is_hex_digit(b'F')); ++ assert!(!is_hex_digit(b'g')); ++ assert!(!is_hex_digit(b'G')); ++ assert!(!is_hex_digit(b'/')); ++ assert!(!is_hex_digit(b':')); ++ assert!(!is_hex_digit(b'@')); ++ assert!(!is_hex_digit(b'\x60')); ++ } ++ ++ #[test] ++ fn oct_digit_test() { ++ let empty = &b""[..]; ++ ++ let i = &b"01234567"[..]; ++ assert_eq!(oct_digit(i), Done(empty, i)); ++ ++ let i = &b"8"[..]; ++ assert_eq!(oct_digit(i), Error(Position(ErrorKind::OctDigit,i))); ++ ++ assert!(is_oct_digit(b'0')); ++ assert!(is_oct_digit(b'7')); ++ assert!(!is_oct_digit(b'8')); ++ assert!(!is_oct_digit(b'9')); ++ assert!(!is_oct_digit(b'a')); ++ assert!(!is_oct_digit(b'A')); ++ assert!(!is_oct_digit(b'/')); ++ assert!(!is_oct_digit(b':')); ++ assert!(!is_oct_digit(b'@')); ++ assert!(!is_oct_digit(b'\x60')); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/regexp.rs third_party/rust/nom-1.2.4/src/regexp.rs +new file mode 100644 +index 000000000000..17f8ede1a3f7 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/regexp.rs +@@ -0,0 +1,644 @@ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! regex ( ++ ($re: ident, $s:expr) => ( ++ lazy_static! { ++ static ref $re: ::regex::Regex = ::regex::Regex::new($s).unwrap(); ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! regex_bytes ( ++ ($re: ident, $s:expr) => ( ++ lazy_static! { ++ static ref $re: ::regex::bytes::Regex = ::regex::bytes::Regex::new($s).unwrap(); ++ } ++ ); ++); ++ ++ ++/// `re_match!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the whole input if a match is found ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_match ( ++ ($i:expr, $re:expr) => ( ++ { ++ use $crate::InputLength; ++ let re = ::regex::Regex::new($re).unwrap(); ++ if re.is_match($i) { ++ $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_match_static!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the whole input if a match is found. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_match_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ use $crate::InputLength; ++ regex!(RE, $re); ++ if RE.is_match($i) { ++ $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ } ++ } ++ ) ++); ++ ++/// `re_bytes_match!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the whole input if a match is found ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_bytes_match ( ++ ($i:expr, $re:expr) => ( ++ { ++ use $crate::InputLength; ++ let re = ::regex::bytes::Regex::new($re).unwrap(); ++ if re.is_match($i) { ++ $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_bytes_match_static!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the whole input if a match is found. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_bytes_match_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ use $crate::InputLength; ++ regex_bytes!(RE, $re); ++ if RE.is_match($i) { ++ $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ } ++ } ++ ) ++); ++ ++/// `re_find!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the first match ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_find ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::Regex::new($re).unwrap(); ++ if let Some((begin, end)) = re.find($i) { ++ $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_find_static!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the first match. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_find_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex!(RE, $re); ++ if let Some((begin, end)) = RE.find($i) { ++ $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ } ++ } ++ ++ ) ++); ++ ++/// `re_bytes_find!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the first match ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_bytes_find ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::bytes::Regex::new($re).unwrap(); ++ if let Some((begin, end)) = re.find($i) { ++ $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_bytes_find!(regexp) => &[T] -> IResult<&[T], &[T]>` ++/// Returns the first match. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_bytes_find_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex_bytes!(RE, $re); ++ if let Some((begin, end)) = RE.find($i) { ++ $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ } ++ } ++ ++ ) ++); ++ ++/// `re_matches!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns all the matched parts ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_matches ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::Regex::new($re).unwrap(); ++ let v: Vec<&str> = re.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_matches_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns all the matched parts. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_matches_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex!(RE, $re); ++ let v: Vec<&str> = RE.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ } ++ } ++ ) ++); ++ ++/// `re_bytes_matches!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns all the matched parts ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_bytes_matches ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::bytes::Regex::new($re).unwrap(); ++ let v: Vec<&[u8]> = re.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_bytes_matches_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns all the matched parts. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_bytes_matches_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex_bytes!(RE, $re); ++ let v: Vec<&[u8]> = RE.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ } ++ } ++ ) ++); ++ ++/// `re_capture!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns the first capture group ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_capture ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::Regex::new($re).unwrap(); ++ if let Some(c) = re.captures($i) { ++ let v:Vec<&str> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_capture_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns the first capture group. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_capture_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex!(RE, $re); ++ if let Some(c) = RE.captures($i) { ++ let v:Vec<&str> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++/// `re_bytes_capture!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns the first capture group ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_bytes_capture ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::bytes::Regex::new($re).unwrap(); ++ if let Some(c) = re.captures($i) { ++ let v:Vec<&[u8]> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_bytes_capture_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` ++/// Returns the first capture group. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_bytes_capture_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex_bytes!(RE, $re); ++ if let Some(c) = RE.captures($i) { ++ let v:Vec<&[u8]> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let offset = { ++ let end = v.last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++/// `re_captures!(regexp) => &[T] -> IResult<&[T], Vec>>` ++/// Returns all the capture groups ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_captures ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::Regex::new($re).unwrap(); ++ let v:Vec> = re.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap().last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_captures_static!(regexp) => &[T] -> IResult<&[T], Vec>>` ++/// Returns all the capture groups. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_captures_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex!(RE, $re); ++ let v:Vec> = RE.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap().last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++/// `re_bytes_captures!(regexp) => &[T] -> IResult<&[T], Vec>>` ++/// Returns all the capture groups ++/// ++/// requires the `regexp` feature ++#[macro_export] ++macro_rules! re_bytes_captures ( ++ ($i:expr, $re:expr) => ( ++ { ++ let re = ::regex::bytes::Regex::new($re).unwrap(); ++ let v:Vec> = re.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap().last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++ ++#[cfg(feature = "regexp_macros")] ++/// `re_bytes_captures_static!(regexp) => &[T] -> IResult<&[T], Vec>>` ++/// Returns all the capture groups. Regular expression calculated at compile time ++/// ++/// requires the `regexp_macros` feature ++#[macro_export] ++macro_rules! re_bytes_captures_static ( ++ ($i:expr, $re:expr) => ( ++ { ++ regex_bytes!(RE, $re); ++ let v:Vec> = RE.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ if v.len() != 0 { ++ let offset = { ++ let end = v.last().unwrap().last().unwrap(); ++ end.as_ptr() as usize + end.len() - $i.as_ptr() as usize ++ }; ++ $crate::IResult::Done(&$i[offset..], v) ++ } else { ++ $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ } ++ } ++ ) ++); ++#[cfg(test)] ++mod tests { ++ use internal::IResult::*; ++ use internal::Err::*; ++ use util::ErrorKind; ++ ++ #[test] ++ fn re_match() { ++ named!(rm<&str,&str>, re_match!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm("2015-09-07blah"), Done("", "2015-09-07blah")); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_match_static() { ++ named!(rm<&str,&str>, re_match_static!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm("2015-09-07blah"), Done("", "2015-09-07blah")); ++ } ++ ++ #[test] ++ fn re_find() { ++ named!(rm<&str,&str>, re_find!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm("2015-09-07blah"), Done("blah", "2015-09-07")); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_find_static() { ++ named!(rm<&str,&str>, re_find_static!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm("2015-09-07blah"), Done("blah", "2015-09-07")); ++ } ++ ++ #[test] ++ fn re_matches() { ++ named!(rm< &str,Vec<&str> >, re_matches!(r"\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm("2015-09-07"), Done("", vec!["2015-09-07"])); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm("aaa2015-09-07blah2015-09-09pouet"), Done("pouet", vec!["2015-09-07", "2015-09-09"])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_matches_static() { ++ named!(rm< &str,Vec<&str> >, re_matches_static!(r"\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm("2015-09-07"), Done("", vec!["2015-09-07"])); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm("aaa2015-09-07blah2015-09-09pouet"), Done("pouet", vec!["2015-09-07", "2015-09-09"])); ++ } ++ ++ #[test] ++ fn re_capture() { ++ named!(rm< &str,Vec<&str> >, re_capture!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41"), Done(" world regex 0.1.41", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_capture_static() { ++ named!(rm< &str,Vec<&str> >, re_capture_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41"), Done(" world regex 0.1.41", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); ++ } ++ ++ #[test] ++ fn re_captures() { ++ named!(rm< &str,Vec> >, re_captures!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec![vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]])); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41 aaa"), Done(" aaa", vec![ ++ vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"], ++ vec!["regex 0.1.41", "regex", "0.1.41", "0", "1", "41"], ++ ])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_captures_static() { ++ named!(rm< &str,Vec> >, re_captures_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec![vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]])); ++ assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41 aaa"), Done(" aaa", vec![ ++ vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"], ++ vec!["regex 0.1.41", "regex", "0.1.41", "0", "1", "41"], ++ ])); ++ } ++ ++ #[test] ++ fn re_bytes_match() { ++ named!(rm, re_bytes_match!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b""[..], &b"2015-09-07blah"[..])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_bytes_match_static() { ++ named!(rm, re_bytes_match_static!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b""[..], &b"2015-09-07blah"[..])); ++ } ++ ++ #[test] ++ fn re_bytes_find() { ++ named!(rm, re_bytes_find!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b"blah"[..], &b"2015-09-07"[..])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_bytes_find_static() { ++ named!(rm, re_bytes_find_static!(r"^\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b"blah"[..], &b"2015-09-07"[..])); ++ } ++ ++ #[test] ++ fn re_bytes_matches() { ++ named!(rm >, re_bytes_matches!(r"\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], vec![&b"2015-09-07"[..]])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm(&b"aaa2015-09-07blah2015-09-09pouet"[..]), Done(&b"pouet"[..], vec![&b"2015-09-07"[..], &b"2015-09-09"[..]])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_bytes_matches_static() { ++ named!(rm >, re_bytes_matches_static!(r"\d{4}-\d{2}-\d{2}")); ++ assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], vec![&b"2015-09-07"[..]])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm(&b"aaa2015-09-07blah2015-09-09pouet"[..]), Done(&b"pouet"[..], vec![&b"2015-09-07"[..], &b"2015-09-09"[..]])); ++ } ++ ++ #[test] ++ fn re_bytes_capture() { ++ named!(rm >, re_bytes_capture!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41"[..]), Done(&b" world regex 0.1.41"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_bytes_capture_static() { ++ named!(rm< Vec<&[u8]> >, re_bytes_capture_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41"[..]), Done(&b" world regex 0.1.41"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); ++ } ++ ++ #[test] ++ fn re_bytes_captures() { ++ named!(rm< Vec> >, re_bytes_captures!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]]])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41 aaa"[..]), Done(&b" aaa"[..], vec![ ++ vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]], ++ vec![&b"regex 0.1.41"[..], &b"regex"[..], &b"0.1.41"[..], &b"0"[..], &b"1"[..], &b"41"[..]], ++ ])); ++ } ++ ++ #[cfg(feature = "regexp_macros")] ++ #[test] ++ fn re_bytes_captures_static() { ++ named!(rm< Vec> >, re_bytes_captures_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]]])); ++ assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41 aaa"[..]), Done(&b" aaa"[..], vec![ ++ vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]], ++ vec![&b"regex 0.1.41"[..], &b"regex"[..], &b"0.1.41"[..], &b"0"[..], &b"1"[..], &b"41"[..]], ++ ])); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/str.rs third_party/rust/nom-1.2.4/src/str.rs +new file mode 100644 +index 000000000000..768786edaba1 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/str.rs +@@ -0,0 +1,734 @@ ++//! Parsers and helper functions operating on strings, especially useful when writing parsers for ++//! text-based formats. ++ ++/// `tag_s!(&str) => &str -> IResult<&str, &str>` ++/// declares a string as a suite to recognize ++/// ++/// consumes the recognized characters ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self,Done}; ++/// # fn main() { ++/// fn test(input: &str) -> IResult<&str, &str> { ++/// tag_s!(input, "abcd") ++/// } ++/// let r = test("abcdefgh"); ++/// assert_eq!(r, Done("efgh", "abcd")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! tag_s ( ++ ($i:expr, $tag: expr) => ( ++ { ++ let res: $crate::IResult<_,_> = if $tag.len() > $i.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($tag.len())) ++ //} else if &$i[0..$tag.len()] == $tag { ++ } else if ($i).starts_with($tag) { ++ $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagStr, $i)) ++ }; ++ res ++ } ++ ); ++); ++ ++/// `take_s!(nb) => &str -> IResult<&str, &str>` ++/// generates a parser consuming the specified number of characters ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// // Desmond parser ++/// named!(take5<&str,&str>, take_s!( 5 ) ); ++/// ++/// let a = "abcdefgh"; ++/// ++/// assert_eq!(take5(a), Done("fgh", "abcde")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! take_s ( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res: $crate::IResult<_,_> = if $i.chars().count() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ let mut offset = $i.len(); ++ let mut count = 0; ++ for (o, _) in $i.char_indices() { ++ if count == cnt { ++ offset = o; ++ break; ++ } ++ count += 1; ++ } ++ $crate::IResult::Done(&$i[offset..], &$i[..offset]) ++ }; ++ res ++ } ++ ); ++); ++ ++ ++/// `is_not_s!(&str) => &str -> IResult<&str, &str>` ++/// returns the longest list of characters that do not appear in the provided array ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!( not_space<&str,&str>, is_not_s!( " \t\r\n" ) ); ++/// ++/// let r = not_space("abcdefgh\nijkl"); ++/// assert_eq!(r, Done("\nijkl", "abcdefgh")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! is_not_s ( ++ ($input:expr, $arr:expr) => ( ++ { ++ use std::collections::HashSet; ++ let set: HashSet = $arr.chars().collect(); ++ let mut offset = $input.len(); ++ for (o, c) in $input.char_indices() { ++ if set.contains(&c) { ++ offset = o; ++ break; ++ } ++ } ++ if offset == 0 { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsAStr,$input)) ++ } else if offset < $input.len() { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Done("", $input) ++ } ++ } ++ ); ++); ++ ++/// `is_a_s!(&str) => &str -> IResult<&str, &str>` ++/// returns the longest list of characters that appear in the provided array ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(abcd<&str, &str>, is_a_s!( "abcd" )); ++/// ++/// let r1 = abcd("aaaaefgh"); ++/// assert_eq!(r1, Done("efgh", "aaaa")); ++/// ++/// let r2 = abcd("dcbaefgh"); ++/// assert_eq!(r2, Done("efgh", "dcba")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! is_a_s ( ++ ($input:expr, $arr:expr) => ( ++ { ++ use std::collections::HashSet; ++ let set: HashSet = $arr.chars().collect(); ++ let mut offset = $input.len(); ++ for (o, c) in $input.char_indices() { ++ if !set.contains(&c) { ++ offset = o; ++ break; ++ } ++ } ++ if offset == 0 { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsAStr,$input)) ++ } else if offset < $input.len() { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Done("", $input) ++ } ++ } ++ ); ++); ++ ++ ++/// `take_while_s!(char -> bool) => &str -> IResult<&str, &str>` ++/// returns the longest list of characters until the provided function fails. ++/// ++/// The argument is either a function `char -> bool` or a macro returning a `bool ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::is_alphanumeric; ++/// # fn main() { ++/// fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) } ++/// named!( alpha<&str,&str>, take_while_s!( alphabetic ) ); ++/// ++/// let r = alpha("abcd\nefgh"); ++/// assert_eq!(r, Done("\nefgh", "abcd")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! take_while_s ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let mut offset = $input.len(); ++ for (o, c) in $input.char_indices() { ++ if !$submac!(c, $($args)*) { ++ offset = o; ++ break; ++ } ++ } ++ if offset < $input.len() { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Done("", $input) ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_while_s!($input, call!($f)); ++ ); ++); ++ ++/// `take_while1_s!(char -> bool) => &str -> IResult<&str, &str>` ++/// returns the longest (non empty) list of characters until the provided function fails. ++/// ++/// The argument is either a function `char -> bool` or a macro returning a `bool` ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::is_alphanumeric; ++/// # fn main() { ++/// fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) } ++/// named!( alpha<&str,&str>, take_while1_s!( alphabetic ) ); ++/// ++/// let r = alpha("abcd\nefgh"); ++/// assert_eq!(r, Done("\nefgh", "abcd")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! take_while1_s ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let mut offset = $input.len(); ++ for (o, c) in $input.char_indices() { ++ if !$submac!(c, $($args)*) { ++ offset = o; ++ break; ++ } ++ } ++ if offset == 0 { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1Str,$input)) ++ } else if offset < $input.len() { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Done("", $input) ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_while1_s!($input, call!($f)); ++ ); ++); ++ ++ ++/// `take_till_s!(&str -> bool) => &str -> IResult<&str, &str>` ++/// returns the longest list of characters until the provided function succeeds ++/// ++/// The argument is either a function `char -> bool` or a macro returning a `bool ++#[macro_export] ++macro_rules! take_till_s ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ ++ { ++ let mut offset = $input.len(); ++ for (o, c) in $input.char_indices() { ++ if $submac!(c, $($args)*) { ++ offset = o; ++ break; ++ } ++ } ++ if offset < $input.len() { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Done("", $input) ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_till_s!($input, call!($f)); ++ ); ++); ++ ++/// `take_until_and_consume_s!(&str) => &str -> IResult<&str, &str>` ++/// generates a parser consuming all chars until the specified string is found and consumes it ++#[macro_export] ++macro_rules! take_until_and_consume_s ( ++ ($input:expr, $substr:expr) => ( ++ { ++ #[inline(always)] ++ fn shift_window_and_cmp(window: & mut ::std::vec::Vec, c: char, substr_vec: & ::std::vec::Vec) -> bool { ++ window.push(c); ++ if window.len() > substr_vec.len() { ++ window.remove(0); ++ } ++ window == substr_vec ++ } ++ let res: $crate::IResult<_, _> = if $substr.len() > $input.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($substr.len())) ++ } else { ++ let substr_vec: ::std::vec::Vec = $substr.chars().collect(); ++ let mut window: ::std::vec::Vec = vec![]; ++ let mut offset = $input.len(); ++ let mut parsed = false; ++ for (o, c) in $input.char_indices() { ++ if parsed { ++ // The easiest way to get the byte offset of the char after the found string ++ offset = o; ++ break; ++ } ++ if shift_window_and_cmp(& mut window, c, &substr_vec) { ++ parsed = true; ++ } ++ } ++ if parsed { ++ if offset < $input.len() { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Done("", $input) ++ } ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilAndConsumeStr,$input)) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++/// `take_until_s!(&str) => &str -> IResult<&str, &str>` ++/// generates a parser consuming all chars until the specified string is found and leaves it in the remaining input ++#[macro_export] ++macro_rules! take_until_s ( ++ ($input:expr, $substr:expr) => ( ++ { ++ #[inline(always)] ++ fn shift_window_and_cmp(window: & mut Vec, c: char, substr_vec: &Vec) -> bool { ++ window.push(c); ++ if window.len() > substr_vec.len() { ++ window.remove(0); ++ } ++ window == substr_vec ++ } ++ let res: $crate::IResult<&str, &str> = if $substr.len() > $input.len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($substr.len())) ++ } else { ++ let substr_vec: Vec = $substr.chars().collect(); ++ let mut window: Vec = vec![]; ++ let mut offset = $input.len(); ++ let mut parsed = false; ++ for (o, c) in $input.char_indices() { ++ if shift_window_and_cmp(& mut window, c, &substr_vec) { ++ parsed = true; ++ window.pop(); ++ let window_len: usize = window.iter() ++ .map(|x| x.len_utf8()) ++ .fold(0, |x, y| x + y); ++ offset = o - window_len; ++ break; ++ } ++ } ++ if parsed { ++ $crate::IResult::Done(&$input[offset..], &$input[..offset]) ++ } else { ++ $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilStr,$input)) ++ } ++ }; ++ res ++ } ++ ); ++); ++ ++#[cfg(test)] ++mod test { ++ use ::IResult; ++ ++ #[test] ++ fn tag_str_succeed() { ++ const INPUT: &'static str = "Hello World!"; ++ const TAG: &'static str = "Hello"; ++ fn test(input: &str) -> IResult<&str, &str> { ++ tag_s!(input, TAG) ++ } ++ ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == " World!", "Parser `tag_s` consumed leftover input."); ++ assert!(output == TAG, ++ "Parser `tag_s` doesn't return the tag it matched on success. \ ++ Expected `{}`, got `{}`.", TAG, output); ++ }, ++ other => panic!("Parser `tag_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn tag_str_incomplete() { ++ const INPUT: &'static str = "Hello"; ++ const TAG: &'static str = "Hello World!"; ++ ++ match tag_s!(INPUT, TAG) { ++ IResult::Incomplete(_) => (), ++ other => { ++ panic!("Parser `tag_s` didn't require more input when it should have. \ ++ Got `{:?}`.", other); ++ } ++ }; ++ } ++ ++ #[test] ++ fn tag_str_error() { ++ const INPUT: &'static str = "Hello World!"; ++ const TAG: &'static str = "Random"; // TAG must be closer than INPUT. ++ ++ match tag_s!(INPUT, TAG) { ++ IResult::Error(_) => (), ++ other => { ++ panic!("Parser `tag_s` didn't fail when it should have. Got `{:?}`.`", other); ++ }, ++ }; ++ } ++ ++ #[test] ++ fn take_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ ++ match take_s!(INPUT, 9) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_s` consumed leftover input. Leftover `{}`.", extra); ++ assert!(output == CONSUMED, ++ "Parser `take_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.", ++ CONSUMED, output); ++ }, ++ other => panic!("Parser `take_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_until_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇ∂áƒƭèř"; ++ const FIND: &'static str = "ÂßÇ∂"; ++ const CONSUMED: &'static str = "βèƒôřè"; ++ const LEFTOVER: &'static str = "ÂßÇ∂áƒƭèř"; ++ ++ match take_until_s!(INPUT, FIND) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_until_s`\ ++ consumed leftover input. Leftover `{}`.", extra); ++ assert!(output == CONSUMED, "Parser `take_until_s`\ ++ doens't return the string it consumed on success. Expected `{}`, got `{}`.", ++ CONSUMED, output); ++ } ++ other => panic!("Parser `take_until_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_s_incomplete() { ++ const INPUT: &'static str = "βèƒôřèÂßÇá"; ++ ++ match take_s!(INPUT, 13) { ++ IResult::Incomplete(_) => (), ++ other => panic!("Parser `take_s` didn't require more input when it should have. \ ++ Got `{:?}`.", other), ++ } ++ } ++ ++ use internal::IResult::{Done, Error}; ++ use internal::Err::Position; ++ use util::ErrorKind; ++ ++ pub fn is_alphabetic(c:char) -> bool { ++ (c as u8 >= 0x41 && c as u8 <= 0x5A) || (c as u8 >= 0x61 && c as u8 <= 0x7A) ++ } ++ #[test] ++ fn take_while_s() { ++ named!(f<&str,&str>, take_while_s!(is_alphabetic)); ++ let a = ""; ++ let b = "abcd"; ++ let c = "abcd123"; ++ let d = "123"; ++ ++ assert_eq!(f(&a[..]), Done(&a[..], &a[..])); ++ assert_eq!(f(&b[..]), Done(&a[..], &b[..])); ++ assert_eq!(f(&c[..]), Done(&d[..], &b[..])); ++ assert_eq!(f(&d[..]), Done(&d[..], &a[..])); ++ } ++ ++ #[test] ++ fn take_while1_s() { ++ named!(f<&str,&str>, take_while1_s!(is_alphabetic)); ++ let a = ""; ++ let b = "abcd"; ++ let c = "abcd123"; ++ let d = "123"; ++ ++ assert_eq!(f(&a[..]), Error(Position(ErrorKind::TakeWhile1Str, &""[..]))); ++ assert_eq!(f(&b[..]), Done(&a[..], &b[..])); ++ assert_eq!(f(&c[..]), Done(&"123"[..], &b[..])); ++ assert_eq!(f(&d[..]), Error(Position(ErrorKind::TakeWhile1Str, &d[..]))); ++ } ++ ++ #[test] ++ fn take_till_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ fn till_s(c: char) -> bool { ++ c == 'á' ++ } ++ fn test(input: &str) -> IResult<&str, &str> { ++ take_till_s!(input, till_s) ++ } ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_till_s` consumed leftover input."); ++ assert!(output == CONSUMED, ++ "Parser `take_till_s` doesn't return the string it consumed on success. \ ++ Expected `{}`, got `{}`.", CONSUMED, output); ++ }, ++ other => panic!("Parser `take_till_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_while_s_succeed_none() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const CONSUMED: &'static str = ""; ++ const LEFTOVER: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ fn while_s(c: char) -> bool { ++ c == '9' ++ } ++ fn test(input: &str) -> IResult<&str, &str> { ++ take_while_s!(input, while_s) ++ } ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_while_s` consumed leftover input."); ++ assert!(output == CONSUMED, ++ "Parser `take_while_s` doesn't return the string it consumed on success. \ ++ Expected `{}`, got `{}`.", CONSUMED, output); ++ }, ++ other => panic!("Parser `take_while_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn is_not_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const AVOID: &'static str = "£úçƙ¥á"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ fn test(input: &str) -> IResult<&str, &str> { ++ is_not_s!(input, AVOID) ++ } ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `is_not_s` consumed leftover input. Leftover `{}`.", extra); ++ assert!(output == CONSUMED, ++ "Parser `is_not_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.", ++ CONSUMED, output); ++ }, ++ other => panic!("Parser `is_not_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_until_and_consume_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const FIND: &'static str = "ÂßÇ"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ ++ match take_until_and_consume_s!(INPUT, FIND) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_until_and_consume_s`\ ++ consumed leftover input. Leftover `{}`.", extra); ++ assert!(output == CONSUMED, "Parser `take_until_and_consume_s`\ ++ doens't return the string it consumed on success. Expected `{}`, got `{}`.", ++ CONSUMED, output); ++ } ++ other => panic!("Parser `take_until_and_consume_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_while_s_succeed_some() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ fn while_s(c: char) -> bool { ++ c == 'β' || c == 'è' || c == 'ƒ' || c == 'ô' || c == 'ř' || ++ c == 'è' || c == 'Â' || c == 'ß' || c == 'Ç' ++ } ++ fn test(input: &str) -> IResult<&str, &str> { ++ take_while_s!(input, while_s) ++ } ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_while_s` consumed leftover input."); ++ assert!(output == CONSUMED, ++ "Parser `take_while_s` doesn't return the string it consumed on success. \ ++ Expected `{}`, got `{}`.", CONSUMED, output); ++ }, ++ other => panic!("Parser `take_while_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn is_not_s_fail() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const AVOID: &'static str = "βúçƙ¥"; ++ fn test(input: &str) -> IResult<&str, &str> { ++ is_not_s!(input, AVOID) ++ } ++ match test(INPUT) { ++ IResult::Error(_) => (), ++ other => panic!("Parser `is_not_s` didn't fail when it should have. Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_while1_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ fn while1_s(c: char) -> bool { ++ c == 'β' || c == 'è' || c == 'ƒ' || c == 'ô' || c == 'ř' || ++ c == 'è' || c == 'Â' || c == 'ß' || c == 'Ç' ++ } ++ fn test(input: &str) -> IResult<&str, &str> { ++ take_while1_s!(input, while1_s) ++ } ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `take_while1_s` consumed leftover input."); ++ assert!(output == CONSUMED, ++ "Parser `take_while1_s` doesn't return the string it consumed on success. \ ++ Expected `{}`, got `{}`.", CONSUMED, output); ++ }, ++ other => panic!("Parser `take_while1_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_until_and_consume_s_incomplete() { ++ const INPUT: &'static str = "βèƒôřè"; ++ const FIND: &'static str = "βèƒôřèÂßÇ"; ++ ++ match take_until_and_consume_s!(INPUT, FIND) { ++ IResult::Incomplete(_) => (), ++ other => panic!("Parser `take_until_and_consume_s` didn't require more input when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_until_s_incomplete() { ++ const INPUT: &'static str = "βèƒôřè"; ++ const FIND: &'static str = "βèƒôřèÂßÇ"; ++ ++ match take_until_s!(INPUT, FIND) { ++ IResult::Incomplete(_) => (), ++ other => panic!("Parser `take_until_s` didn't require more input when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn is_a_s_succeed() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const MATCH: &'static str = "βèƒôřèÂßÇ"; ++ const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const LEFTOVER: &'static str = "áƒƭèř"; ++ fn test(input: &str) -> IResult<&str, &str> { ++ is_a_s!(input, MATCH) ++ } ++ match test(INPUT) { ++ IResult::Done(extra, output) => { ++ assert!(extra == LEFTOVER, "Parser `is_a_s` consumed leftover input. Leftover `{}`.", extra); ++ assert!(output == CONSUMED, ++ "Parser `is_a_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.", ++ CONSUMED, output); ++ }, ++ other => panic!("Parser `is_a_s` didn't succeed when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_while1_s_fail() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ fn while1_s(c: char) -> bool { ++ c == '9' ++ } ++ fn test(input: &str) -> IResult<&str, &str> { ++ take_while1_s!(input, while1_s) ++ } ++ match test(INPUT) { ++ IResult::Error(_) => (), ++ other => panic!("Parser `take_while1_s` didn't fail when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn is_a_s_fail() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const MATCH: &'static str = "Ûñℓúçƙ¥"; ++ fn test(input: &str) -> IResult<&str, &str> { ++ is_a_s!(input, MATCH) ++ } ++ match test(INPUT) { ++ IResult::Error(_) => (), ++ other => panic!("Parser `is_a_s` didn't fail when it should have. Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_until_and_consume_s_error() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const FIND: &'static str = "Ráñδô₥"; ++ ++ match take_until_and_consume_s!(INPUT, FIND) { ++ IResult::Error(_) => (), ++ other => panic!("Parser `take_until_and_consume_s` didn't fail when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++ ++ #[test] ++ fn take_until_s_error() { ++ const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; ++ const FIND: &'static str = "Ráñδô₥"; ++ ++ match take_until_s!(INPUT, FIND) { ++ IResult::Error(_) => (), ++ other => panic!("Parser `take_until_and_consume_s` didn't fail when it should have. \ ++ Got `{:?}`.", other), ++ }; ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/stream.rs third_party/rust/nom-1.2.4/src/stream.rs +new file mode 100644 +index 000000000000..38d5c870c938 +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/stream.rs +@@ -0,0 +1,1031 @@ ++/// Context: ++/// * Rust does not have tail call optimization, so we cannot recurse wildly ++/// * data lifetimes makes sure that the result of a function applied to a producer cannot live longer than the producer's data (unless there is cloning) ++/// * previous implementation of Producer and Consumer spent its time copying buffers ++/// * the old Consumer was handling everything and buffering data. The new design has the producer handle data, but the consumer makes seeking decision ++use std::io::{self,Read,Write,Seek,SeekFrom}; ++use std::fs::File; ++use std::path::Path; ++use std::ptr; ++use std::iter::repeat; ++use internal::Needed; ++ ++//pub type Computation = Box) -> (I,Consumer)>; ++ ++#[derive(Debug,Clone)] ++pub enum Input { ++ Element(I), ++ Empty, ++ Eof(Option) ++} ++ ++/// Stores a consumer's current computation state ++#[derive(Debug,Clone)] ++pub enum ConsumerState { ++ /// A value of type O has been produced ++ Done(M,O), ++ /// An error of type E has been encountered ++ Error(E), ++ /// Continue applying, and pass a message of type M to the data source ++ Continue(M) ++} ++ ++impl ConsumerState { ++ pub fn map(&self, f: F) -> ConsumerState where F: FnOnce(O) -> P { ++ match *self { ++ ConsumerState::Error(e) => ConsumerState::Error(e), ++ ConsumerState::Continue(m) => ConsumerState::Continue(m), ++ ConsumerState::Done(m, ref o) => ConsumerState::Done(m, f(o.clone())) ++ } ++ } ++ pub fn flat_map(&self, f: F) -> ConsumerState where F: FnOnce(M, O) -> ConsumerState { ++ match *self { ++ ConsumerState::Error(e) => ConsumerState::Error(e), ++ ConsumerState::Continue(m) => ConsumerState::Continue(m), ++ ConsumerState::Done(m, ref o) => f(m, o.clone()) ++ } ++ } ++} ++/// The Consumer trait wraps a computation and its state ++/// ++/// it depends on the input type I, the produced value's type O, the error type E, and the message type M ++pub trait Consumer { ++ ++ /// implement handle for the current computation, returning the new state of the consumer ++ fn handle(&mut self, input: Input) -> &ConsumerState; ++ /// returns the current state ++ fn state(&self) -> &ConsumerState; ++ ++} ++ ++/// The producer wraps a data source, like file or network, and applies a consumer on it ++/// ++/// it handles buffer copying and reallocation, to provide streaming patterns. ++/// it depends on the input type I, and the message type M. ++/// the consumer can change the way data is produced (for example, to seek in the source) by sending a message of type M. ++pub trait Producer<'b,I,M: 'b> { ++ /// Applies a consumer once on the produced data, and return the consumer's state ++ /// ++ /// a new producer has to implement this method. ++ /// ++ /// WARNING: if the `ConsumerState` generated by your consumer has a reference ++ /// to the input, it will generate borrow checking errors such as ++ /// `error: cannot borrow `producer` as mutable more than once at a time [E0499]`. ++ /// ++ /// It is caused by the producer's ability to refill the input at will, so it can modify ++ /// the input slice the `ConsumerState` is referring to. ++ /// ++ /// To avoid that kind of issue, try to do all the computations on input slices inside the ++ /// `Consumer` chain ++ fn apply<'a, O,E>(&'b mut self, consumer: &'a mut Consumer) -> &'a ConsumerState; ++ ++ /// Applies a consumer once on the produced data, and returns the generated value if there is one ++ fn run<'a: 'b,O,E: 'b>(&'b mut self, consumer: &'a mut Consumer) -> Option<&O> { ++ if let &ConsumerState::Done(_,ref o) = self.apply(consumer) { ++ Some(o) ++ } else { ++ None ++ } ++ } ++ // fn fromFile, FromSocket, fromRead ++} ++ ++/// ProducerRepeat takes a single value, and generates it at each step ++pub struct ProducerRepeat { ++ value: I ++} ++ ++impl<'b,I:Copy,M: 'b> Producer<'b,I,M> for ProducerRepeat { ++ fn apply<'a,O,E>(&'b mut self, consumer: &'a mut Consumer) -> &'a ConsumerState { ++ if { ++ if let &ConsumerState::Continue(_) = consumer.state() { ++ true ++ } else { ++ false ++ } ++ } ++ { ++ consumer.handle(Input::Element(self.value)) ++ } else { ++ consumer.state() ++ } ++ } ++} ++ ++/// A MemProducer generates values from an in memory byte buffer ++/// ++/// it generates data by chunks, and keeps track of how much was consumed. ++/// It can receive messages of type `Move` to handle consumption and seeking ++pub struct MemProducer<'x> { ++ buffer: &'x [u8], ++ chunk_size: usize, ++ length: usize, ++ index: usize ++} ++ ++impl<'x> MemProducer<'x> { ++ pub fn new(buffer: &'x[u8], chunk_size: usize) -> MemProducer { ++ MemProducer { ++ buffer: buffer, ++ chunk_size: chunk_size, ++ length: buffer.len(), ++ index: 0 ++ } ++ } ++} ++ ++#[derive(Debug,Clone,Copy,PartialEq,Eq)] ++pub enum Move { ++ /// indcates how much data was consumed ++ Consume(usize), ++ /// indicates where in the input the consumer must seek ++ Seek(SeekFrom), ++ /// indicates more data is needed ++ Await(Needed) ++} ++ ++impl<'x,'b> Producer<'b,&'x[u8],Move> for MemProducer<'x> { ++ fn apply<'a,O,E>(&'b mut self, consumer: &'a mut Consumer<&'x[u8],O,E,Move>) -> &'a ConsumerState { ++ if { ++ if let &ConsumerState::Continue(ref m) = consumer.state() { ++ match *m { ++ Move::Consume(s) => { ++ if self.length - self.index >= s { ++ self.index += s ++ } else { ++ panic!("cannot consume past the end of the buffer"); ++ } ++ }, ++ Move::Await(a) => { ++ panic!("not handled for now: await({:?}", a); ++ } ++ Move::Seek(SeekFrom::Start(position)) => { ++ if position as usize > self.length { ++ self.index = self.length ++ } else { ++ self.index = position as usize ++ } ++ }, ++ Move::Seek(SeekFrom::Current(offset)) => { ++ let next = if offset >= 0 { ++ (self.index as u64).checked_add(offset as u64) ++ } else { ++ (self.index as u64).checked_sub(-offset as u64) ++ }; ++ match next { ++ None => None, ++ Some(u) => { ++ if u as usize > self.length { ++ self.index = self.length ++ } else { ++ self.index = u as usize ++ } ++ Some(self.index as u64) ++ } ++ }; ++ }, ++ Move::Seek(SeekFrom::End(i)) => { ++ let next = if i < 0 { ++ (self.length as u64).checked_sub(-i as u64) ++ } else { ++ // std::io::SeekFrom documentation explicitly allows ++ // seeking beyond the end of the stream, so we seek ++ // to the end of the content if the offset is 0 or ++ // greater. ++ Some(self.length as u64) ++ }; ++ match next { ++ // std::io:SeekFrom documentation states that it `is an ++ // error to seek before byte 0.' So it's the sensible ++ // thing to refuse to seek on underflow. ++ None => None, ++ Some(u) => { ++ self.index = u as usize; ++ Some(u) ++ } ++ }; ++ } ++ } ++ true ++ } else { ++ false ++ } ++ } ++ { ++ use std::cmp; ++ let end = cmp::min(self.index + self.chunk_size, self.length); ++ consumer.handle(Input::Element(&self.buffer[self.index..end])) ++ } else { ++ consumer.state() ++ } ++ } ++} ++ ++#[derive(Debug,Copy,Clone,PartialEq,Eq)] ++pub enum FileProducerState { ++ Normal, ++ Error, ++ Eof ++} ++ ++#[derive(Debug)] ++pub struct FileProducer { ++ size: usize, ++ file: File, ++ position: usize, ++ v: Vec, ++ start: usize, ++ end: usize, ++ state: FileProducerState, ++} ++ ++impl FileProducer { ++ pub fn new(filename: &str, buffer_size: usize) -> io::Result { ++ File::open(&Path::new(filename)).and_then(|mut f| { ++ f.seek(SeekFrom::Start(0)).map(|_| { ++ let mut v = Vec::with_capacity(buffer_size); ++ v.extend(repeat(0).take(buffer_size)); ++ FileProducer {size: buffer_size, file: f, position: 0, v: v, start: 0, end: 0, state: FileProducerState::Normal } ++ }) ++ }) ++ } ++ ++ pub fn state(&self) -> FileProducerState { ++ self.state ++ } ++ ++ // FIXME: should handle refill until a certain size is obtained ++ pub fn refill(&mut self) -> Option { ++ shift(&mut self.v, self.start, self.end); ++ self.end = self.end - self.start; ++ self.start = 0; ++ match self.file.read(&mut self.v[self.end..]) { ++ Err(_) => { ++ self.state = FileProducerState::Error; ++ None ++ }, ++ Ok(n) => { ++ //println!("read: {} bytes\ndata:\n{:?}", n, &self.v); ++ if n == 0 { ++ self.state = FileProducerState::Eof; ++ } ++ self.end += n; ++ Some(0) ++ } ++ } ++ } ++ ++ /// Resize the internal buffer, copy the data to the new one and returned how much data was copied ++ /// ++ /// If the new buffer is smaller, the prefix will be copied, and the rest of the data will be dropped ++ pub fn resize(&mut self, s: usize) -> usize { ++ let mut v = vec![0; s]; ++ let length = self.end - self.start; ++ ++ let size = if length <= s { length } else { s }; ++ ++ // Use `Write` for `&mut [u8]` ++ (&mut v[..]).write(&self.v[self.start..self.start + size]).unwrap(); ++ ++ self.v = v; ++ self.start = 0; ++ self.end = size; ++ ++ size ++ } ++} ++ ++pub fn shift(s: &mut[u8], start: usize, end: usize) { ++ if start > 0 { ++ unsafe { ++ let length = end - start; ++ ptr::copy( (&s[start..end]).as_ptr(), (&mut s[..length]).as_mut_ptr(), length); ++ } ++ } ++} ++ ++ ++impl<'x> Producer<'x,&'x [u8],Move> for FileProducer { ++ ++ fn apply<'a,O,E>(&'x mut self, consumer: &'a mut Consumer<&'x[u8],O,E,Move>) -> &'a ConsumerState { ++ //consumer.handle(Input::Element(&self.v[self.start..self.end])) ++ //self.my_apply(consumer) ++ if { ++ if let &ConsumerState::Continue(ref m) = consumer.state() { ++ match *m { ++ Move::Consume(s) => { ++ //println!("start: {}, end: {}, consumed: {}", self.start, self.end, s); ++ if self.end - self.start >= s { ++ self.start = self.start + s; ++ self.position = self.position + s; ++ } else { ++ panic!("cannot consume past the end of the buffer"); ++ } ++ if self.start == self.end { ++ self.refill(); ++ } ++ }, ++ Move::Await(_) => { ++ self.refill(); ++ }, ++ ++ // FIXME: naive seeking for now ++ Move::Seek(position) => { ++ let pos = match position { ++ // take into account data in the buffer ++ SeekFrom::Current(c) => SeekFrom::Current(c - (self.end - self.start) as i64), ++ default => default ++ }; ++ match self.file.seek(pos) { ++ Ok(pos) => { ++ //println!("file got seek to position {:?}. New position is {:?}", position, next); ++ self.position = pos as usize; ++ self.start = 0; ++ self.end = 0; ++ self.refill(); ++ }, ++ Err(_) => { ++ self.state = FileProducerState::Error; ++ } ++ } ++ } ++ } ++ true ++ } else { ++ false ++ } ++ } ++ { ++ //println!("producer state: {:?}", self.state); ++ match self.state { ++ FileProducerState::Normal => consumer.handle(Input::Element(&self.v[self.start..self.end])), ++ FileProducerState::Eof => { ++ let slice = &self.v[self.start..self.end]; ++ ++ if slice.is_empty() { ++ consumer.handle(Input::Eof(None)) ++ } else { ++ consumer.handle(Input::Eof(Some(slice))) ++ } ++ } ++ // is it right? ++ FileProducerState::Error => consumer.state() ++ } ++ } else { ++ consumer.state() ++ } ++ } ++} ++ ++ ++use std::marker::PhantomData; ++ ++/// MapConsumer takes a function S -> T and applies it on a consumer producing values of type S ++pub struct MapConsumer<'a, C:'a,R,S,T,E,M,F> { ++ state: ConsumerState, ++ consumer: &'a mut C, ++ f: F, ++ consumer_input_type: PhantomData, ++ f_input_type: PhantomData, ++ f_output_type: PhantomData ++} ++ ++impl<'a,R,S:Clone,T,E:Clone,M:Clone,F:Fn(S) -> T,C:Consumer> MapConsumer<'a,C,R,S,T,E,M,F> { ++ pub fn new(c: &'a mut C, f: F) -> MapConsumer<'a,C,R,S,T,E,M,F> { ++ //let state = c.state(); ++ let initial = match *c.state() { ++ ConsumerState::Done(ref m, ref o) => ConsumerState::Done(m.clone(), f(o.clone())), ++ ConsumerState::Error(ref e) => ConsumerState::Error(e.clone()), ++ ConsumerState::Continue(ref m) => ConsumerState::Continue(m.clone()) ++ }; ++ ++ MapConsumer { ++ state: initial, ++ consumer: c, ++ f: f, ++ consumer_input_type: PhantomData, ++ f_input_type: PhantomData, ++ f_output_type: PhantomData ++ } ++ } ++} ++ ++impl<'a,R,S:Clone,T,E:Clone,M:Clone,F:Fn(S) -> T,C:Consumer> Consumer for MapConsumer<'a,C,R,S,T,E,M,F> { ++ fn handle(&mut self, input: Input) -> &ConsumerState { ++ let res:&ConsumerState = self.consumer.handle(input); ++ self.state = match res { ++ &ConsumerState::Done(ref m, ref o) => ConsumerState::Done(m.clone(), (self.f)(o.clone())), ++ &ConsumerState::Error(ref e) => ConsumerState::Error(e.clone()), ++ &ConsumerState::Continue(ref m) => ConsumerState::Continue(m.clone()) ++ }; ++ &self.state ++ } ++ ++ fn state(&self) -> &ConsumerState { ++ &self.state ++ } ++} ++ ++/// ChainConsumer takes a consumer C1 R -> S, and a consumer C2 S -> T, and makes a consumer R -> T by applying C2 on C1's result ++pub struct ChainConsumer<'a,'b, C1:'a,C2:'b,R,S,T,E,M> { ++ state: ConsumerState, ++ consumer1: &'a mut C1, ++ consumer2: &'b mut C2, ++ input_type: PhantomData, ++ temp_type: PhantomData ++} ++ ++impl<'a,'b,R,S:Clone,T:Clone,E:Clone,M:Clone,C1:Consumer, C2:Consumer> ChainConsumer<'a,'b,C1,C2,R,S,T,E,M> { ++ pub fn new(c1: &'a mut C1, c2: &'b mut C2) -> ChainConsumer<'a,'b,C1,C2,R,S,T,E,M> { ++ let initial = match *c1.state() { ++ ConsumerState::Error(ref e) => ConsumerState::Error(e.clone()), ++ ConsumerState::Continue(ref m) => ConsumerState::Continue(m.clone()), ++ ConsumerState::Done(ref m, ref o) => match *c2.handle(Input::Element(o.clone())) { ++ ConsumerState::Error(ref e) => ConsumerState::Error(e.clone()), ++ ConsumerState::Continue(ref m2) => ConsumerState::Continue(m2.clone()), ++ ConsumerState::Done(_,ref o2) => ConsumerState::Done(m.clone(), o2.clone()) ++ } ++ }; ++ ++ ChainConsumer { ++ state: initial, ++ consumer1: c1, ++ consumer2: c2, ++ input_type: PhantomData, ++ temp_type: PhantomData ++ } ++ } ++} ++ ++impl<'a,'b,R,S:Clone,T:Clone,E:Clone,M:Clone,C1:Consumer, C2:Consumer> Consumer for ChainConsumer<'a,'b,C1,C2,R,S,T,E,M> { ++ fn handle(&mut self, input: Input) -> &ConsumerState { ++ let res:&ConsumerState = self.consumer1.handle(input); ++ self.state = match *res { ++ ConsumerState::Error(ref e) => ConsumerState::Error(e.clone()), ++ ConsumerState::Continue(ref m) => ConsumerState::Continue(m.clone()), ++ ConsumerState::Done(ref m, ref o) => match *self.consumer2.handle(Input::Element(o.clone())) { ++ ConsumerState::Error(ref e) => ConsumerState::Error(e.clone()), ++ ConsumerState::Continue(ref m) => ConsumerState::Continue(m.clone()), ++ ConsumerState::Done(_, ref o2) => ConsumerState::Done(m.clone(), o2.clone()) ++ } ++ }; ++ &self.state ++ } ++ ++ fn state(&self) -> &ConsumerState { ++ &self.state ++ } ++} ++ ++#[macro_export] ++macro_rules! consumer_from_parser ( ++ //FIXME: should specify the error and move type ++ ($name:ident<$input:ty, $output:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[derive(Debug)] ++ struct $name { ++ state: $crate::ConsumerState<$output, (), $crate::Move> ++ } ++ ++ impl $name { ++ fn new() -> $name { ++ $name { state: $crate::ConsumerState::Continue($crate::Move::Consume(0)) } ++ } ++ } ++ ++ impl $crate::Consumer<$input, $output, (), $crate::Move> for $name { ++ fn handle(&mut self, input: $crate::Input<$input>) -> & $crate::ConsumerState<$output, (), $crate::Move> { ++ use $crate::HexDisplay; ++ match input { ++ $crate::Input::Empty | $crate::Input::Eof(None) => &self.state, ++ $crate::Input::Element(sl) | $crate::Input::Eof(Some(sl)) => { ++ self.state = match $submac!(sl, $($args)*) { ++ $crate::IResult::Incomplete(n) => { ++ $crate::ConsumerState::Continue($crate::Move::Await(n)) ++ }, ++ $crate::IResult::Error(_) => { ++ $crate::ConsumerState::Error(()) ++ }, ++ $crate::IResult::Done(i,o) => { ++ $crate::ConsumerState::Done($crate::Move::Consume(sl.offset(i)), o) ++ } ++ }; ++ ++ &self.state ++ } ++ } ++ ++ } ++ ++ fn state(&self) -> &$crate::ConsumerState<$output, (), $crate::Move> { ++ &self.state ++ } ++ } ++ ); ++ ($name:ident<$output:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[derive(Debug)] ++ struct $name { ++ state: $crate::ConsumerState<$output, (), $crate::Move> ++ } ++ ++ impl $name { ++ // Allow this to go unused, because code in the defining scope can create the struct directly. ++ #[allow(dead_code)] ++ fn new() -> $name { ++ $name { state: $crate::ConsumerState::Continue($crate::Move::Consume(0)) } ++ } ++ } ++ ++ impl<'a> $crate::Consumer<&'a[u8], $output, (), $crate::Move> for $name { ++ fn handle(&mut self, input: $crate::Input<&'a[u8]>) -> & $crate::ConsumerState<$output, (), $crate::Move> { ++ use $crate::HexDisplay; ++ match input { ++ $crate::Input::Empty | $crate::Input::Eof(None) => &self.state, ++ $crate::Input::Element(sl) | $crate::Input::Eof(Some(sl)) => { ++ self.state = match $submac!(sl, $($args)*) { ++ $crate::IResult::Incomplete(n) => { ++ $crate::ConsumerState::Continue($crate::Move::Await(n)) ++ }, ++ $crate::IResult::Error(_) => { ++ $crate::ConsumerState::Error(()) ++ }, ++ $crate::IResult::Done(i,o) => { ++ $crate::ConsumerState::Done($crate::Move::Consume(sl.offset(i)), o) ++ } ++ }; ++ ++ &self.state ++ } ++ } ++ ++ } ++ ++ fn state(&self) -> &$crate::ConsumerState<$output, (), $crate::Move> { ++ &self.state ++ } ++ } ++ ); ++ ($name:ident<$input:ty, $output:ty>, $f:expr) => ( ++ consumer_from_parser!($name<$input, $output>, call!($f)); ++ ); ++ ($name:ident<$output:ty>, $f:expr) => ( ++ consumer_from_parser!($name<$output>, call!($f)); ++ ); ++ ++); ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use internal::IResult; ++ use util::HexDisplay; ++ use std::str::from_utf8; ++ use std::io::SeekFrom; ++ ++ #[derive(Debug)] ++ struct AbcdConsumer<'a> { ++ state: ConsumerState<&'a [u8], (), Move> ++ } ++ ++ named!(abcd, tag!("abcd")); ++ impl<'a> Consumer<&'a [u8], &'a [u8], (), Move> for AbcdConsumer<'a> { ++ fn handle(&mut self, input: Input<&'a [u8]>) -> &ConsumerState<&'a [u8],(),Move> { ++ match input { ++ Input::Empty | Input::Eof(None) => &self.state, ++ Input::Element(sl) => { ++ match abcd(sl) { ++ IResult::Error(_) => { ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.state = ConsumerState::Continue(Move::Consume(0)) ++ }, ++ IResult::Done(i,o) => { ++ self.state = ConsumerState::Done(Move::Consume(sl.offset(i)),o) ++ } ++ }; ++ &self.state ++ } ++ Input::Eof(Some(sl)) => { ++ match abcd(sl) { ++ IResult::Error(_) => { ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ // we cannot return incomplete on Eof ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Done(i,o) => { ++ self.state = ConsumerState::Done(Move::Consume(sl.offset(i)), o) ++ } ++ }; ++ &self.state ++ } ++ } ++ ++ } ++ ++ fn state(&self) -> &ConsumerState<&'a [u8], (), Move> { ++ &self.state ++ } ++ } ++ ++ #[test] ++ fn mem() { ++ let mut m = MemProducer::new(&b"abcdabcdabcdabcdabcd"[..], 8); ++ ++ let mut a = AbcdConsumer { state: ConsumerState::Continue(Move::Consume(0)) }; ++ ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ //assert!(false); ++ } ++ ++ named!(efgh, tag!("efgh")); ++ named!(ijkl, tag!("ijkl")); ++ #[derive(Debug)] ++ enum State { ++ Initial, ++ A, ++ B, ++ End, ++ Error ++ } ++ #[derive(Debug)] ++ struct StateConsumer<'a> { ++ state: ConsumerState<&'a [u8], (), Move>, ++ parsing_state: State ++ } ++ ++ impl<'a> Consumer<&'a [u8], &'a [u8], (), Move> for StateConsumer<'a> { ++ fn handle(&mut self, input: Input<&'a [u8]>) -> &ConsumerState<&'a [u8], (), Move> { ++ match input { ++ Input::Empty | Input::Eof(None) => &self.state, ++ Input::Element(sl) => { ++ match self.parsing_state { ++ State::Initial => match abcd(sl) { ++ IResult::Error(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.state = ConsumerState::Continue(Move::Consume(0)) ++ }, ++ IResult::Done(i,_) => { ++ self.parsing_state = State::A; ++ self.state = ConsumerState::Continue(Move::Consume(sl.offset(i))) ++ } ++ }, ++ State::A => match efgh(sl) { ++ IResult::Error(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.state = ConsumerState::Continue(Move::Consume(0)) ++ }, ++ IResult::Done(i,_) => { ++ self.parsing_state = State::B; ++ self.state = ConsumerState::Continue(Move::Consume(sl.offset(i))) ++ } ++ }, ++ State::B => match ijkl(sl) { ++ IResult::Error(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.state = ConsumerState::Continue(Move::Consume(0)) ++ }, ++ IResult::Done(i,o) => { ++ self.parsing_state = State::End; ++ self.state = ConsumerState::Done(Move::Consume(sl.offset(i)),o) ++ } ++ }, ++ _ => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ } ++ } ++ &self.state ++ } ++ Input::Eof(Some(sl)) => { ++ match self.parsing_state { ++ State::Initial => match abcd(sl) { ++ IResult::Error(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Done(_,_) => { ++ self.parsing_state = State::A; ++ self.state = ConsumerState::Error(()) ++ } ++ }, ++ State::A => match efgh(sl) { ++ IResult::Error(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Done(_,_) => { ++ self.parsing_state = State::B; ++ self.state = ConsumerState::Error(()) ++ } ++ }, ++ State::B => match ijkl(sl) { ++ IResult::Error(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Incomplete(_) => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ }, ++ IResult::Done(i,o) => { ++ self.parsing_state = State::End; ++ self.state = ConsumerState::Done(Move::Consume(sl.offset(i)), o) ++ } ++ }, ++ _ => { ++ self.parsing_state = State::Error; ++ self.state = ConsumerState::Error(()) ++ } ++ } ++ &self.state ++ } ++ } ++ ++ } ++ ++ fn state(&self) -> &ConsumerState<&'a [u8], (), Move> { ++ &self.state ++ } ++ } ++ impl<'a> StateConsumer<'a> { ++ fn parsing(&self) -> &State { ++ &self.parsing_state ++ } ++ } ++ ++ #[test] ++ fn mem2() { ++ let mut m = MemProducer::new(&b"abcdefghijklabcdabcd"[..], 8); ++ ++ let mut a = StateConsumer { state: ConsumerState::Continue(Move::Consume(0)), parsing_state: State::Initial }; ++ ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("state {:?}", a.parsing()); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("state {:?}", a.parsing()); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("state {:?}", a.parsing()); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("state {:?}", a.parsing()); ++ //assert!(false); ++ } ++ ++ ++ #[test] ++ fn map() { ++ let mut m = MemProducer::new(&b"abcdefghijklabcdabcd"[..], 8); ++ ++ let mut s = StateConsumer { state: ConsumerState::Continue(Move::Consume(0)), parsing_state: State::Initial }; ++ let mut a = MapConsumer::new(&mut s, from_utf8); ++ ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ //assert!(false); ++ } ++ ++ #[derive(Debug)] ++ struct StrConsumer<'a> { ++ state: ConsumerState<&'a str, (), Move> ++ } ++ ++ impl<'a> Consumer<&'a [u8], &'a str, (), Move> for StrConsumer<'a> { ++ fn handle(&mut self, input: Input<&'a [u8]>) -> &ConsumerState<&'a str, (), Move> { ++ match input { ++ Input::Empty | Input::Eof(None) => &self.state, ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ self.state = ConsumerState::Done(Move::Consume(sl.len()), from_utf8(sl).unwrap()); ++ &self.state ++ } ++ } ++ ++ } ++ ++ fn state(&self) -> &ConsumerState<&'a str, (), Move> { ++ &self.state ++ } ++ } ++ ++ ++ #[test] ++ fn chain() { ++ let mut m = MemProducer::new(&b"abcdefghijklabcdabcd"[..], 8); ++ ++ let mut s1 = StateConsumer { state: ConsumerState::Continue(Move::Consume(0)), parsing_state: State::Initial }; ++ let mut s2 = StrConsumer { state: ConsumerState::Continue(Move::Consume(0)) }; ++ let mut a = ChainConsumer::new(&mut s1, &mut s2); ++ ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ println!("apply {:?}", m.apply(&mut a)); ++ //assert!(false); ++ // ++ //let x = [0, 1, 2, 3, 4]; ++ //let b = [1, 2, 3]; ++ //assert_eq!(&x[1..3], &b[..]); ++ } ++ ++ #[test] ++ fn shift_test() { ++ let mut v = vec![0,1,2,3,4,5]; ++ shift(&mut v, 1, 3); ++ assert_eq!(&v[..2], &[1,2][..]); ++ let mut v2 = vec![0,1,2,3,4,5]; ++ shift(&mut v2, 2, 6); ++ assert_eq!(&v2[..4], &[2,3,4,5][..]); ++ } ++ ++ /*#[derive(Debug)] ++ struct LineConsumer { ++ state: ConsumerState ++ } ++ impl<'a> Consumer<&'a [u8], String, (), Move> for LineConsumer { ++ fn handle(&mut self, input: Input<&'a [u8]>) -> &ConsumerState { ++ match input { ++ Input::Empty | Input::Eof(None) => &self.state, ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ //println!("got slice: {:?}", sl); ++ self.state = match line(sl) { ++ IResult::Incomplete(n) => { ++ println!("line not complete, continue (line was \"{}\")", from_utf8(sl).unwrap()); ++ ConsumerState::Continue(Move::Await(n)) ++ }, ++ IResult::Error(e) => { ++ println!("LineConsumer parsing error: {:?}", e); ++ ConsumerState::Error(()) ++ }, ++ IResult::Done(i,o) => { ++ let res = String::from(from_utf8(o).unwrap()); ++ println!("found: {}", res); ++ //println!("sl: {:?}\ni:{:?}\noffset:{}", sl, i, sl.offset(i)); ++ ConsumerState::Done(Move::Consume(sl.offset(i)), res) ++ } ++ }; ++ ++ &self.state ++ } ++ } ++ ++ } ++ ++ fn state(&self) -> &ConsumerState { ++ &self.state ++ } ++ }*/ ++ ++ fn lf(i:& u8) -> bool { ++ *i == '\n' as u8 ++ } ++ fn to_utf8_string(input:&[u8]) -> String { ++ String::from(from_utf8(input).unwrap()) ++ } ++ ++ //named!(line<&[u8]>, terminated!(take_till!(lf), tag!("\n"))); ++ ++ consumer_from_parser!(LineConsumer, map!(terminated!(take_till!(lf), tag!("\n")), to_utf8_string)); ++ ++ fn get_line(producer: &mut FileProducer, mv: Move) -> Option<(Move,String)> { ++ let mut a = LineConsumer { state: ConsumerState::Continue(mv) }; ++ while let &ConsumerState::Continue(_) = producer.apply(&mut a) { ++ println!("continue"); ++ } ++ ++ if let &ConsumerState::Done(ref m, ref s) = a.state() { ++ Some((m.clone(), s.clone())) ++ } else { ++ None ++ } ++ } ++ ++ #[test] ++ fn file() { ++ let mut f = FileProducer::new("LICENSE", 200).unwrap(); ++ f.refill(); ++ ++ let mut mv = Move::Consume(0); ++ for i in 1..10 { ++ if let Some((m,s)) = get_line(&mut f, mv.clone()) { ++ println!("got line[{}]: {}", i, s); ++ mv = m; ++ } else { ++ assert!(false, "LineConsumer should not have failed"); ++ } ++ } ++ //assert!(false); ++ } ++ ++ #[derive(Debug,Clone,Copy,PartialEq,Eq)] ++ enum SeekState { ++ Begin, ++ SeekedToEnd, ++ ShouldEof, ++ IsEof ++ } ++ ++ #[derive(Debug)] ++ struct SeekingConsumer { ++ state: ConsumerState<(), u8, Move>, ++ position: SeekState ++ } ++ ++ impl SeekingConsumer { ++ fn position(&self) -> SeekState { ++ self.position ++ } ++ } ++ ++ impl<'a> Consumer<&'a [u8], (), u8, Move> for SeekingConsumer { ++ fn handle(&mut self, input: Input<&'a [u8]>) -> &ConsumerState<(), u8, Move> { ++ println!("input: {:?}", input); ++ match self.position { ++ SeekState::Begin => { ++ self.state = ConsumerState::Continue(Move::Seek(SeekFrom::End(-4))); ++ self.position = SeekState::SeekedToEnd; ++ }, ++ SeekState::SeekedToEnd => match input { ++ Input::Element(sl) => { ++ if sl.len() == 4 { ++ self.state = ConsumerState::Continue(Move::Consume(4)); ++ self.position = SeekState::ShouldEof; ++ } else { ++ self.state = ConsumerState::Error(0); ++ } ++ }, ++ Input::Eof(Some(sl)) => { ++ if sl.len() == 4 { ++ self.state = ConsumerState::Done(Move::Consume(4), ()); ++ self.position = SeekState::IsEof; ++ } else { ++ self.state = ConsumerState::Error(1); ++ } ++ }, ++ _ => self.state = ConsumerState::Error(2) ++ }, ++ SeekState::ShouldEof => match input { ++ Input::Eof(Some(sl)) => { ++ if sl.len() == 0 { ++ self.state = ConsumerState::Done(Move::Consume(0), ()); ++ self.position = SeekState::IsEof; ++ } else { ++ self.state = ConsumerState::Error(3); ++ } ++ }, ++ Input::Eof(None) => { ++ self.state = ConsumerState::Done(Move::Consume(0), ()); ++ self.position = SeekState::IsEof; ++ }, ++ _ => self.state = ConsumerState::Error(4) ++ }, ++ _ => self.state = ConsumerState::Error(5) ++ }; ++ &self.state ++ } ++ ++ fn state(&self) -> &ConsumerState<(), u8, Move> { ++ &self.state ++ } ++ } ++ ++ #[test] ++ fn seeking_consumer() { ++ let mut f = FileProducer::new("assets/testfile.txt", 200).unwrap(); ++ f.refill(); ++ ++ let mut a = SeekingConsumer { state: ConsumerState::Continue(Move::Consume(0)), position: SeekState::Begin }; ++ for _ in 1..4 { ++ println!("file apply {:?}", f.apply(&mut a)); ++ } ++ println!("consumer is now: {:?}", a); ++ if let &ConsumerState::Done(Move::Consume(0), ()) = a.state() { ++ println!("end"); ++ } else { ++ println!("invalid state is {:?}", a.state()); ++ assert!(false, "consumer is not at EOF"); ++ } ++ assert_eq!(a.position(), SeekState::IsEof); ++ } ++} +diff --git third_party/rust/nom-1.2.4/src/util.rs third_party/rust/nom-1.2.4/src/util.rs +new file mode 100644 +index 000000000000..e2428ead0a4d +--- /dev/null ++++ third_party/rust/nom-1.2.4/src/util.rs +@@ -0,0 +1,769 @@ ++use internal::{IResult,Err}; ++ ++#[cfg(not(feature = "core"))] ++use std::collections::HashMap; ++ ++#[cfg(feature = "core")] ++use std::prelude::v1::*; ++use std::vec::Vec; ++use std::string::ToString; ++ ++/// useful functions to calculate the offset between slices and show a hexdump of a slice ++#[cfg(not(feature = "core"))] ++pub trait HexDisplay { ++ /// offset between the first byte of self and the first byte of the argument ++ fn offset(&self, second:&[u8]) -> usize;// OFFSET SHOULD GO TO ITS OWN TRAIT ++ ++ /// Converts the value of `self` to a hex dump, returning the owned ++ /// string. ++ fn to_hex(&self, chunk_size: usize) -> String; ++ ++ /// Converts the value of `self` to a hex dump beginning at `from` address, returning the owned ++ /// string. ++ fn to_hex_from(&self, chunk_size: usize, from: usize) -> String; ++} ++ ++pub trait InputLength { ++ #[inline] ++ fn input_len(&self) -> usize; ++} ++ ++impl<'a, T> InputLength for &'a[T] { ++ #[inline] ++ fn input_len(&self) -> usize { ++ self.len() ++ } ++} ++ ++impl<'a> InputLength for &'a str { ++ #[inline] ++ fn input_len(&self) -> usize { ++ self.len() ++ } ++} ++ ++impl<'a> InputLength for (&'a [u8], usize) { ++ #[inline] ++ fn input_len(&self) -> usize { ++ //println!("bit input length for ({:?}, {}):", self.0, self.1); ++ let res = self.0.len() * 8 - self.1; ++ //println!("-> {}", res); ++ res ++ } ++} ++ ++use std::iter::Enumerate; ++#[cfg(not(feature = "core"))] ++use std::str::CharIndices; ++ ++pub trait AsChar { ++ #[inline] ++ fn as_char(self) -> char; ++ #[inline] ++ fn is_alpha(self) -> bool; ++ #[inline] ++ fn is_alphanum(self) -> bool; ++ #[inline] ++ fn is_0_to_9(self) -> bool; ++ #[inline] ++ fn is_hex_digit(self) -> bool; ++ #[inline] ++ fn is_oct_digit(self) -> bool; ++} ++ ++impl<'a> AsChar for &'a u8 { ++ #[inline] ++ fn as_char(self) -> char { *self as char } ++ #[inline] ++ fn is_alpha(self) -> bool { ++ (*self >= 0x41 && *self <= 0x5A) || (*self >= 0x61 && *self <= 0x7A) ++ } ++ #[inline] ++ fn is_alphanum(self) -> bool { self.is_alpha() || self.is_0_to_9() } ++ #[inline] ++ fn is_0_to_9(self) -> bool { ++ *self >= 0x30 && *self <= 0x39 ++ } ++ #[inline] ++ fn is_hex_digit(self) -> bool { ++ (*self >= 0x30 && *self <= 0x39) || ++ (*self >= 0x41 && *self <= 0x46) || ++ (*self >= 0x61 && *self <= 0x66) ++ } ++ #[inline] ++ fn is_oct_digit(self) -> bool { ++ *self >= 0x30 && *self <= 0x37 ++ } ++} ++ ++impl AsChar for char { ++ #[inline] ++ fn as_char(self) -> char { self } ++ #[inline] ++ fn is_alpha(self) -> bool { self.is_alphabetic() } ++ #[inline] ++ fn is_alphanum(self) -> bool { self.is_alpha() || self.is_0_to_9() } ++ #[inline] ++ fn is_0_to_9(self) -> bool { self.is_digit(10) } ++ #[inline] ++ fn is_hex_digit(self) -> bool { self.is_digit(16) } ++ #[inline] ++ fn is_oct_digit(self) -> bool { self.is_digit(8) } ++} ++ ++pub trait IterIndices { ++ type Item: AsChar; ++ type Iter : Iterator; ++ fn iter_indices(self) -> Self::Iter; ++} ++ ++impl<'a> IterIndices for &'a [u8] { ++ type Item = &'a u8; ++ type Iter = Enumerate<::std::slice::Iter<'a, u8>>; ++ #[inline] ++ fn iter_indices(self) -> Enumerate<::std::slice::Iter<'a, u8>> { ++ self.iter().enumerate() ++ } ++} ++ ++#[cfg(not(feature = "core"))] ++impl<'a> IterIndices for &'a str { ++ type Item = char; ++ type Iter = CharIndices<'a>; ++ #[inline] ++ fn iter_indices(self) -> CharIndices<'a> { ++ self.char_indices() ++ } ++} ++ ++static CHARS: &'static[u8] = b"0123456789abcdef"; ++ ++#[cfg(not(feature = "core"))] ++impl HexDisplay for [u8] { ++ fn offset(&self, second:&[u8]) -> usize { ++ let fst = self.as_ptr(); ++ let snd = second.as_ptr(); ++ ++ snd as usize - fst as usize ++ } ++ ++ #[allow(unused_variables)] ++ fn to_hex(&self, chunk_size: usize) -> String { ++ self.to_hex_from(chunk_size, 0) ++ } ++ ++ #[allow(unused_variables)] ++ fn to_hex_from(&self, chunk_size: usize, from: usize) -> String { ++ let mut v = Vec::with_capacity(self.len() * 3); ++ let mut i = from; ++ for chunk in self.chunks(chunk_size) { ++ let s = format!("{:08x}", i); ++ for &ch in s.as_bytes().iter() { ++ v.push(ch); ++ } ++ v.push('\t' as u8); ++ ++ i = i + chunk_size; ++ ++ for &byte in chunk { ++ v.push(CHARS[(byte >> 4) as usize]); ++ v.push(CHARS[(byte & 0xf) as usize]); ++ v.push(' ' as u8); ++ } ++ if chunk_size > chunk.len() { ++ for j in 0..(chunk_size - chunk.len()) { ++ v.push(' ' as u8); ++ v.push(' ' as u8); ++ v.push(' ' as u8); ++ } ++ } ++ v.push('\t' as u8); ++ ++ for &byte in chunk { ++ if (byte >=32 && byte <= 126) || byte >= 128 { ++ v.push(byte); ++ } else { ++ v.push('.' as u8); ++ } ++ } ++ v.push('\n' as u8); ++ } ++ ++ String::from_utf8_lossy(&v[..]).into_owned() ++ } ++} ++ ++/// Prints a message if the parser fails ++/// ++/// The message prints the `Error` or `Incomplete` ++/// and the parser's calling code ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # fn main() { ++/// named!(f, dbg!( tag!( "abcd" ) ) ); ++/// ++/// let a = &b"efgh"[..]; ++/// ++/// // Will print the following message: ++/// // Error(Position(0, [101, 102, 103, 104])) at l.5 by ' tag ! ( "abcd" ) ' ++/// f(a); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! dbg ( ++ ($i: expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let l = line!(); ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(a) => { ++ println!("Error({:?}) at l.{} by ' {} '", a, l, stringify!($submac!($($args)*))); ++ $crate::IResult::Error(a) ++ }, ++ $crate::IResult::Incomplete(a) => { ++ println!("Incomplete({:?}) at {} by ' {} '", a, l, stringify!($submac!($($args)*))); ++ $crate::IResult::Incomplete(a) ++ }, ++ a => a ++ } ++ } ++ ); ++ ++ ($i:expr, $f:ident) => ( ++ dbg!($i, call!($f)); ++ ); ++); ++ ++/// Prints a message and the input if the parser fails ++/// ++/// The message prints the `Error` or `Incomplete` ++/// and the parser's calling code. ++/// ++/// It also displays the input in hexdump format ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # fn main() { ++/// named!(f, dbg_dmp!( tag!( "abcd" ) ) ); ++/// ++/// let a = &b"efghijkl"[..]; ++/// ++/// // Will print the following message: ++/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) ' ++/// // 00000000 65 66 67 68 69 6a 6b 6c efghijkl ++/// f(a); ++/// # } ++#[macro_export] ++macro_rules! dbg_dmp ( ++ ($i: expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::HexDisplay; ++ let l = line!(); ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(a) => { ++ println!("Error({:?}) at l.{} by ' {} '\n{}", a, l, stringify!($submac!($($args)*)), $i.to_hex(8)); ++ $crate::IResult::Error(a) ++ }, ++ $crate::IResult::Incomplete(a) => { ++ println!("Incomplete({:?}) at {} by ' {} '\n{}", a, l, stringify!($submac!($($args)*)), $i.to_hex(8)); ++ $crate::IResult::Incomplete(a) ++ }, ++ a => a ++ } ++ } ++ ); ++ ++ ($i:expr, $f:ident) => ( ++ dbg_dmp!($i, call!($f)); ++ ); ++); ++ ++pub fn error_to_list(e:&Err) -> Vec> { ++ let mut v:Vec> = Vec::new(); ++ let mut err = e; ++ loop { ++ match *err { ++ Err::Code(ref i) | Err::Position(ref i,_) => { ++ v.push(i.clone()); ++ return v; ++ }, ++ Err::Node(ref i, ref next) | Err::NodePosition(ref i, _, ref next) => { ++ v.push(i.clone()); ++ err = &*next; ++ } ++ } ++ } ++} ++ ++pub fn compare_error_paths(e1:&Err, e2:&Err) -> bool { ++ error_to_list(e1) == error_to_list(e2) ++} ++ ++ ++#[cfg(not(feature = "core"))] ++use std::hash::Hash; ++ ++#[cfg(not(feature = "core"))] ++pub fn add_error_pattern<'a,I,O,E: Clone+Hash+Eq>(h: &mut HashMap>, &'a str>, res: IResult, message: &'a str) -> bool { ++ if let IResult::Error(e) = res { ++ h.insert(error_to_list(&e), message); ++ true ++ } else { ++ false ++ } ++} ++ ++pub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) { ++ let start = input.as_ptr(); ++ let off1 = s.as_ptr() as usize - start as usize; ++ let off2 = off1 + s.len(); ++ (off1, off2) ++} ++ ++#[cfg(not(feature = "core"))] ++pub fn prepare_errors(input: &[u8], res: IResult<&[u8],O,E>) -> Option, usize, usize)> > { ++ if let IResult::Error(e) = res { ++ let mut v:Vec<(ErrorKind, usize, usize)> = Vec::new(); ++ let mut err = e.clone(); ++ loop { ++ match err { ++ Err::Position(i,s) => { ++ let (o1, o2) = slice_to_offsets(input, s); ++ v.push((i, o1, o2)); ++ //println!("v is: {:?}", v); ++ break; ++ }, ++ Err::NodePosition(i, s, next) => { ++ let (o1, o2) = slice_to_offsets(input, s); ++ v.push((i, o1, o2)); ++ err = *next; ++ }, ++ Err::Node(_, next) => { ++ err = *next; ++ }, ++ Err::Code(_) => { ++ break; ++ } ++ } ++ } ++ v.sort_by(|a, b| a.1.cmp(&b.1)); ++ Some(v) ++ } else { ++ None ++ } ++} ++ ++#[cfg(not(feature = "core"))] ++pub fn print_error(input: &[u8], res: IResult<&[u8],O,E>) { ++ if let Some(v) = prepare_errors(input, res) { ++ let colors = generate_colors(&v); ++ println!("parser codes: {}", print_codes(colors, HashMap::new())); ++ println!("{}", print_offsets(input, 0, &v)); ++ ++ } else { ++ println!("not an error"); ++ } ++} ++ ++#[cfg(not(feature = "core"))] ++pub fn generate_colors(v: &[(ErrorKind, usize, usize)]) -> HashMap { ++ let mut h: HashMap = HashMap::new(); ++ let mut color = 0; ++ ++ for &(ref c,_,_) in v.iter() { ++ h.insert(error_to_u32(c), color + 31); ++ color = color + 1 % 7; ++ } ++ ++ h ++} ++ ++pub fn code_from_offset(v: &[(ErrorKind, usize, usize)], offset: usize) -> Option { ++ let mut acc: Option<(u32, usize, usize)> = None; ++ for &(ref ek, s, e) in v.iter() { ++ let c = error_to_u32(ek); ++ if s <= offset && offset <=e { ++ if let Some((_, start, end)) = acc { ++ if start <= s && e <= end { ++ acc = Some((c, s, e)); ++ } ++ } else { ++ acc = Some((c, s, e)); ++ } ++ } ++ } ++ if let Some((code, _, _)) = acc { ++ return Some(code); ++ } else { ++ return None; ++ } ++} ++ ++pub fn reset_color(v: &mut Vec) { ++ v.push(0x1B); ++ v.push('[' as u8); ++ v.push(0); ++ v.push('m' as u8); ++} ++ ++pub fn write_color(v: &mut Vec, color: u8) { ++ v.push(0x1B); ++ v.push('[' as u8); ++ v.push(1); ++ v.push(';' as u8); ++ let s = color.to_string(); ++ let bytes = s.as_bytes(); ++ v.extend(bytes.iter().cloned()); ++ v.push('m' as u8); ++} ++ ++#[cfg(not(feature = "core"))] ++pub fn print_codes(colors: HashMap, names: HashMap) -> String { ++ let mut v = Vec::new(); ++ for (code, &color) in &colors { ++ if let Some(&s) = names.get(&code) { ++ let bytes = s.as_bytes(); ++ write_color(&mut v, color); ++ v.extend(bytes.iter().cloned()); ++ } else { ++ let s = code.to_string(); ++ let bytes = s.as_bytes(); ++ write_color(&mut v, color); ++ v.extend(bytes.iter().cloned()); ++ } ++ reset_color(&mut v); ++ v.push(' ' as u8); ++ } ++ reset_color(&mut v); ++ ++ String::from_utf8_lossy(&v[..]).into_owned() ++} ++ ++#[cfg(not(feature = "core"))] ++pub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String { ++ let mut v = Vec::with_capacity(input.len() * 3); ++ let mut i = from; ++ let chunk_size = 8; ++ let mut current_code: Option = None; ++ let mut current_code2: Option = None; ++ ++ let colors = generate_colors(&offsets); ++ ++ for chunk in input.chunks(chunk_size) { ++ let s = format!("{:08x}", i); ++ for &ch in s.as_bytes().iter() { ++ v.push(ch); ++ } ++ v.push('\t' as u8); ++ ++ let mut k = i; ++ let mut l = i; ++ for &byte in chunk { ++ if let Some(code) = code_from_offset(&offsets, k) { ++ if let Some(current) = current_code { ++ if current != code { ++ reset_color(&mut v); ++ current_code = Some(code); ++ if let Some(&color) = colors.get(&code) { ++ write_color(&mut v, color); ++ } ++ } ++ } else { ++ current_code = Some(code); ++ if let Some(&color) = colors.get(&code) { ++ write_color(&mut v, color); ++ } ++ } ++ } ++ v.push(CHARS[(byte >> 4) as usize]); ++ v.push(CHARS[(byte & 0xf) as usize]); ++ v.push(' ' as u8); ++ k = k + 1; ++ } ++ ++ reset_color(&mut v); ++ ++ if chunk_size > chunk.len() { ++ for _ in 0..(chunk_size - chunk.len()) { ++ v.push(' ' as u8); ++ v.push(' ' as u8); ++ v.push(' ' as u8); ++ } ++ } ++ v.push('\t' as u8); ++ ++ for &byte in chunk { ++ if let Some(code) = code_from_offset(&offsets, l) { ++ if let Some(current) = current_code2 { ++ if current != code { ++ reset_color(&mut v); ++ current_code2 = Some(code); ++ if let Some(&color) = colors.get(&code) { ++ write_color(&mut v, color); ++ } ++ } ++ } else { ++ current_code2 = Some(code); ++ if let Some(&color) = colors.get(&code) { ++ write_color(&mut v, color); ++ } ++ } ++ } ++ if (byte >=32 && byte <= 126) || byte >= 128 { ++ v.push(byte); ++ } else { ++ v.push('.' as u8); ++ } ++ l = l + 1; ++ } ++ reset_color(&mut v); ++ ++ v.push('\n' as u8); ++ i = i + chunk_size; ++ } ++ ++ String::from_utf8_lossy(&v[..]).into_owned() ++} ++ ++pub trait AsBytes { ++ fn as_bytes(&self) -> &[u8]; ++} ++ ++impl<'a> AsBytes for &'a str { ++ #[inline(always)] ++ fn as_bytes(&self) -> &[u8] { ++ str::as_bytes(self) ++ } ++} ++ ++impl AsBytes for str { ++ #[inline(always)] ++ fn as_bytes(&self) -> &[u8] { ++ str::as_bytes(self) ++ } ++} ++ ++impl<'a> AsBytes for &'a [u8] { ++ #[inline(always)] ++ fn as_bytes(&self) -> &[u8] { ++ *self ++ } ++} ++ ++impl AsBytes for [u8] { ++ #[inline(always)] ++ fn as_bytes(&self) -> &[u8] { ++ self ++ } ++} ++ ++macro_rules! array_impls { ++ ($($N:expr)+) => { ++ $( ++ impl<'a> AsBytes for &'a [u8; $N] { ++ #[inline(always)] ++ fn as_bytes(&self) -> &[u8] { ++ *self ++ } ++ } ++ ++ impl AsBytes for [u8; $N] { ++ #[inline(always)] ++ fn as_bytes(&self) -> &[u8] { ++ self ++ } ++ } ++ )+ ++ }; ++} ++ ++ ++array_impls! { ++ 0 1 2 3 4 5 6 7 8 9 ++ 10 11 12 13 14 15 16 17 18 19 ++ 20 21 22 23 24 25 26 27 28 29 ++ 30 31 32 ++} ++ ++/// indicates which parser returned an error ++#[derive(Debug,PartialEq,Eq,Hash,Clone)] ++pub enum ErrorKind { ++ Custom(E), ++ Tag, ++ MapRes, ++ MapOpt, ++ Alt, ++ IsNot, ++ IsA, ++ SeparatedList, ++ SeparatedNonEmptyList, ++ Many0, ++ Many1, ++ Count, ++ TakeUntilAndConsume, ++ TakeUntil, ++ TakeUntilEitherAndConsume, ++ TakeUntilEither, ++ LengthValue, ++ TagClosure, ++ Alpha, ++ Digit, ++ HexDigit, ++ OctDigit, ++ AlphaNumeric, ++ Space, ++ MultiSpace, ++ LengthValueFn, ++ Eof, ++ ExprOpt, ++ ExprRes, ++ CondReduce, ++ Switch, ++ TagBits, ++ OneOf, ++ NoneOf, ++ Char, ++ CrLf, ++ RegexpMatch, ++ RegexpMatches, ++ RegexpFind, ++ RegexpCapture, ++ RegexpCaptures, ++ TakeWhile1, ++ Complete, ++ Fix, ++ Escaped, ++ EscapedTransform, ++ TagStr, ++ IsNotStr, ++ IsAStr, ++ TakeWhile1Str, ++ NonEmpty, ++ ManyMN, ++ TakeUntilAndConsumeStr, ++ TakeUntilStr, ++ Not ++} ++ ++pub fn error_to_u32(e: &ErrorKind) -> u32 { ++ match *e { ++ ErrorKind::Custom(_) => 0, ++ ErrorKind::Tag => 1, ++ ErrorKind::MapRes => 2, ++ ErrorKind::MapOpt => 3, ++ ErrorKind::Alt => 4, ++ ErrorKind::IsNot => 5, ++ ErrorKind::IsA => 6, ++ ErrorKind::SeparatedList => 7, ++ ErrorKind::SeparatedNonEmptyList => 8, ++ ErrorKind::Many1 => 9, ++ ErrorKind::Count => 10, ++ ErrorKind::TakeUntilAndConsume => 11, ++ ErrorKind::TakeUntil => 12, ++ ErrorKind::TakeUntilEitherAndConsume => 13, ++ ErrorKind::TakeUntilEither => 14, ++ ErrorKind::LengthValue => 15, ++ ErrorKind::TagClosure => 16, ++ ErrorKind::Alpha => 17, ++ ErrorKind::Digit => 18, ++ ErrorKind::AlphaNumeric => 19, ++ ErrorKind::Space => 20, ++ ErrorKind::MultiSpace => 21, ++ ErrorKind::LengthValueFn => 22, ++ ErrorKind::Eof => 23, ++ ErrorKind::ExprOpt => 24, ++ ErrorKind::ExprRes => 25, ++ ErrorKind::CondReduce => 26, ++ ErrorKind::Switch => 27, ++ ErrorKind::TagBits => 28, ++ ErrorKind::OneOf => 29, ++ ErrorKind::NoneOf => 30, ++ ErrorKind::Char => 40, ++ ErrorKind::CrLf => 41, ++ ErrorKind::RegexpMatch => 42, ++ ErrorKind::RegexpMatches => 43, ++ ErrorKind::RegexpFind => 44, ++ ErrorKind::RegexpCapture => 45, ++ ErrorKind::RegexpCaptures => 46, ++ ErrorKind::TakeWhile1 => 47, ++ ErrorKind::Complete => 48, ++ ErrorKind::Fix => 49, ++ ErrorKind::Escaped => 50, ++ ErrorKind::EscapedTransform => 51, ++ ErrorKind::TagStr => 52, ++ ErrorKind::IsNotStr => 53, ++ ErrorKind::IsAStr => 54, ++ ErrorKind::TakeWhile1Str => 55, ++ ErrorKind::NonEmpty => 56, ++ ErrorKind::ManyMN => 57, ++ ErrorKind::TakeUntilAndConsumeStr => 58, ++ ErrorKind::HexDigit => 59, ++ ErrorKind::TakeUntilStr => 60, ++ ErrorKind::OctDigit => 61, ++ ErrorKind::Many0 => 62, ++ ErrorKind::Not => 63, ++ } ++} ++ ++ impl ErrorKind { ++ pub fn description(&self) -> &str { ++ match *self { ++ ErrorKind::Custom(_) => "Custom error", ++ ErrorKind::Tag => "Tag", ++ ErrorKind::MapRes => "Map on Result", ++ ErrorKind::MapOpt => "Map on Option", ++ ErrorKind::Alt => "Alternative", ++ ErrorKind::IsNot => "IsNot", ++ ErrorKind::IsA => "IsA", ++ ErrorKind::SeparatedList => "Separated list", ++ ErrorKind::SeparatedNonEmptyList => "Separated non empty list", ++ ErrorKind::Many0 => "Many0", ++ ErrorKind::Many1 => "Many1", ++ ErrorKind::Count => "Count", ++ ErrorKind::TakeUntilAndConsume => "Take until and consume", ++ ErrorKind::TakeUntil => "Take until", ++ ErrorKind::TakeUntilEitherAndConsume => "Take until either and consume", ++ ErrorKind::TakeUntilEither => "Take until either", ++ ErrorKind::LengthValue => "Length followed by value", ++ ErrorKind::TagClosure => "Tag closure", ++ ErrorKind::Alpha => "Alphabetic", ++ ErrorKind::Digit => "Digit", ++ ErrorKind::AlphaNumeric => "AlphaNumeric", ++ ErrorKind::Space => "Space", ++ ErrorKind::MultiSpace => "Multiple spaces", ++ ErrorKind::LengthValueFn => "LengthValueFn", ++ ErrorKind::Eof => "End of file", ++ ErrorKind::ExprOpt => "Evaluate Option", ++ ErrorKind::ExprRes => "Evaluate Result", ++ ErrorKind::CondReduce => "Condition reduce", ++ ErrorKind::Switch => "Switch", ++ ErrorKind::TagBits => "Tag on bitstream", ++ ErrorKind::OneOf => "OneOf", ++ ErrorKind::NoneOf => "NoneOf", ++ ErrorKind::Char => "Char", ++ ErrorKind::CrLf => "CrLf", ++ ErrorKind::RegexpMatch => "RegexpMatch", ++ ErrorKind::RegexpMatches => "RegexpMatches", ++ ErrorKind::RegexpFind => "RegexpFind", ++ ErrorKind::RegexpCapture => "RegexpCapture", ++ ErrorKind::RegexpCaptures => "RegexpCaptures", ++ ErrorKind::TakeWhile1 => "TakeWhile1", ++ ErrorKind::Complete => "Complete", ++ ErrorKind::Fix => "Fix", ++ ErrorKind::Escaped => "Escaped", ++ ErrorKind::EscapedTransform => "EscapedTransform", ++ ErrorKind::TagStr => "Tag on strings", ++ ErrorKind::IsNotStr => "IsNot on strings", ++ ErrorKind::IsAStr => "IsA on strings", ++ ErrorKind::TakeWhile1Str => "TakeWhile1 on strings", ++ ErrorKind::NonEmpty => "NonEmpty", ++ ErrorKind::ManyMN => "Many(m, n)", ++ ErrorKind::TakeUntilAndConsumeStr => "Take until and consume on strings", ++ ErrorKind::HexDigit => "Hexadecimal Digit", ++ ErrorKind::TakeUntilStr => "Take until on strings", ++ ErrorKind::OctDigit => "Octal digit", ++ ErrorKind::Not => "Negation", ++ } ++ ++ } ++ } +diff --git third_party/rust/nom-1.2.4/tests/arithmetic.rs third_party/rust/nom-1.2.4/tests/arithmetic.rs +new file mode 100644 +index 000000000000..eea990fb07cf +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/arithmetic.rs +@@ -0,0 +1,80 @@ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,digit, multispace}; ++ ++use std::str; ++use std::str::FromStr; ++ ++named!(parens, delimited!( ++ delimited!(opt!(multispace), tag!("("), opt!(multispace)), ++ expr, ++ delimited!(opt!(multispace), tag!(")"), opt!(multispace)) ++ ) ++); ++ ++named!(factor, alt!( ++ map_res!( ++ map_res!( ++ delimited!(opt!(multispace), digit, opt!(multispace)), ++ str::from_utf8 ++ ), ++ FromStr::from_str ++ ) ++ | parens ++ ) ++); ++ ++named!(term , chain!( ++ mut acc: factor ~ ++ many0!( ++ alt!( ++ tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) | ++ tap!(div: preceded!(tag!("/"), factor) => acc = acc / div) ++ ) ++ ), ++ || { return acc } ++ ) ++); ++ ++named!(expr , chain!( ++ mut acc: term ~ ++ many0!( ++ alt!( ++ tap!(add: preceded!(tag!("+"), term) => acc = acc + add) | ++ tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub) ++ ) ++ ), ++ || { return acc } ++ ) ++); ++ ++#[test] ++fn factor_test() { ++ assert_eq!(factor(&b"3"[..]), IResult::Done(&b""[..], 3)); ++ assert_eq!(factor(&b" 12"[..]), IResult::Done(&b""[..], 12)); ++ assert_eq!(factor(&b"537 "[..]), IResult::Done(&b""[..], 537)); ++ assert_eq!(factor(&b" 24 "[..]), IResult::Done(&b""[..], 24)); ++} ++ ++ ++#[test] ++fn term_test() { ++ assert_eq!(term(&b" 12 *2 / 3"[..]), IResult::Done(&b""[..], 8)); ++ assert_eq!(term(&b" 2* 3 *2 *2 / 3"[..]), IResult::Done(&b""[..], 8)); ++ assert_eq!(term(&b" 48 / 3/2"[..]), IResult::Done(&b""[..], 8)); ++} ++ ++#[test] ++fn expr_test() { ++ assert_eq!(expr(&b" 1 + 2 "[..]), IResult::Done(&b""[..], 3)); ++ assert_eq!(expr(&b" 12 + 6 - 4+ 3"[..]), IResult::Done(&b""[..], 17)); ++ assert_eq!(expr(&b" 1 + 2*3 + 4"[..]), IResult::Done(&b""[..], 11)); ++} ++ ++#[test] ++fn parens_test() { ++ assert_eq!(expr(&b" ( 2 )"[..]), IResult::Done(&b""[..], 2)); ++ assert_eq!(expr(&b" 2* ( 3 + 4 ) "[..]), IResult::Done(&b""[..], 14)); ++ assert_eq!(expr(&b" 2*2 / ( 5 - 1) + 3"[..]), IResult::Done(&b""[..], 4)); ++} +diff --git third_party/rust/nom-1.2.4/tests/arithmetic_ast.rs third_party/rust/nom-1.2.4/tests/arithmetic_ast.rs +new file mode 100644 +index 000000000000..9a8956936ff8 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/arithmetic_ast.rs +@@ -0,0 +1,137 @@ ++#[macro_use] ++extern crate nom; ++ ++use std::fmt; ++use std::fmt::{Display, Debug, Formatter}; ++ ++use std::str; ++use std::str::FromStr; ++ ++use nom::{IResult, digit, multispace}; ++ ++pub enum Expr { ++ Value(i64), ++ Add(Box, Box), ++ Sub(Box, Box), ++ Mul(Box, Box), ++ Div(Box, Box), ++ Paren(Box), ++} ++ ++pub enum Oper { ++ Add, ++ Sub, ++ Mul, ++ Div, ++} ++ ++impl Display for Expr { ++ fn fmt(&self, format: &mut Formatter) -> fmt::Result { ++ use self::Expr::*; ++ match *self { ++ Value(val) => write!(format, "{}", val), ++ Add(ref left, ref right) => write!(format, "{} + {}", left, right), ++ Sub(ref left, ref right) => write!(format, "{} - {}", left, right), ++ Mul(ref left, ref right) => write!(format, "{} * {}", left, right), ++ Div(ref left, ref right) => write!(format, "{} / {}", left, right), ++ Paren(ref expr) => write!(format, "({})", expr), ++ } ++ } ++} ++ ++impl Debug for Expr { ++ fn fmt(&self, format: &mut Formatter) -> fmt::Result { ++ use self::Expr::*; ++ match *self { ++ Value(val) => write!(format, "{}", val), ++ Add(ref left, ref right) => write!(format, "({:?} + {:?})", left, right), ++ Sub(ref left, ref right) => write!(format, "({:?} - {:?})", left, right), ++ Mul(ref left, ref right) => write!(format, "({:?} * {:?})", left, right), ++ Div(ref left, ref right) => write!(format, "({:?} / {:?})", left, right), ++ Paren(ref expr) => write!(format, "[{:?}]", expr), ++ } ++ } ++} ++ ++named!(parens< Expr >, delimited!( ++ delimited!(opt!(multispace), tag!("("), opt!(multispace)), ++ map!(map!(expr, Box::new), Expr::Paren), ++ delimited!(opt!(multispace), tag!(")"), opt!(multispace)) ++ ) ++); ++ ++named!(factor< Expr >, alt_complete!( ++ map!( ++ map_res!( ++ map_res!( ++ delimited!(opt!(multispace), digit, opt!(multispace)), ++ str::from_utf8 ++ ), ++ FromStr::from_str ++ ), ++ Expr::Value) ++ | parens ++ ) ++); ++ ++fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr { ++ remainder.into_iter().fold(initial, |acc, pair| { ++ let (oper, expr) = pair; ++ match oper { ++ Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)), ++ Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)), ++ Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)), ++ Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)), ++ } ++ }) ++} ++ ++named!(term< Expr >, chain!( ++ initial: factor ~ ++ remainder: many0!( ++ alt!( ++ chain!(tag!("*") ~ mul: factor, || { (Oper::Mul, mul) }) | ++ chain!(tag!("/") ~ div: factor, || { (Oper::Div, div) }) ++ ) ++ ), ++ || fold_exprs(initial, remainder)) ++); ++ ++named!(expr< Expr >, chain!( ++ initial: term ~ ++ remainder: many0!( ++ alt!( ++ chain!(tag!("+") ~ add: term, || { (Oper::Add, add) }) | ++ chain!(tag!("-") ~ sub: term, || { (Oper::Sub, sub) }) ++ ) ++ ), ++ || fold_exprs(initial, remainder)) ++); ++ ++#[test] ++fn factor_test() { ++ assert_eq!(factor(&b" 3 "[..]).map(|x| format!("{:?}", x)), ++ IResult::Done(&b""[..], String::from("3"))); ++} ++ ++#[test] ++fn term_test() { ++ assert_eq!(term(&b" 3 * 5 "[..]).map(|x| format!("{:?}", x)), ++ IResult::Done(&b""[..], String::from("(3 * 5)"))); ++} ++ ++#[test] ++fn expr_test() { ++ assert_eq!(expr(&b" 1 + 2 * 3 "[..]).map(|x| format!("{:?}", x)), ++ IResult::Done(&b""[..], String::from("(1 + (2 * 3))"))); ++ assert_eq!(expr(&b" 1 + 2 * 3 / 4 - 5 "[..]).map(|x| format!("{:?}", x)), ++ IResult::Done(&b""[..], String::from("((1 + ((2 * 3) / 4)) - 5)"))); ++ assert_eq!(expr(&b" 72 / 2 / 3 "[..]).map(|x| format!("{:?}", x)), ++ IResult::Done(&b""[..], String::from("((72 / 2) / 3)"))); ++} ++ ++#[test] ++fn parens_test() { ++ assert_eq!(expr(&b" ( 1 + 2 ) * 3 "[..]).map(|x| format!("{:?}", x)), ++ IResult::Done(&b""[..], String::from("([(1 + 2)] * 3)"))); ++} +diff --git third_party/rust/nom-1.2.4/tests/cross_function_backtracking.rs third_party/rust/nom-1.2.4/tests/cross_function_backtracking.rs +new file mode 100644 +index 000000000000..592670c43999 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/cross_function_backtracking.rs +@@ -0,0 +1,140 @@ ++/// this file tests a different backtracking behaviour. With the current ++/// `error!` macro, an early return is done in the current function, but ++/// backtracking continues normally outside of that function. ++/// ++/// The solution here wraps `IResult` in a `Result`: a `Ok` indicates usual ++/// backtracking, `Err` indicates that we must "cut". ++ ++#[macro_use] ++extern crate nom; ++ ++macro_rules! n ( ++ ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: $i ) -> std::result::Result, nom::Err<$i, u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ ($name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: $i ) -> std::result::Result, nom::Err<$i, $e>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ ($name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: $i ) -> std::result::Result, nom::Err<$i, u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name<'a>( i: &'a[u8] ) -> std::result::Result, nom::Err<&'a [u8], u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ ($name:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name( i: &[u8] ) -> std::result::Result, nom::Err<&[u8], u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ (pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: $i ) -> std::result::Result, nom::Err<$i, u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ (pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: $i ) -> std::result::Result, nom::Err<$i, $e>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ (pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: $i ) -> std::result::Result, nom::Err<$i, u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name( i: &[u8] ) -> std::result::Result, nom::Err<&[u8], u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++ (pub $name:ident, $submac:ident!( $($args:tt)* )) => ( ++ pub fn $name<'a>( i: &'a [u8] ) -> std::result::Result, nom::Err<&[u8], u32>> { ++ std::result::Result::Ok($submac!(i, $($args)*)) ++ } ++ ); ++); ++ ++macro_rules! cut ( ++ ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let cl = || { ++ Ok($submac!($i, $($args)*)) ++ }; ++ ++ match cl() { ++ std::result::Result::Ok(nom::IResult::Incomplete(x)) => nom::IResult::Incomplete(x), ++ std::result::Result::Ok(nom::IResult::Done(i, o)) => nom::IResult::Done(i, o), ++ std::result::Result::Ok(nom::IResult::Error(e)) | std::result::Result::Err(e) => { ++ return std::result::Result::Err(nom::Err::NodePosition($code, $i, Box::new(e))) ++ } ++ } ++ } ++ ); ++ ($i:expr, $code:expr, $f:expr) => ( ++ cut!($i, $code, call!($f)); ++ ); ++); ++ ++macro_rules! c ( ++ ($i:expr, $f:expr) => ( ++ { ++ match $f($i) { ++ std::result::Result::Ok(nom::IResult::Incomplete(x)) => nom::IResult::Incomplete(x), ++ std::result::Result::Ok(nom::IResult::Done(i, o)) => nom::IResult::Done(i, o), ++ std::result::Result::Ok(nom::IResult::Error(e)) => nom::IResult::Error(e), ++ std::result::Result::Err(e) => { ++ return std::result::Result::Err(e) ++ } ++ } ++ } ++ ); ++); ++ ++n!(pub foo< bool >, ++ chain!( ++ tag!("a") ~ ++ cut!(nom::ErrorKind::Custom(42),dbg_dmp!(tag!("b"))) , ++ || { true } ++ ) ++); ++ ++n!(pub foos< Vec >, ++ delimited!( ++ tag!("("), ++ many0!(c!(foo)), ++ tag!(")") ++ ) ++); ++ ++#[test] ++fn test_ok() { ++ let r = foos(b"(abab)"); ++ println!("result: {:?}", r); ++ match r { ++ Ok(nom::IResult::Done(_,result)) => assert_eq!(result,vec![true,true]), ++ res => panic!("Oops {:?}.",res) ++ } ++} ++ ++#[test] ++fn test_err() { ++ let input = b"(ac)"; ++ let r = foos(&input[..]); ++ println!("result: {:?}", r); ++ match r { ++ //Ok(nom::IResult::Error(nom::Err::Position(kind,_))) => assert_eq!(kind,nom::ErrorKind::Custom(42)), ++ Err(nom::Err::NodePosition(kind, position, _)) => { ++ assert_eq!(kind, nom::ErrorKind::Custom(42)); ++ assert_eq!(position, &input[2..]); ++ } ++ res => panic!("Oops, {:?}",res) ++ } ++} ++ +diff --git third_party/rust/nom-1.2.4/tests/ini.rs third_party/rust/nom-1.2.4/tests/ini.rs +new file mode 100644 +index 000000000000..a3a33431bf02 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/ini.rs +@@ -0,0 +1,234 @@ ++ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,not_line_ending, space, alphanumeric, multispace}; ++ ++use std::str; ++use std::collections::HashMap; ++ ++named!(category<&str>, map_res!( ++ terminated!( ++ delimited!(tag!("["), take_until!("]"), tag!("]")), ++ opt!(multispace) ++ ), ++ str::from_utf8 ++)); ++ ++named!(key_value <&[u8],(&str,&str)>, ++ chain!( ++ key: map_res!(alphanumeric, std::str::from_utf8) ~ ++ space? ~ ++ tag!("=") ~ ++ space? ~ ++ val: map_res!( ++ take_until_either!("\n;"), ++ str::from_utf8 ++ ) ~ ++ space? ~ ++ chain!( ++ tag!(";") ~ ++ not_line_ending , ++ ||{} ++ ) ? ~ ++ multispace? , ++ ||{(key, val)} ++ ) ++); ++ ++ ++named!(keys_and_values_aggregator<&[u8], Vec<(&str,&str)> >, many0!(key_value)); ++ ++fn keys_and_values(input:&[u8]) -> IResult<&[u8], HashMap<&str, &str> > { ++ let mut h: HashMap<&str, &str> = HashMap::new(); ++ ++ match keys_and_values_aggregator(input) { ++ IResult::Done(i,tuple_vec) => { ++ for &(k,v) in &tuple_vec { ++ h.insert(k, v); ++ } ++ IResult::Done(i, h) ++ }, ++ IResult::Incomplete(a) => IResult::Incomplete(a), ++ IResult::Error(a) => IResult::Error(a) ++ } ++} ++ ++named!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>, ++ chain!( ++ category: category ~ ++ keys: keys_and_values , ++ move ||{(category, keys)} ++ ) ++); ++ ++named!(categories_aggregator<&[u8], Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys)); ++ ++fn categories(input: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str> > > { ++ let mut h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); ++ ++ match categories_aggregator(input) { ++ IResult::Done(i,tuple_vec) => { ++ for &(k,ref v) in &tuple_vec { ++ h.insert(k, v.clone()); ++ } ++ IResult::Done(i, h) ++ }, ++ IResult::Incomplete(a) => IResult::Incomplete(a), ++ IResult::Error(a) => IResult::Error(a) ++ } ++} ++ ++#[test] ++fn parse_category_test() { ++ let ini_file = &b"[category] ++ ++parameter=value ++key = value2"[..]; ++ ++ let ini_without_category = &b"parameter=value ++key = value2"[..]; ++ ++ let res = category(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_category, "category")); ++} ++ ++#[test] ++fn parse_key_value_test() { ++ let ini_file = &b"parameter=value ++key = value2"[..]; ++ ++ let ini_without_key_value = &b"key = value2"[..]; ++ ++ let res = key_value(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value"))); ++} ++ ++ ++#[test] ++fn parse_key_value_with_space_test() { ++ let ini_file = &b"parameter = value ++key = value2"[..]; ++ ++ let ini_without_key_value = &b"key = value2"[..]; ++ ++ let res = key_value(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value"))); ++} ++ ++#[test] ++fn parse_key_value_with_comment_test() { ++ let ini_file = &b"parameter=value;abc ++key = value2"[..]; ++ ++ let ini_without_key_value = &b"key = value2"[..]; ++ ++ let res = key_value(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value"))); ++} ++ ++#[test] ++fn parse_multiple_keys_and_values_test() { ++ let ini_file = &b"parameter=value;abc ++ ++key = value2 ++ ++[category]"[..]; ++ ++ let ini_without_key_value = &b"[category]"[..]; ++ ++ let res = keys_and_values(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), ++ _ => println!("error") ++ } ++ ++ let mut expected: HashMap<&str, &str> = HashMap::new(); ++ expected.insert("parameter", "value"); ++ expected.insert("key", "value2"); ++ assert_eq!(res, IResult::Done(ini_without_key_value, expected)); ++} ++ ++#[test] ++fn parse_category_then_multiple_keys_and_values_test() { ++ //FIXME: there can be an empty line or a comment line after a category ++ let ini_file = &b"[abcd] ++parameter=value;abc ++ ++key = value2 ++ ++[category]"[..]; ++ ++ let ini_after_parser = &b"[category]"[..]; ++ ++ let res = category_and_keys(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), ++ _ => println!("error") ++ } ++ ++ let mut expected_h: HashMap<&str, &str> = HashMap::new(); ++ expected_h.insert("parameter", "value"); ++ expected_h.insert("key", "value2"); ++ assert_eq!(res, IResult::Done(ini_after_parser, ("abcd", expected_h))); ++} ++ ++#[test] ++fn parse_multiple_categories_test() { ++ let ini_file = &b"[abcd] ++ ++parameter=value;abc ++ ++key = value2 ++ ++[category] ++parameter3=value3 ++key4 = value4 ++"[..]; ++ ++ let ini_after_parser = &b""[..]; ++ ++ let res = categories(ini_file); ++ //println!("{:?}", res); ++ match res { ++ IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), ++ _ => println!("error") ++ } ++ ++ let mut expected_1: HashMap<&str, &str> = HashMap::new(); ++ expected_1.insert("parameter", "value"); ++ expected_1.insert("key", "value2"); ++ let mut expected_2: HashMap<&str, &str> = HashMap::new(); ++ expected_2.insert("parameter3", "value3"); ++ expected_2.insert("key4", "value4"); ++ let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); ++ expected_h.insert("abcd", expected_1); ++ expected_h.insert("category", expected_2); ++ assert_eq!(res, IResult::Done(ini_after_parser, expected_h)); ++} +diff --git third_party/rust/nom-1.2.4/tests/ini_str.rs third_party/rust/nom-1.2.4/tests/ini_str.rs +new file mode 100644 +index 000000000000..c69756dc2aca +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/ini_str.rs +@@ -0,0 +1,251 @@ ++ ++#[macro_use] ++extern crate nom; ++ ++use nom::IResult; ++ ++use std::collections::HashMap; ++ ++fn is_alphabetic(chr:char) -> bool { ++ (chr as u8 >= 0x41 && chr as u8 <= 0x5A) || (chr as u8 >= 0x61 && chr as u8 <= 0x7A) ++} ++ ++fn is_digit(chr: char) -> bool { ++ chr as u8 >= 0x30 && chr as u8 <= 0x39 ++} ++ ++fn is_alphanumeric(chr: char) -> bool { ++ is_alphabetic(chr) || is_digit(chr) ++} ++ ++fn is_space(chr:char) -> bool { ++ chr == ' ' || chr == '\t' ++} ++ ++fn is_line_ending_or_comment(chr:char) -> bool { ++ chr == ';' || chr == '\n' ++} ++ ++named!(alphanumeric<&str,&str>, take_while_s!(is_alphanumeric)); ++named!(not_line_ending<&str,&str>, is_not_s!("\r\n")); ++named!(space<&str,&str>, take_while_s!(is_space)); ++named!(space_or_line_ending<&str,&str>, is_a_s!(" \r\n")); ++ ++fn right_bracket(c:char) -> bool { ++ c == ']' ++} ++ ++named!(category <&str, &str>, ++ chain!( ++ tag_s!("[") ~ ++ name: take_till_s!(right_bracket) ~ ++ tag_s!("]") ~ ++ space_or_line_ending? , ++ ||{ name } ++ ) ++); ++ ++named!(key_value <&str,(&str,&str)>, ++ chain!( ++ key: alphanumeric ~ ++ space? ~ ++ tag_s!("=") ~ ++ space? ~ ++ val: take_till_s!(is_line_ending_or_comment) ~ ++ space? ~ ++ pair!(tag_s!(";"), not_line_ending)? ~ ++ space_or_line_ending? , ++ ||{(key, val)} ++ ) ++); ++ ++named!(keys_and_values_aggregator<&str, Vec<(&str,&str)> >, many0!(key_value)); ++ ++fn keys_and_values(input:&str) -> IResult<&str, HashMap<&str, &str> > { ++ let mut h: HashMap<&str, &str> = HashMap::new(); ++ ++ match keys_and_values_aggregator(input) { ++ IResult::Done(i,tuple_vec) => { ++ for &(k,v) in &tuple_vec { ++ h.insert(k, v); ++ } ++ IResult::Done(i, h) ++ }, ++ IResult::Incomplete(a) => IResult::Incomplete(a), ++ IResult::Error(a) => IResult::Error(a) ++ } ++} ++ ++ ++named!(category_and_keys<&str,(&str,HashMap<&str,&str>)>, ++ pair!(category, keys_and_values) ++); ++ ++named!(categories_aggregator<&str, Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys)); ++ ++fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str> > > { ++ let mut h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); ++ ++ match categories_aggregator(input) { ++ IResult::Done(i,tuple_vec) => { ++ for &(k,ref v) in &tuple_vec { ++ h.insert(k, v.clone()); ++ } ++ IResult::Done(i, h) ++ }, ++ IResult::Incomplete(a) => IResult::Incomplete(a), ++ IResult::Error(a) => IResult::Error(a) ++ } ++} ++ ++ ++#[test] ++fn parse_category_test() { ++ let ini_file = "[category] ++ ++parameter=value ++key = value2"; ++ ++ let ini_without_category = "parameter=value ++key = value2"; ++ ++ let res = category(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, o) => println!("i: {} | o: {:?}", i, o), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_category, "category")); ++} ++ ++#[test] ++fn parse_key_value_test() { ++ let ini_file = "parameter=value ++key = value2"; ++ ++ let ini_without_key_value = "key = value2"; ++ ++ let res = key_value(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value"))); ++} ++ ++#[test] ++fn parse_key_value_with_space_test() { ++ let ini_file = "parameter = value ++key = value2"; ++ ++ let ini_without_key_value = "key = value2"; ++ ++ let res = key_value(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value"))); ++} ++ ++#[test] ++fn parse_key_value_with_comment_test() { ++ let ini_file = "parameter=value;abc ++key = value2"; ++ ++ let ini_without_key_value = "key = value2"; ++ ++ let res = key_value(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), ++ _ => println!("error") ++ } ++ ++ assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value"))); ++} ++ ++#[test] ++fn parse_multiple_keys_and_values_test() { ++ let ini_file = "parameter=value;abc ++ ++key = value2 ++ ++[category]"; ++ ++ let ini_without_key_value = "[category]"; ++ ++ let res = keys_and_values(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, ref o) => println!("i: {} | o: {:?}", i, o), ++ _ => println!("error") ++ } ++ ++ let mut expected: HashMap<&str, &str> = HashMap::new(); ++ expected.insert("parameter", "value"); ++ expected.insert("key", "value2"); ++ assert_eq!(res, IResult::Done(ini_without_key_value, expected)); ++} ++ ++#[test] ++fn parse_category_then_multiple_keys_and_values_test() { ++ //FIXME: there can be an empty line or a comment line after a category ++ let ini_file = "[abcd] ++parameter=value;abc ++ ++key = value2 ++ ++[category]"; ++ ++ let ini_after_parser = "[category]"; ++ ++ let res = category_and_keys(ini_file); ++ println!("{:?}", res); ++ match res { ++ IResult::Done(i, ref o) => println!("i: {} | o: {:?}", i, o), ++ _ => println!("error") ++ } ++ ++ let mut expected_h: HashMap<&str, &str> = HashMap::new(); ++ expected_h.insert("parameter", "value"); ++ expected_h.insert("key", "value2"); ++ assert_eq!(res, IResult::Done(ini_after_parser, ("abcd", expected_h))); ++} ++ ++#[test] ++fn parse_multiple_categories_test() { ++ let ini_file = "[abcd] ++ ++parameter=value;abc ++ ++key = value2 ++ ++[category] ++parameter3=value3 ++key4 = value4 ++"; ++ ++ let res = categories(ini_file); ++ //println!("{:?}", res); ++ match res { ++ IResult::Done(i, ref o) => println!("i: {} | o: {:?}", i, o), ++ _ => println!("error") ++ } ++ ++ let mut expected_1: HashMap<&str, &str> = HashMap::new(); ++ expected_1.insert("parameter", "value"); ++ expected_1.insert("key", "value2"); ++ let mut expected_2: HashMap<&str, &str> = HashMap::new(); ++ expected_2.insert("parameter3", "value3"); ++ expected_2.insert("key4", "value4"); ++ let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); ++ expected_h.insert("abcd", expected_1); ++ expected_h.insert("category", expected_2); ++ assert_eq!(res, IResult::Done("", expected_h)); ++} +diff --git third_party/rust/nom-1.2.4/tests/issues.rs third_party/rust/nom-1.2.4/tests/issues.rs +new file mode 100644 +index 000000000000..6466d7f2e069 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/issues.rs +@@ -0,0 +1,131 @@ ++//#![feature(trace_macros)] ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,Needed,HexDisplay,space,digit,be_u16}; ++use std::str; ++ ++#[allow(dead_code)] ++struct Range { ++ start: char, ++ end: char ++} ++ ++pub fn take_char(input: &[u8]) -> IResult<&[u8], char> { ++ if input.len() > 0 { ++ IResult::Done(&input[1..], input[0] as char) ++ } else { ++ IResult::Incomplete(Needed::Size(1)) ++ } ++} ++ ++//trace_macros!(true); ++ ++#[allow(dead_code)] ++named!(range<&[u8], Range>, ++ alt!( ++ chain!( ++ start: take_char ~ ++ tag!("-") ~ ++ end: take_char, ++ || { ++ Range { ++ start: start, ++ end: end, ++ } ++ } ++ ) | ++ map!( ++ take_char, ++ |c| { ++ Range { ++ start: c, ++ end: c, ++ } ++ } ++ ) ++ ) ++); ++ ++ ++#[allow(dead_code)] ++named!(literal<&[u8], Vec >, ++ map!( ++ many1!(take_char), ++ |cs| { ++ cs ++ } ++ ) ++); ++ ++#[test] ++fn issue_58() { ++ range(&b"abcd"[..]); ++ literal(&b"abcd"[..]); ++} ++ ++//trace_macros!(false); ++ ++named!(parse_ints< Vec >, many0!(spaces_or_int)); ++ ++fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{ ++ println!("{}", input.to_hex(8)); ++ chain!(input, ++ opt!(space) ~ ++ x: digit, ++ || { ++ println!("x: {:?}", x); ++ let result = str::from_utf8(x).unwrap(); ++ println!("Result: {}", result); ++ println!("int is empty?: {}", x.is_empty()); ++ match result.parse(){ ++ Ok(i) => i, ++ Err(_) => panic!("UH OH! NOT A DIGIT!") ++ } ++ } ++ ) ++} ++ ++#[test] ++fn issue_142(){ ++ let subject = parse_ints(&b"12 34 5689"[..]); ++ let expected = IResult::Done(&b""[..], vec![12, 34, 5689]); ++ assert_eq!(subject, expected); ++ ++ let subject = parse_ints(&b"12 34 5689 "[..]); ++ let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]); ++ assert_eq!(subject, expected) ++} ++ ++#[test] ++fn usize_length_bytes_issue(){ ++ length_bytes!(b"012346", be_u16); ++} ++ ++/* ++ DOES NOT COMPILE ++#[test] ++fn issue_152() { ++ named!(take4, take!(4)); ++ named!(xyz, tag!("XYZ")); ++ named!(abc, tag!("abc")); ++ ++ ++ named!(sw, ++ switch!(take4, ++ b"abcd" => xyz | ++ b"efgh" => abc ++ ) ++ ); ++} ++*/ ++ ++#[test] ++fn take_till_issue() { ++ named!(nothing, ++ take_till!(call!(|_| true)) ++ ); ++ ++ assert_eq!(nothing(b""), IResult::Done(&b""[..], &b""[..])); ++ assert_eq!(nothing(b"abc"), IResult::Done(&b"abc"[..], &b""[..])); ++} +diff --git third_party/rust/nom-1.2.4/tests/mp4.rs third_party/rust/nom-1.2.4/tests/mp4.rs +new file mode 100644 +index 000000000000..8c128f57a928 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/mp4.rs +@@ -0,0 +1,531 @@ ++#![cfg(feature = "stream")] ++#![allow(dead_code)] ++ ++#[macro_use] ++extern crate nom; ++ ++use nom::{HexDisplay,Needed,IResult,be_u16,be_u32,be_u64,be_f32,ErrorKind}; ++use nom::{Consumer,ConsumerState,Move,Input,Producer,FileProducer,FileProducerState}; ++use nom::IResult::*; ++use nom::Err::*; ++ ++use std::str; ++use std::io::SeekFrom; ++ ++fn mp4_box(input:&[u8]) -> IResult<&[u8], &[u8]> { ++ match be_u32(input) { ++ Done(i, offset) => { ++ let sz: usize = offset as usize; ++ if i.len() >= sz - 4 { ++ Done(&i[(sz-4)..], &i[0..(sz-4)]) ++ } else { ++ Incomplete(Needed::Size(offset as usize + 4)) ++ } ++ } ++ Error(e) => Error(e), ++ Incomplete(e) => Incomplete(e) ++ } ++} ++ ++#[derive(PartialEq,Eq,Debug)] ++struct FileType<'a> { ++ major_brand: &'a str, ++ major_brand_version: &'a [u8], ++ compatible_brands: Vec<&'a str> ++} ++ ++#[allow(non_snake_case)] ++#[derive(Debug,Clone)] ++pub struct Mvhd32 { ++ version_flags: u32, // actually: ++ // version: u8, ++ // flags: u24 // 3 bytes ++ created_date: u32, ++ modified_date: u32, ++ scale: u32, ++ duration: u32, ++ speed: f32, ++ volume: u16, // actually a 2 bytes decimal ++ /* 10 bytes reserved */ ++ scaleA: f32, ++ rotateB: f32, ++ angleU: f32, ++ rotateC: f32, ++ scaleD: f32, ++ angleV: f32, ++ positionX: f32, ++ positionY: f32, ++ scaleW: f32, ++ preview: u64, ++ poster: u32, ++ selection: u64, ++ current_time: u32, ++ track_id: u32 ++} ++ ++#[allow(non_snake_case)] ++#[derive(Debug,Clone)] ++pub struct Mvhd64 { ++ version_flags: u32, // actually: ++ // version: u8, ++ // flags: u24 // 3 bytes ++ created_date: u64, ++ modified_date: u64, ++ scale: u32, ++ duration: u64, ++ speed: f32, ++ volume: u16, // actually a 2 bytes decimal ++ /* 10 bytes reserved */ ++ scaleA: f32, ++ rotateB: f32, ++ angleU: f32, ++ rotateC: f32, ++ scaleD: f32, ++ angleV: f32, ++ positionX: f32, ++ positionY: f32, ++ scaleW: f32, ++ preview: u64, ++ poster: u32, ++ selection: u64, ++ current_time: u32, ++ track_id: u32 ++} ++ ++#[allow(non_snake_case)] ++named!(mvhd32 <&[u8], MvhdBox>, ++ chain!( ++ version_flags: be_u32 ~ ++ created_date: be_u32 ~ ++ modified_date: be_u32 ~ ++ scale: be_u32 ~ ++ duration: be_u32 ~ ++ speed: be_f32 ~ ++ volume: be_u16 ~ // actually a 2 bytes decimal ++ take!(10) ~ ++ scale_a: be_f32 ~ ++ rotate_b: be_f32 ~ ++ angle_u: be_f32 ~ ++ rotate_c: be_f32 ~ ++ scale_d: be_f32 ~ ++ angle_v: be_f32 ~ ++ position_x: be_f32 ~ ++ position_y: be_f32 ~ ++ scale_w: be_f32 ~ ++ preview: be_u64 ~ ++ poster: be_u32 ~ ++ selection: be_u64 ~ ++ current_time: be_u32 ~ ++ track_id: be_u32, ++ ||{ ++ MvhdBox::M32(Mvhd32 { ++ version_flags: version_flags, ++ created_date: created_date, ++ modified_date: modified_date, ++ scale: scale, ++ duration: duration, ++ speed: speed, ++ volume: volume, ++ scaleA: scale_a, ++ rotateB: rotate_b, ++ angleU: angle_u, ++ rotateC: rotate_c, ++ scaleD: scale_d, ++ angleV: angle_v, ++ positionX: position_x, ++ positionY: position_y, ++ scaleW: scale_w, ++ preview: preview, ++ poster: poster, ++ selection: selection, ++ current_time: current_time, ++ track_id: track_id ++ }) ++ } ++ ) ++); ++ ++#[allow(non_snake_case)] ++named!(mvhd64 <&[u8], MvhdBox>, ++ chain!( ++ version_flags: be_u32 ~ ++ created_date: be_u64 ~ ++ modified_date: be_u64 ~ ++ scale: be_u32 ~ ++ duration: be_u64 ~ ++ speed: be_f32 ~ ++ volume: be_u16 ~ // actually a 2 bytes decimal ++ take!(10) ~ ++ scale_a: be_f32 ~ ++ rotate_b: be_f32 ~ ++ angle_u: be_f32 ~ ++ rotate_c: be_f32 ~ ++ scale_d: be_f32 ~ ++ angle_v: be_f32 ~ ++ position_x: be_f32 ~ ++ position_y: be_f32 ~ ++ scale_w: be_f32 ~ ++ preview: be_u64 ~ ++ poster: be_u32 ~ ++ selection: be_u64 ~ ++ current_time: be_u32 ~ ++ track_id: be_u32, ++ ||{ ++ MvhdBox::M64(Mvhd64 { ++ version_flags: version_flags, ++ created_date: created_date, ++ modified_date: modified_date, ++ scale: scale, ++ duration: duration, ++ speed: speed, ++ volume: volume, ++ scaleA: scale_a, ++ rotateB: rotate_b, ++ angleU: angle_u, ++ rotateC: rotate_c, ++ scaleD: scale_d, ++ angleV: angle_v, ++ positionX: position_x, ++ positionY: position_y, ++ scaleW: scale_w, ++ preview: preview, ++ poster: poster, ++ selection: selection, ++ current_time: current_time, ++ track_id: track_id ++ }) ++ } ++ ) ++); ++ ++#[derive(Debug,Clone)] ++pub enum MvhdBox { ++ M32(Mvhd32), ++ M64(Mvhd64) ++} ++ ++#[derive(Debug,Clone)] ++pub enum MoovBox { ++ Mdra, ++ Dref, ++ Cmov, ++ Rmra, ++ Iods, ++ Mvhd(MvhdBox), ++ Clip, ++ Trak, ++ Udta ++} ++ ++#[derive(Debug)] ++enum MP4BoxType { ++ Ftyp, ++ Moov, ++ Mdat, ++ Free, ++ Skip, ++ Wide, ++ Mdra, ++ Dref, ++ Cmov, ++ Rmra, ++ Iods, ++ Mvhd, ++ Clip, ++ Trak, ++ Udta, ++ Unknown ++} ++ ++#[derive(Debug)] ++struct MP4BoxHeader { ++ length: u32, ++ tag: MP4BoxType ++} ++ ++named!(brand_name<&[u8],&str>, map_res!(take!(4), str::from_utf8)); ++ ++named!(filetype_parser<&[u8], FileType>, ++ chain!( ++ m: brand_name ~ ++ v: take!(4) ~ ++ c: many0!(brand_name) , ++ ||{ FileType{ major_brand: m, major_brand_version:v, compatible_brands: c } } ++ ) ++); ++ ++fn mvhd_box(input:&[u8]) -> IResult<&[u8],MvhdBox> { ++ let res = if input.len() < 100 { ++ Incomplete(Needed::Size(100)) ++ } else if input.len() == 100 { ++ mvhd32(input) ++ } else if input.len() == 112 { ++ mvhd64(input) ++ } else { ++ Error(Position(ErrorKind::Custom(32),input)) ++ }; ++ println!("res: {:?}", res); ++ res ++} ++ ++fn unknown_box_type(input:&[u8]) -> IResult<&[u8], MP4BoxType> { ++ Done(input, MP4BoxType::Unknown) ++} ++ ++//named!(box_type<&[u8], MP4BoxType>, ++fn box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType, u32> { ++ alt!(input, ++ tag!("ftyp") => { |_| MP4BoxType::Ftyp } | ++ tag!("moov") => { |_| MP4BoxType::Moov } | ++ tag!("mdat") => { |_| MP4BoxType::Mdat } | ++ tag!("free") => { |_| MP4BoxType::Free } | ++ tag!("skip") => { |_| MP4BoxType::Skip } | ++ tag!("wide") => { |_| MP4BoxType::Wide } | ++ unknown_box_type ++ ) ++} ++ ++// warning, an alt combinator with 9 branches containing a tag combinator ++// can make the compilation very slow. Use functions as sub parsers, ++// or split into multiple alt! parsers if it gets slow ++named!(moov_type<&[u8], MP4BoxType>, ++ alt!( ++ tag!("mdra") => { |_| MP4BoxType::Mdra } | ++ tag!("dref") => { |_| MP4BoxType::Dref } | ++ tag!("cmov") => { |_| MP4BoxType::Cmov } | ++ tag!("rmra") => { |_| MP4BoxType::Rmra } | ++ tag!("iods") => { |_| MP4BoxType::Iods } | ++ tag!("mvhd") => { |_| MP4BoxType::Mvhd } | ++ tag!("clip") => { |_| MP4BoxType::Clip } | ++ tag!("trak") => { |_| MP4BoxType::Trak } | ++ tag!("udta") => { |_| MP4BoxType::Udta } ++ ) ++); ++ ++named!(box_header<&[u8],MP4BoxHeader>, ++ chain!( ++ length: be_u32 ~ ++ tag: box_type , ++ || { MP4BoxHeader{ length: length, tag: tag} } ++ ) ++); ++ ++named!(moov_header<&[u8],MP4BoxHeader>, ++ chain!( ++ length: be_u32 ~ ++ tag: moov_type , ++ || { MP4BoxHeader{ length: length, tag: tag} } ++ ) ++); ++ ++#[derive(Debug,PartialEq,Eq)] ++enum MP4State { ++ Main, ++ Moov, ++ Mvhd(usize) ++} ++ ++pub struct MP4Consumer { ++ state: MP4State, ++ moov_bytes: usize, ++ c_state: ConsumerState<(), (), Move> ++} ++ ++impl MP4Consumer { ++ fn new() -> MP4Consumer { ++ MP4Consumer { state: MP4State::Main, moov_bytes: 0, c_state: ConsumerState::Continue(Move::Consume(0)) } ++ } ++ ++ fn consume_main(&mut self, input: Input<&[u8]>) -> ConsumerState<(), (), Move> { ++ //println!("\nparsing box header:\n{}", input.to_hex(8)); ++ match input { ++ Input::Eof(None) => ConsumerState::Done(Move::Consume(0), ()), ++ Input::Empty => ConsumerState::Continue(Move::Consume(0)), ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ match box_header(sl) { ++ Done(i, header) => { ++ match header.tag { ++ MP4BoxType::Ftyp => { ++ println!("-> FTYP"); ++ match filetype_parser(&i[0..(header.length as usize - 8)]) { ++ Done(rest, filetype_header) => { ++ println!("filetype header: {:?}", filetype_header); ++ //return ConsumerState::Await(header.length as usize, header.length as usize - 8); ++ return ConsumerState::Continue(Move::Consume(sl.offset(rest))); ++ } ++ Error(a) => { ++ println!("ftyp parsing error: {:?}", a); ++ assert!(false); ++ return ConsumerState::Error(()); ++ }, ++ Incomplete(n) => { ++ println!("ftyp incomplete -> await: {}", sl.len()); ++ return ConsumerState::Continue(Move::Await(n)); ++ //return ConsumerState::Await(0, input.len() + 100); ++ } ++ } ++ }, ++ MP4BoxType::Moov => { ++ println!("-> MOOV"); ++ self.state = MP4State::Moov; ++ self.moov_bytes = header.length as usize - 8; ++ return ConsumerState::Continue(Move::Consume(sl.offset(i))); ++ }, ++ MP4BoxType::Mdat => println!("-> MDAT"), ++ MP4BoxType::Free => println!("-> FREE"), ++ MP4BoxType::Skip => println!("-> SKIP"), ++ MP4BoxType::Wide => println!("-> WIDE"), ++ MP4BoxType::Unknown => { ++ println!("-> UNKNOWN"); ++ println!("bytes:\n{}", (sl).to_hex(8)); ++ //return ConsumerState::Continue(Move::Consume(sl.offset(i))); ++ }, ++ _ => { println!("invalid"); return ConsumerState::Error(())} ++ } ++ return ConsumerState::Continue(Move::Seek(SeekFrom::Current((header.length) as i64))) ++ }, ++ Error(a) => { ++ println!("mp4 parsing error: {:?}", a); ++ assert!(false); ++ return ConsumerState::Error(()); ++ }, ++ Incomplete(i) => { ++ // FIXME: incomplete should send the required size ++ println!("mp4 incomplete -> await: {}", sl.len()); ++ return ConsumerState::Continue(Move::Await(i)); ++ } ++ } ++ } ++ } ++ } ++ ++ fn consume_moov(&mut self, input: Input<&[u8]>) -> ConsumerState<(), (), Move> { ++ //println!("\nparsing moov box(remaining {} bytes):\n{}", self.moov_bytes, input.to_hex(8)); ++ match input { ++ Input::Eof(None) => return ConsumerState::Error(()), ++ Input::Empty => return ConsumerState::Continue(Move::Consume(0)), ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ if self.moov_bytes == 0 { ++ //println!("finished parsing moov atom, continuing with main parser"); ++ self.state = MP4State::Main; ++ return ConsumerState::Continue(Move::Consume(0)); ++ } ++ match moov_header(sl) { ++ Done(i, header) => { ++ match header.tag { ++ MP4BoxType::Mvhd => { ++ println!("-> MVHD"); ++ self.state = MP4State::Mvhd(header.length as usize - 8); ++ // TODO: check for overflow here ++ self.moov_bytes = self.moov_bytes - (sl.len() - i.len()); ++ println!("remaining moov_bytes: {}", self.moov_bytes); ++ return ConsumerState::Continue(Move::Consume(sl.offset(i))); ++ }, ++ MP4BoxType::Wide => println!("-> WIDE"), ++ MP4BoxType::Mdra => println!("-> MDRA"), ++ MP4BoxType::Dref => println!("-> DREF"), ++ MP4BoxType::Cmov => println!("-> CMOV"), ++ MP4BoxType::Rmra => println!("-> RMRA"), ++ MP4BoxType::Iods => println!("-> IODS"), ++ MP4BoxType::Clip => println!("-> CLIP"), ++ MP4BoxType::Trak => println!("-> TRAK"), ++ MP4BoxType::Udta => println!("-> UDTA"), ++ MP4BoxType::Unknown => println!("-> MOOV UNKNOWN"), ++ _ => { println!("invalid header here: {:?}", header.tag); return ConsumerState::Error(());} ++ }; ++ // TODO: check for overflow here ++ self.moov_bytes = self.moov_bytes - header.length as usize; ++ println!("remaining moov_bytes: {}", self.moov_bytes); ++ return ConsumerState::Continue(Move::Seek(SeekFrom::Current((header.length) as i64))) ++ }, ++ Error(a) => { ++ println!("moov parsing error: {:?}", a); ++ println!("data:\n{}", sl.to_hex(8)); ++ assert!(false); ++ return ConsumerState::Error(()); ++ }, ++ Incomplete(i) => { ++ println!("moov incomplete -> await: {}", sl.len()); ++ return ConsumerState::Continue(Move::Await(i)); ++ } ++ } ++ } ++ }; ++ } ++ ++} ++ ++consumer_from_parser!(MvhdConsumer, mvhd_box); ++ ++impl<'a> Consumer<&'a[u8], (), (), Move> for MP4Consumer { ++ fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState<(), (), Move> { ++ match self.state { ++ MP4State::Main => { ++ self.c_state = self.consume_main(input); ++ }, ++ MP4State::Moov => { ++ self.c_state = self.consume_moov(input); ++ }, ++ MP4State::Mvhd(sz) => { ++ match input { ++ Input::Eof(None) => self.c_state = ConsumerState::Error(()), ++ Input::Empty => self.c_state = ConsumerState::Continue(Move::Consume(0)), ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ let mut c = MvhdConsumer{ state:ConsumerState::Continue(Move::Consume(0)) }; ++ self.c_state = c.handle(Input::Element(&sl[..sz])).flat_map(|m, _| { ++ self.state = MP4State::Moov; ++ ConsumerState::Continue(m) ++ }); ++ println!("found mvhd?: {:?}", c.state()); ++ match self.c_state { ++ ConsumerState::Continue(Move::Consume(sz)) => self.moov_bytes = self.moov_bytes - sz, ++ ConsumerState::Continue(Move::Seek(SeekFrom::Current(sz))) => self.moov_bytes = self.moov_bytes - (sz as usize), ++ _ => () ++ }; ++ println!("remaining moov_bytes: {}", self.moov_bytes); ++ } ++ } ++ } ++ }; ++ &self.c_state ++ } ++ ++ fn state(&self) -> &ConsumerState<(), (), Move> { ++ &self.c_state ++ } ++} ++ ++#[allow(unused_must_use)] ++fn explore_mp4_file(filename: &str) { ++ let mut p = FileProducer::new(filename, 400).unwrap(); ++ let mut c = MP4Consumer{state: MP4State::Main, moov_bytes: 0, c_state: ConsumerState::Continue(Move::Consume(0))}; ++ //c.run(&mut p); ++ while let &ConsumerState::Continue(mv) = p.apply(&mut c) { ++ println!("move: {:?}", mv); ++ } ++ println!("last consumer state: {:?} | last state: {:?}", c.c_state, c.state); ++ ++ if let ConsumerState::Done(Move::Consume(0), ()) = c.c_state { ++ println!("consumer state ok"); ++ } else { ++ assert!(false, "consumer should have reached Done state"); ++ } ++ assert_eq!(c.state, MP4State::Main); ++ assert_eq!(p.state(), FileProducerState::Eof); ++ //assert!(false); ++} ++ ++ ++#[test] ++fn small_test() { ++ explore_mp4_file("assets/small.mp4"); ++} ++ ++ ++#[test] ++fn big_bunny_test() { ++ explore_mp4_file("assets/bigbuckbunny.mp4"); ++} ++ ++ ++ +diff --git third_party/rust/nom-1.2.4/tests/omnom.rs third_party/rust/nom-1.2.4/tests/omnom.rs +new file mode 100644 +index 000000000000..b8cfa04fb7e4 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/omnom.rs +@@ -0,0 +1,160 @@ ++#![cfg(feature = "stream")] ++ ++#[macro_use] ++extern crate nom; ++ ++use nom::{Producer,Consumer,ConsumerState,Input,Move,MemProducer,IResult,HexDisplay}; ++ ++#[derive(PartialEq,Eq,Debug)] ++enum State { ++ Beginning, ++ Middle, ++ End, ++ Done, ++ Error ++} ++ ++struct TestConsumer { ++ state: State, ++ c_state: ConsumerState, ++ counter: usize, ++} ++ ++named!(om_parser, tag!("om")); ++named!(nomnom_parser<&[u8],Vec<&[u8]> >, many1!(tag!("nom"))); ++named!(end_parser, tag!("kthxbye")); ++ ++impl<'a> Consumer<&'a[u8], usize, (), Move> for TestConsumer { ++ fn state(&self) -> &ConsumerState { ++ &self.c_state ++ } ++ ++ fn handle(&mut self, input: Input<&'a [u8]>) -> &ConsumerState { ++ match self.state { ++ State::Beginning => { ++ match input { ++ Input::Empty | Input::Eof(None) => { ++ self.state = State::Error; ++ self.c_state = ConsumerState::Error(()); ++ }, ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ match om_parser(sl) { ++ IResult::Error(_) => { ++ self.state = State::Error; ++ self.c_state = ConsumerState::Error(()); ++ }, ++ IResult::Incomplete(n) => { ++ self.c_state = ConsumerState::Continue(Move::Await(n)); ++ }, ++ IResult::Done(i,_) => { ++ self.state = State::Middle; ++ self.c_state = ConsumerState::Continue(Move::Consume(sl.offset(i))); ++ } ++ } ++ } ++ } ++ }, ++ State::Middle => { ++ match input { ++ Input::Empty | Input::Eof(None) => { ++ self.state = State::Error; ++ self.c_state = ConsumerState::Error(()); ++ }, ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ match nomnom_parser(sl) { ++ IResult::Error(_) => { ++ self.state = State::End; ++ self.c_state = ConsumerState::Continue(Move::Consume(0)); ++ }, ++ IResult::Incomplete(n) => { ++ println!("Middle got Incomplete({:?})", n); ++ self.c_state = ConsumerState::Continue(Move::Await(n)); ++ }, ++ IResult::Done(i,noms_vec) => { ++ self.counter = self.counter + noms_vec.len(); ++ self.state = State::Middle; ++ self.c_state = ConsumerState::Continue(Move::Consume(sl.offset(i))); ++ } ++ } ++ } ++ } ++ }, ++ State::End => { ++ match input { ++ Input::Empty | Input::Eof(None) => { ++ self.state = State::Error; ++ self.c_state = ConsumerState::Error(()); ++ }, ++ Input::Element(sl) | Input::Eof(Some(sl)) => { ++ match end_parser(sl) { ++ IResult::Error(_) => { ++ self.state = State::Error; ++ self.c_state = ConsumerState::Error(()); ++ }, ++ IResult::Incomplete(n) => { ++ self.c_state = ConsumerState::Continue(Move::Await(n)); ++ }, ++ IResult::Done(i,_) => { ++ self.state = State::Done; ++ self.c_state = ConsumerState::Done(Move::Consume(sl.offset(i)), self.counter); ++ } ++ } ++ } ++ } ++ }, ++ State::Done | State::Error => { ++ // this should not be called ++ self.state = State::Error; ++ self.c_state = ConsumerState::Error(()) ++ } ++ }; ++ &self.c_state ++ } ++} ++ ++#[test] ++fn nom1() { ++ let mut p = MemProducer::new(&b"omnomkthxbye"[..], 8); ++ let mut c = TestConsumer{state: State::Beginning, counter: 0, c_state: ConsumerState::Continue(Move::Consume(0))}; ++ while let &ConsumerState::Continue(Move::Consume(_)) = p.apply(&mut c) { ++ } ++ ++ assert_eq!(c.counter, 1); ++ assert_eq!(c.state, State::Done); ++} ++ ++#[test] ++fn nomnomnom() { ++ let mut p = MemProducer::new(&b"omnomnomnomkthxbye"[..], 9); ++ let mut c = TestConsumer{state: State::Beginning, counter: 0, c_state: ConsumerState::Continue(Move::Consume(0))}; ++ while let &ConsumerState::Continue(_) = p.apply(&mut c) { ++ } ++ ++ assert_eq!(c.counter, 3); ++ assert_eq!(c.state, State::Done); ++} ++ ++#[test] ++fn no_nomnom() { ++ let mut p = MemProducer::new(&b"omkthxbye"[..], 8); ++ let mut c = TestConsumer{state: State::Beginning, counter: 0, c_state: ConsumerState::Continue(Move::Consume(0))}; ++ while let &ConsumerState::Continue(_) = p.apply(&mut c) { ++ } ++ ++ assert_eq!(c.counter, 0); ++ assert_eq!(c.state, State::Done); ++} ++ ++/* ++#[test] ++fn impolite() { ++ let mut p = MemProducer::new(&b"omnomnomnom"[..], 11); ++ let mut c = TestConsumer{state: State::Beginning, counter: 0, c_state: ConsumerState::Continue(Move::Consume(0))}; ++ while let &ConsumerState::Continue(cont) = p.apply(&mut c) { ++ println!("continue {:?}", cont); ++ } ++ ++ assert_eq!(c.counter, 3); ++ assert_eq!(c.state, State::End); ++} ++*/ +diff --git third_party/rust/nom-1.2.4/tests/test1.rs third_party/rust/nom-1.2.4/tests/test1.rs +new file mode 100644 +index 000000000000..95f8fd45b6d4 +--- /dev/null ++++ third_party/rust/nom-1.2.4/tests/test1.rs +@@ -0,0 +1,44 @@ ++#![cfg(feature = "stream")] ++ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,Producer,FileProducer,not_line_ending}; ++ ++use std::str; ++use std::fmt::Debug; ++ ++#[test] ++#[allow(unused_must_use)] ++fn tag() { ++ FileProducer::new("assets/links.txt", 20).map(|producer: FileProducer| { ++ let mut p = producer; ++ p.refill(); ++ ++ consumer_from_parser!(PrintConsumer<()>, flat_map!(map_res!(tag!("https!"), str::from_utf8), print)); ++ let mut cs = PrintConsumer::new(); ++ for _ in 1..4 { ++ p.apply(&mut cs); ++ } ++ }); ++} ++ ++pub fn print(input: T) -> IResult { ++ println!("{:?}", input); ++ IResult::Done(input, ()) ++} ++ ++ ++#[test] ++fn is_not() { ++ //is_not!(foo b"\r\n"); ++ named!(foo<&[u8],&[u8]>, is_not!(&b"\r\n"[..])); ++ let a = &b"ab12cd\nefgh"[..]; ++ assert_eq!(foo(a), IResult::Done(&b"\nefgh"[..], &b"ab12cd"[..])); ++} ++ ++#[test] ++fn exported_public_method_defined_by_macro() { ++ let a = &b"ab12cd\nefgh"[..]; ++ assert_eq!(not_line_ending(a), IResult::Done(&b"\nefgh"[..], &b"ab12cd"[..])); ++} +diff --git third_party/rust/nom/.cargo-checksum.json third_party/rust/nom/.cargo-checksum.json +index 9d93bcc0afc2..5baf0864c842 100644 +--- third_party/rust/nom/.cargo-checksum.json ++++ third_party/rust/nom/.cargo-checksum.json +@@ -1 +1 @@ +-{"files":{".travis.yml":"6d4e81838b10c5e330749857c72c2f2b1a2e575e71abcd11c094f3b612347b2a","CHANGELOG.md":"d4722e028b2a5b88c466b0d759e463b90bdcfa1b79181a1c76cd313b0a27c615","Cargo.toml":"aebcb999933c3425db85012bea19f9ce78da8e7834dbab54d4a2966e8bc62149","LICENSE":"de730187d5563a81342a3c011d968f78dff37c934fac9b3701e8c762b6118a55","src/bits.rs":"97c9148f63e175489bb6199d039c594ddc56bdf0b7491b9f38b8d74e898bca80","src/bytes.rs":"8f29b976a5e8e6500eb618a9dead7f212688ba9eb06c7066a4016e2db99fed00","src/character.rs":"9ee081f56b508212231ff70d7455b1b85ae44722a39aa60223e8cd95c6570859","src/internal.rs":"ada499b9c178be2a7f9b56319ffb10a778f25fafcda39c78d26b364d89debd72","src/lib.rs":"34efb051214acfde2053e93a7ba718a4fd41b6e0d9edd65a1737605d99b994ab","src/macros.rs":"d39ce3a2cd2b1cb9dd57ce90c06a1ca84720a2dc75e6332cffebba6086cb75d3","src/methods.rs":"24bdbcb0e3570c8bf3fa270dd8d79dd6dfcb982276c82180a89a1e73c5e38019","src/nom.rs":"b0a9c7ce0d09388179bce8f8e23bf57df76b504d925815583c249ec3fc04baab","src/regexp.rs":"8fdae52b761dbad90179e6be87e0e66357fefa34d76af541fb0fcf550fd6ec08","src/str.rs":"198fa15d45c3636289d92c0a592002a07e5a04a431e8cfdf724266e44d484be2","src/stream.rs":"c1bd5b8e7a2061ff66eb2c954033146001f1d65a26d12efa06af8cf93ffa53e4","src/util.rs":"da40ebac865d3176567d3a37b01170234398a03e938553720ce30aa1f6005b6d","tests/arithmetic.rs":"b98936b7fa0228835ca022f6db5342b72a9c01cc3f16a4e05263bbe6424ba3e9","tests/arithmetic_ast.rs":"b18b9a46ba573ae13c40a31217425f6e8cf8fade09a75cdbbfa7146ec668f0b2","tests/cross_function_backtracking.rs":"b071d13031c1f12195473186e3775943991496b10f4590db3f36d511e9f98a1c","tests/ini.rs":"776f681542028564899e55f71533b3bcda5ed1bbb971f24b5b1b9578111ba0cb","tests/ini_str.rs":"315046d9b6dc38d6d306d3562d7ac6518c9ecce9aabcc58fb80c07577ad99789","tests/issues.rs":"2193c219397b7a417cc009b72c13adc42471e7a4917a2a4009aa0fca23c6ea8c","tests/mp4.rs":"b4bf0514fd645160851cc4da9ad6bf81d571cd14865bf134837c19578caaf6e6","tests/omnom.rs":"409d2349fa24f3503bd02e0079c1554a58ce3d40dd7eb0e5d4bb63b588afdae4","tests/test1.rs":"3e0c187bad91d822ebc113eb5cf30fc6585e53a961728304ac24e05ab2123d10"},"package":"a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"} +\ No newline at end of file ++{"files":{"CHANGELOG.md":"0ca452f3de1955e58ac7e6814077b430c0ee1dbf7e64c5348b6d7b0b997ffb27","Cargo.toml":"69edf4fdee4c17415625f77366f55cf6b3fd7410222c392a2b4bc262bf2e2bc9","LICENSE":"568d0ae12e18bf9dda98fcd838732321852abdb557c24900d474e71f8fd29f4e","src/bits.rs":"8cd8786191145b5365d381ffdf3aedf69002b6a8d40520c7b752c3e6adb83cc9","src/branch.rs":"e298f1d370a25e0a85f34186d38427f5805e745808f98586c2e8c51581e40480","src/bytes.rs":"bf0fe97e34f47d1f5d4ef93d3a00bd7553ae87ea248162cbce8872ea64c44b36","src/character.rs":"3891258d893c09833f6577dee5b9c7af3e12dc2e60458df542a8fcfb8516e068","src/internal.rs":"7be274fd578166404e0b8236417efeaa8a6cda4a8b10ab637083b1d6cba70f1c","src/lib.rs":"14300d7984ea66e052923e0db31b6c99840e5e234cc76042ce94645d2779c7ea","src/macros.rs":"58cde368c072e219ac19a83b7cb6eb9942d57030b2f74426110e8d91e7968145","src/methods.rs":"e6438ac91baec05fb898765879722d55bb54d9e96e29ab823ed34fe571802063","src/multi.rs":"318b4a345b185252515e1373e3fb1302d74ba3a0c65d44c55b4da39bf74a4c29","src/nom.rs":"48acec4a5dd92222823272e38b63e0decf33a31bdd3e97d22ed5d02ae4c6696c","src/regexp.rs":"8a780a8d328b31012a083ca763b8326e7126320a9071ea011629ddb9d82d178a","src/sequence.rs":"20055b97349f135fae182ba3755261439784b3b83572938ed2d9e4eda3c04758","src/simple_errors.rs":"0a37b042eba1c41da6d18b9249f3b7360f1732a5ed43150c39f36877b40594df","src/str.rs":"4cc81376b1d8c48709d73af357141554bbabb4e0546c1bb4606cfdd2ad8082cb","src/stream.rs":"f80895c621aae949a655576fc1082b65235d3e3af5d6a1cafcc9c0d2398264c9","src/traits.rs":"15db8ac6d5f698d9f55d23fbd025dd10f0e461533b34166e6234bf00e443f42e","src/util.rs":"5c8af3f73dff0efe3bcff59ff0c9cdbfeeecc4bafed14763c229a37bf26f7c99","src/verbose_errors.rs":"f640709d9bd8ffffb8baebab8252bc3d55e247a4c4ee814007b7fbda29856233","src/whitespace.rs":"0117cc62c288acd3ba53903fc14fd650934039919039ba5f83195e0435e12535","tests/arithmetic.rs":"aac143de5c80179f9cb71bf3c79268aa892876622b6f08d5e360ab9308f21341","tests/arithmetic_ast.rs":"bb8995cf726ac382e87dd9665f168cba0d25c8cc040372321027d23499ddea99","tests/blockbuf-arithmetic.rs":"485605360f68fc301390eff084657c27cb30347b8eaaed6d92a5830767d50ce6","tests/cross_function_backtracking.rs":"ea847fa762954e1ff8d8e4fbd130e453d57f41132735e4745286a2fbaf10dd6e","tests/float.rs":"7e380464cd8c2c315eaa2bcd3bb7407a4ba558ee5d6adde3ec72492c7987f784","tests/ini.rs":"c3b2b3ccd6b854c36dc89afc8d68877ff7f5cb8b2cb9d8f138e143deb8ee6ddc","tests/ini_str.rs":"7c5db358330be22e1c64900a8182f26881f7e5d38f1c78d827c60de0af68612f","tests/issues.rs":"d9af6f28be33a70732bec51213a4811910c656a1c38c4ffb5b3202efc188b4b6","tests/json.rs":"5d2c2f3f6ebb9f9c188f5b0cfad723a421ce161caceb3d8517d02fc6546fece6","tests/mp4.rs":"0e5f248dc9e27182ff82b3153481df529600bc4418b84f1f0554e1ada6cc3e08","tests/multiline.rs":"5165e95ba471f77dc0e614a716828d71bbcebcd42fe0fb882b7da1d9633222af","tests/named_args.rs":"3954a031e17e55e12e2bbb107c36a29e2204969ee2e4afb9cbd604decfe3f81a","tests/omnom.rs":"ff749d621b51df8aa3db289b1b626c706190fa15e29061dd5653de83635976d4","tests/overflow.rs":"aec98fc65bf102ae934625aa70e2b48cfcce70f4af38d6520716d79df3e95335","tests/reborrow_fold.rs":"8f140330dd0bfb3bbdab8286b4be6d6f698cadb7b064fac586dcca97e3d397fe","tests/test1.rs":"3e0c187bad91d822ebc113eb5cf30fc6585e53a961728304ac24e05ab2123d10"},"package":"05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"} +\ No newline at end of file +diff --git third_party/rust/nom/.travis.yml third_party/rust/nom/.travis.yml +deleted file mode 100644 +index 1d1e36c593aa..000000000000 +--- third_party/rust/nom/.travis.yml ++++ /dev/null +@@ -1,46 +0,0 @@ +-language: rust +- +-addons: +- apt: +- packages: +- - libcurl4-openssl-dev +- - libelf-dev +- - libdw-dev +- +-rust: +- - nightly +- - beta +- - stable +- - 1.2.0 +- +-before_script: +- - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +- +-script: +- - | +- travis-cargo --only 1.2 test -- --features regexp && +- travis-cargo --only stable test -- --features "regexp regexp_macros" && +- travis-cargo --only beta test -- --features "regexp regexp_macros" && +- travis-cargo --only nightly build -- --features "nightly core regexp" && +- travis-cargo --only nightly test -- --features "regexp" && +- travis-cargo bench && +- travis-cargo --only stable doc -- --features "regexp" +- +-after_success: +- - travis-cargo coveralls --no-sudo +- +-notifications: +- webhooks: +- urls: +- - https://webhooks.gitter.im/e/9c035a194ac4fd4cc061 +- on_success: change +- on_failure: always +- on_start: false +- +- +-env: +- global: +- # override the default `--features unstable` used for the nightly branch (optional) +- - TRAVIS_CARGO_NIGHTLY_FEATURE=nightly +- +-sudo: false +diff --git third_party/rust/nom/CHANGELOG.md third_party/rust/nom/CHANGELOG.md +index f1c331585779..35e523666bd4 100644 +--- third_party/rust/nom/CHANGELOG.md ++++ third_party/rust/nom/CHANGELOG.md +@@ -4,6 +4,267 @@ + + ### Changed + ++## 3.2.1 - 2017-10-27 ++ ++### Thanks ++ ++- @ordian for `alt_complete` fixes ++- @friedm for documentation fixes ++- @kali for improving error management ++ ++### Fixed ++ ++- there were cases where `alt_complete` could return `Incomplete` ++ ++### Added ++ ++- an `into_error_kind` method can be used to transform any error to a common value. This helps when the library is included multiple times as dependency with different feature sets ++ ++ ++## 3.2.0 - 2017-07-24 ++ ++### Thanks ++ ++- @jedireza for documentation fixes ++- @gmorenz for the `bytes` combinator ++- @meh for character combinator fixes for UTF-8 ++- @jethrogb for avoiding move issues in `separated_list` ++ ++### Changed ++ ++- new layout for the main page of documentation ++- `anychar` can now work on any input type ++- `length_bytes` is now an alias for `length_data` ++ ++### Fixed ++ ++- `one_of`, `none_of` and `char` will now index correctly UTF-8 characters ++- the `compiler_error` macro is now correctly exported ++ ++ ++### Added ++ ++- the `bytes` combinator transforms a bit stream back to a byte slice for child parsers ++ ++## 3.1.0 - 2017-06-16 ++ ++### Thanks ++ ++- @sdroege: implementing be_i24 and le_i24 ++- @Hywan: integrating faster substring search using memchr ++- @nizox: fixing type issues in bit stream parsing ++- @grissiom: documentation fixes ++- @doomrobo: implementing separated_list_complete and separated_nonempty_list_complete ++- @CWood1: fixing memchr integration in no_std ++- @lu_zero: integrating the compiler_error crate ++- @dtolnay: helping debug a type inference issue in map ++ ++### Changed ++ ++- memchr is used for substring search if possible ++- if building on nightly, some common syntax errors will display a specific error message. If building no stable, display the documentation to activate those messages ++- `count` no longer preallocates its vector ++ ++### Fixed ++ ++- better type inference in alt_complete ++- `alt` should now work with whitespace parsing ++- `map` should not make type inference errors anymore ++ ++### Added ++ ++- be_i24 and le_i24, parsing big endian and little endian signed 24 bit integers ++- `separated_list_complete` and `separated_nonempty_list_complete` will treat incomplete from sub parsers as error ++ ++## 3.0.0 - 2017-05-12 ++ ++### Thanks ++ ++- Chris Pick for some `Incomplete` related refactors ++- @drbgn for documentation fixes ++- @valarauca for adding `be_u24` ++- @ithinuel for usability fixes ++- @evuez for README readability fixes and improvements to `IResult` ++- @s3bk for allowing non-`Copy` types as input ++- @keruspe for documentation fixes ++- @0xd34d10cc for trait fixes on `InputIter` ++- @sdleffler for lifetime shenanigans on `named_args` ++- @chengsun for type inference fixes in `alt` ++- @iBelieve for adding str to no_std ++- @Hywan for simplifying code in input traits ++- @azerupi for extensive documentation of `alt` and `alt_complete` ++ ++### Breaking Changes ++ ++- `escaped`, `separated_list` and `separated_nonempty_list` can now return `Incomplete` when necessary ++- `InputIter` does not require `AsChar` on its `Item` type anymore ++- the `core` feature that was putting nom in `no_std` mode has been removed. There is now a `std` feature, activated by default. If it is not activated, nom is in `no_std` ++- in `verbose-errors` mode, the error list is now stored in a `Vec` instead of a box based linked list ++- `chain!` has finally been removed ++ ++### Changed ++ ++- `Endianness` now implements `Debug`, `PartialEq`, `Eq`, `Clone` and `Copy` ++- custom input types can now be cloned if they're not `Copy` ++- the infamous 'Cannot infer type for E' error should happen less often now ++- `str` is now available in `no_std` mode ++ ++### Fixed ++ ++- `FileProducer` will be marked as `Eof` on full buffer ++- `named_args!` now has lifetimes that cannot conflict with the lifetimes from other arguments ++ ++### Added ++ ++- `be_u24`: big endian 24 bit unsigned integer parsing ++- `IResult` now has a `unwrap_or` method ++ ++ ++## 2.2.1 - 2017-04-03 ++ ++### Thanks ++ ++- @Victor-Savu for formatting fixes in the README ++- @chifflier for detecting and fixing integer overflows ++- @utkarshkukreti for some performance improvements in benchmarks ++ ++### Changed ++ ++- when calculating how much data is needed in `IResult::Incomplete`, the addition could overflow (it is stored as a usize). This would apparently not result in any security vulnerability on release code ++ ++## 2.2.0 - 2017-03-20 ++ ++### Thanks ++ ++- @seppo0010 for fixing `named_args` ++- @keruspe for implementing or() on `IResult`, adding the option of default cases in `switch!`, adding support for `cargo-travis` ++- @timlyo for documentation fixes ++- @JayKickliter for extending `hex_u32` ++- @1011X for fixing regex integration ++- @Kerollmops for actually marking `chain!` as deprecated ++- @joliss for documentation fixes ++- @utkarshkukreti for tests refactoring and performance improvement ++- @tmccombs for documentation fixes ++ ++### Added ++ ++- `IResult` gets an `or()` method ++- `take_until1`, `take_until_and_consume1`, `take_till1!` and `take_till1_s!` require at least 1 character ++ ++### Changed ++ ++- `hex_u32` accepts uppercase digits as well ++- the character based combinators leverage the input traits ++- the whitespace parsers now work on &str and other types ++- `take_while1` returns `Incomplete` on empty input ++- `switch!` can now take a default case ++ ++### Fixed ++ ++- `named_args!` now imports `IResult` directly ++- the upgrade to regex 0.2 broke the regex combinators, they work now ++ ++## 2.1.0 - 2017-01-27 ++ ++### Thanks ++ ++- @nickbabcock for documentation fixes ++- @derekdreery for documentation fixes ++- @DirkyJerky for documentation fixes ++- @saschagrunert for documentation fixes ++- @lucab for documentation fixes ++- @hyone for documentation fixes ++- @tstorch for factoring `Slice` ++- @shepmaster for adding crate categories ++- @antoyo for adding `named_args!` ++ ++### Added ++ ++- `verify!` uses a first parser, then applies a function to check that its result satisfies some conditions ++- `named_args!` creates a parser function that can accept other arguments along with the input ++- `parse_to!` will use the `parse` method from `FromStr` to parse a value. It will automatically translate the input to a string if necessary ++- `float`, `float_s`, `double`, `double_s` can recognize floating point numbers in text ++ ++### Changed ++ ++- `escaped!` will now return `Incomplete` if needed ++- `permutation!` supports up to 20 child parsers ++ ++## 2.0.1 - 2016-12-10 ++ ++Bugfix release ++ ++*Warning*: there is a small breaking change, `add_error!` is renamed to `add_return_error!`. This was planned for the 2.0 release but was forgotten. This is a small change in a feature that not many people use, for a release that is not yet widely in use, so there will be no 3.0 release for that change. ++ ++### Thanks ++ ++- @nickbabcock for catching and fixing the `add_error!` mixup ++- @lucab for documentation fixes ++- @jtdowney for noticing that `tag_no_case!` was not working at all for byte slices ++ ++### Fixed ++ ++- `add_error!` has been renamed to `add_return_error!` ++- the `not!` combinator now accepts functions ++- `tag_no_case!` is now working as accepted (before, it accepted everything) ++ ++ ++## 2.0 - 2016-11-25 ++ ++The 2.0 release is one of the biggest yet. It was a good opportunity to clean up some badly named combinators and fix invalid behaviours. ++ ++Since this version introduces a few breaking changes, an [upgrade documentation](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_2.md) is available, detailing the steps to fix the most common migration issues. After testing on a set of 30 crates, most of them will build directly, a large part will just need to activate the "verbose-errors" compilation feature. The remaining fixes are documented. ++ ++This version also adds a lot of interesting features, like the permutation combinator or whitespace separated formats support. ++ ++### Thanks ++ ++- @lu-zero for license help ++- @adamgreig for type inference fixes ++- @keruspe for documentation and example fixes, for the `IResult => Result` conversion work, making `AsChar`'s method more consistent, and adding `many_till!` ++- @jdeeny for implementing `Offset` on `&str` ++- @vickenty for documentation fixes and his refactoring of `length_value!` and `length_bytes!` ++- @overdrivenpotato for refactoring some combinators ++- @taralx for documentation fixes ++- @keeperofdakeys for fixing eol behaviour, writing documentation and adding `named_attr!` ++- @jturner314 for writing documentation ++- @bozaro for fixing compilation errors ++- @uniphil for adding a `crates.io` badge ++- @badboy for documentation fixes ++- @jugglerchris for fixing `take_s!` ++- @AndyShiue for implementing `Error` and `Display` on `ErrorKind` and detecting incorrect UTF-8 string indexing ++ ++### Added ++ ++- the "simple" error management system does not accumulates errors when backtracking. This is a big perf gain, and is activated by default in nom 2.0 ++- nom can now work on any type that implement the traits defined in `src/traits.rs`: `InputLength`, `InputIter`, `InputTake`, `Compare`, `FindToken`, `FindSubstring`, `Slice` ++- the documentation from Github's wiki has been moved to the `doc/` directory. They are markdown files that you can build with [cargo-external-doc](https://crates.io/crates/cargo-external-doc) ++- whitespace separated format support: with the `ws!` combinator, you can automatically introduce whitespace parsers between all parsers and combinators ++- the `permutation!` combinator applies its child parsers in any order, as long as they all succeed once, and return a tuple of the results ++- `do_parse!` is a simpler alternative to `chain!`, which is now deprecated ++- you can now transform an `IResult` in a `std::result::Result` ++- `length_data!` parses a length, and returns a subslice of that length ++- `tag_no_case!` provides case independent comparison. It works nicely, without any allocation, for ASCII strings, but for UTF-8 strings, it defaults to an unsatisfying (and incorrect) comparison by lowercasing both strings ++- `named_attr!` creates functions like `named!` but can add attributes like documentation ++- `many_till!` applies repeatedly its first child parser until the second succeeds ++ ++### Changed ++ ++- the "verbose" error management that was available in previous versions is now activated by the "verbose-errors" compilation feature ++- code reorganization: most of the parsers were moved in separate files to make the source easier to navigate ++- most of the combinators are now independent from the input type ++- the `eof` function was replaced with the `eof!` macro ++- `error!` and `add_error!` were replaced with `return_error!` and `add_return_error!` to fix the name conflict with the log crate ++- the `offset()` method is now in the `Offset` trait ++- `length_value!` has been renamed to `length_count!`. The new `length_value!` selects a slice and applies the second parser once on that slice ++- `AsChar::is_0_to_9` is now `AsChar::is_dec_digit` ++- the combinators with configurable endianness now take an enum instead of a boolean as parameter ++ ++### Fixed ++- the `count!`, `count_fixed!` and `length_*!` combinator calculate incomplete data needs correctly ++- `eol`, `line_ending` and `not_line_ending` now have a consistent behaviour that works correctly with incomplete data ++- `take_s!` didn't correctly handle the case when the slice is exactly the right length ++ + ## 1.2.4 - 2016-07-20 + + ### Thanks +@@ -29,14 +290,14 @@ + - `take_bits!` is now more precise + - `many1` inccorectly used the `len` function instead of `input_len` + - the INI parser is simpler +-- `recognize!` had an early `return` taht is removed now ++- `recognize!` had an early `return` that is removed now + + ## 1.2.3 - 2016-05-10 + + ### Thanks + - @lu-zero for the contribution guidelines + - @GuillaumeGomez for fixes on `length_bytes` and some documentation +-- @Hywan for ducomentation and test fixes ++- @Hywan for documentation and test fixes + - @Xirdus for correct trait import issues + - @mspiegel for the new AST example + - @cholcombe973 for adding the `cond_with_error!` combinator +@@ -63,7 +324,7 @@ + ## 1.2.2 - 2016-03-09 + + ### Thanks +-- @conradev for fixing take_until_s!` ++- @conradev for fixing `take_until_s!` + - @GuillaumeGomez for some documentation fixes + - @frewsxcv for some documentation fixes + - @tstorch for some test refactorings +@@ -121,7 +382,7 @@ + - there were type inference issues in a few combinators. They will now be easier to compile + - `peek!` compilation with bare functions + - `&str` parsers were splitting data at the byte level, not at the char level, which can result in inconsistencies in parsing UTF-8 characters. They now use character indexes +-- some method implementations were missing on `ÌResult` (with specified error type instead of implicit) ++- some method implementations were missing on `IResult` (with specified error type instead of implicit) + + ## 1.1.0 - 2016-01-01 + +@@ -137,11 +398,11 @@ There are also a few performance improvements and documentation fixes. + - @meh for fixing `Option` and `Vec` imports + - @hoodie for a documentation fix + - @joelself for some documentation fixes +-- @vberger for his traits magic making `nom functions more generic ++- @vberger for his traits magic making nom functions more generic + + ### Added + +-- string related parsers: `tag_s!`, `take_s!`, `is_a_s!`, `is_not_s!`, `take_while_s!`, `take_while1_s!`, `take_till_s! ++- string related parsers: `tag_s!`, `take_s!`, `is_a_s!`, `is_not_s!`, `take_while_s!`, `take_while1_s!`, `take_till_s!` + - `value!` is a combinator that always returns the same value. If a child parser is passed as second argument, that value is returned when the child parser succeeds + + ### Changed +@@ -521,8 +782,17 @@ Considering the number of changes since the last release, this version can conta + + ## Compare code + +-* [unreleased]: https://github.com/Geal/nom/compare/1.2.4...HEAD +-* [1.2.3]: https://github.com/Geal/nom/compare/1.2.3...1.2.4 ++* [unreleased]: https://github.com/Geal/nom/compare/3.2.1...HEAD ++* [3.2.1]: https://github.com/Geal/nom/compare/3.2.0...3.2.1 ++* [3.2.0]: https://github.com/Geal/nom/compare/3.1.0...3.2.0 ++* [3.1.0]: https://github.com/Geal/nom/compare/3.0.0...3.1.0 ++* [3.0.0]: https://github.com/Geal/nom/compare/2.2.1...3.0.0 ++* [2.2.1]: https://github.com/Geal/nom/compare/2.2.0...2.2.1 ++* [2.2.0]: https://github.com/Geal/nom/compare/2.1.0...2.2.0 ++* [2.1.0]: https://github.com/Geal/nom/compare/2.0.1...2.1.0 ++* [2.0.1]: https://github.com/Geal/nom/compare/2.0.0...2.0.1 ++* [2.0.0]: https://github.com/Geal/nom/compare/1.2.4...2.0.0 ++* [1.2.4]: https://github.com/Geal/nom/compare/1.2.3...1.2.4 + * [1.2.3]: https://github.com/Geal/nom/compare/1.2.2...1.2.3 + * [1.2.2]: https://github.com/Geal/nom/compare/1.2.1...1.2.2 + * [1.2.1]: https://github.com/Geal/nom/compare/1.2.0...1.2.1 +diff --git third_party/rust/nom/Cargo.toml third_party/rust/nom/Cargo.toml +index ae8045bf1135..1ee10cf12c2b 100644 +--- third_party/rust/nom/Cargo.toml ++++ third_party/rust/nom/Cargo.toml +@@ -1,38 +1,50 @@ +-[package] ++# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO ++# ++# When uploading crates to the registry Cargo will automatically ++# "normalize" Cargo.toml files for maximal compatibility ++# with all versions of Cargo and also rewrite `path` dependencies ++# to registry (e.g. crates.io) dependencies ++# ++# If you believe there's an error in this file please file an ++# issue against the rust-lang/cargo repository. If you're ++# editing this file be aware that the upstream Cargo.toml ++# will likely look very different (and much more reasonable) + ++[package] + name = "nom" +-version = "1.2.4" +-authors = [ "contact@geoffroycouprie.com" ] ++version = "3.2.1" ++authors = ["contact@geoffroycouprie.com"] ++include = ["CHANGELOG.md", "LICENSE", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "tests/*.rs"] + description = "A byte-oriented, zero-copy, parser combinators library" +-license = "MIT" +-repository = "https://github.com/Geal/nom" +-readme = "README.md" + documentation = "http://rust.unhandledexpression.com/nom/" ++readme = "README.md" + keywords = ["parser", "parser-combinators", "parsing", "streaming", "bit"] ++categories = ["parsing"] ++license = "MIT" ++repository = "https://github.com/Geal/nom" ++[dependencies.memchr] ++version = "^1.0.1" ++default-features = false + +-include = [ +- "CHANGELOG.md", +- "LICENSE", +- ".gitignore", +- ".travis.yml", +- "Cargo.toml", +- "src/*.rs", +- "tests/*.rs" +-] +- +-[features] +-core = [] +-nightly = [] +-default = ["stream"] +-regexp = ["regex"] +-regexp_macros = ["regexp", "lazy_static"] +-stream = [] ++[dependencies.compiler_error] ++version = "0.1.1" ++optional = true + + [dependencies.regex] +-version = "^0.1.56" ++version = "^0.2" + optional = true + + [dependencies.lazy_static] +-version = "^0.2.1" ++version = "^0.2.2" + optional = true + ++[features] ++default = ["std", "stream"] ++regexp = ["regex"] ++verbose-errors = [] ++stream = [] ++nightly = ["compiler_error"] ++regexp_macros = ["regexp", "lazy_static"] ++std = ["memchr/use_std"] ++[badges.travis-ci] ++repository = "Geal/nom" +diff --git third_party/rust/nom/LICENSE third_party/rust/nom/LICENSE +index 0bd6a1c33dc6..a885458136ae 100644 +--- third_party/rust/nom/LICENSE ++++ third_party/rust/nom/LICENSE +@@ -1,4 +1,4 @@ +-Copyright (c) 2015 Geoffroy Couprie ++Copyright (c) 2015-2016 Geoffroy Couprie + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +diff --git third_party/rust/nom/src/bits.rs third_party/rust/nom/src/bits.rs +index a8bd8b24aa99..d475cd32ebcd 100644 +--- third_party/rust/nom/src/bits.rs ++++ third_party/rust/nom/src/bits.rs +@@ -36,6 +36,7 @@ macro_rules! bits ( + ); + ); + ++#[cfg(feature = "verbose-errors")] + /// Internal parser, do not use directly + #[doc(hidden)] + #[macro_export] +@@ -44,7 +45,7 @@ macro_rules! bits_impl ( + { + let input = ($i, 0usize); + match $submac!(input, $($args)*) { +- $crate::IResult::Error(e) => { ++ $crate::IResult::Error(e) => { + let err = match e { + $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k), + $crate::Err::Position(k, (i,b)) | $crate::Err::NodePosition(k, (i,b), _) => { +@@ -68,6 +69,131 @@ macro_rules! bits_impl ( + ); + ); + ++#[cfg(not(feature = "verbose-errors"))] ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! bits_impl ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let input = ($i, 0usize); ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(e) => { ++ $crate::IResult::Error(e) ++ } ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ //println!("bits parser returned Needed::Size({})", i); ++ $crate::IResult::Incomplete($crate::Needed::Size(i / 8 + 1)) ++ }, ++ $crate::IResult::Done((i, bit_index), o) => { ++ let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ; ++ //println!("bit index=={} => byte index=={}", bit_index, byte_index); ++ $crate::IResult::Done(&i[byte_index..], o) ++ } ++ } ++ } ++ ); ++); ++ ++/// Counterpart to bits, ++/// `bytes!( parser ) => ( (&[u8], usize), &[u8] -> IResult<&[u8], T> ) -> IResult<(&[u8], usize), T>`, ++/// transforms its bits stream input into a byte slice for the underlying parsers. If we start in the ++/// middle of a byte throws away the bits until the end of the byte. ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::rest; ++/// # fn main() { ++/// named!( parse<(u8, u8, &[u8])>, bits!( tuple!( ++/// take_bits!(u8, 4), ++/// take_bits!(u8, 8), ++/// bytes!(rest) ++/// ))); ++/// ++/// let input = &[0xde, 0xad, 0xbe, 0xaf]; ++/// ++/// assert_eq!(parse( input ), Done(&[][..], (0xd, 0xea, &[0xbe, 0xaf][..]))); ++/// # } ++#[macro_export] ++macro_rules! bytes ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ bytes_impl!($i, $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr) => ( ++ bytes_impl!($i, call!($f)); ++ ); ++); ++ ++#[cfg(feature = "verbose-errors")] ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! bytes_impl ( ++ ($macro_i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let inp; ++ if $macro_i.1 % 8 != 0 { ++ inp = & $macro_i.0[1 + $macro_i.1 / 8 ..]; ++ } ++ else { ++ inp = & $macro_i.0[$macro_i.1 / 8 ..]; ++ } ++ ++ match $submac!(inp, $($args)*) { ++ $crate::IResult::Error(e) => { ++ let err = match e { ++ $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k), ++ $crate::Err::Position(k, i) | $crate::Err::NodePosition(k, i, _) => { ++ $crate::Err::Position(k, (i, 0)) ++ } ++ }; ++ $crate::IResult::Error(err) ++ } ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ $crate::IResult::Incomplete($crate::Needed::Size(i * 8)) ++ }, ++ $crate::IResult::Done(i, o) => { ++ $crate::IResult::Done((i, 0), o) ++ } ++ } ++ } ++ ); ++); ++ ++#[cfg(not(feature = "verbose-errors"))] ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! bytes_impl ( ++ ($macro_i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let inp; ++ if $macro_i.1 % 8 != 0 { ++ inp = & $macro_i.0[1 + $macro_i.1 / 8 ..]; ++ } ++ else { ++ inp = & $macro_i.0[$macro_i.1 / 8 ..]; ++ } ++ ++ match $submac!(inp, $($args)*) { ++ $crate::IResult::Error(e) => { ++ $crate::IResult::Error(e) ++ } ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ $crate::IResult::Incomplete($crate::Needed::Size(i * 8)) ++ }, ++ $crate::IResult::Done(i, o) => { ++ $crate::IResult::Done((i, 0), o) ++ } ++ } ++ } ++ ); ++); ++ + /// `take_bits!(type, nb) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>` + /// generates a parser consuming the specified number of bits. + /// +@@ -89,17 +215,18 @@ macro_rules! take_bits ( + ($i:expr, $t:ty, $count:expr) => ( + { + use std::ops::Div; ++ use std::convert::Into; + //println!("taking {} bits from {:?}", $count, $i); + let (input, bit_offset) = $i; + let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 { +- $crate::IResult::Done( (input, bit_offset), 0) ++ $crate::IResult::Done( (input, bit_offset), (0 as u8).into()) + } else { + let cnt = ($count as usize + bit_offset).div(8); + if input.len() * 8 < $count as usize + bit_offset { + //println!("returning incomplete: {}", $count as usize + bit_offset); + $crate::IResult::Incomplete($crate::Needed::Size($count as usize)) + } else { +- let mut acc:$t = 0; ++ let mut acc:$t = (0 as u8).into(); + let mut offset: usize = bit_offset; + let mut remaining: usize = $count; + let mut end_offset: usize = 0; +@@ -109,9 +236,9 @@ macro_rules! take_bits ( + break; + } + let val: $t = if offset == 0 { +- *byte as $t ++ (*byte as u8).into() + } else { +- ((*byte << offset) as u8 >> offset) as $t ++ (((*byte as u8) << offset) as u8 >> offset).into() + }; + + if remaining < 8 - offset { +@@ -144,11 +271,11 @@ macro_rules! tag_bits ( + let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o); + res + } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i)) ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TagBits, $i)) + } + }, + _ => { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i)) ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TagBits, $i)) + } + } + } +@@ -157,12 +284,13 @@ macro_rules! tag_bits ( + + #[cfg(test)] + mod tests { +- use internal::{IResult,Needed,Err}; ++ use std::ops::{Shr,Shl,AddAssign}; ++ use internal::{IResult,Needed}; + use ErrorKind; + + #[test] + fn take_bits() { +- let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let input = [0b10101010, 0b11110000, 0b00110011]; + let sl = &input[..]; + + assert_eq!(take_bits!( (sl, 0), u8, 0 ), IResult::Done((sl, 0), 0)); +@@ -184,7 +312,7 @@ mod tests { + + #[test] + fn tag_bits() { +- let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let input = [0b10101010, 0b11110000, 0b00110011]; + let sl = &input[..]; + + assert_eq!(tag_bits!( (sl, 0), u8, 3, 0b101), IResult::Done((&sl[0..], 3), 5)); +@@ -192,17 +320,17 @@ mod tests { + } + + named!(ch<(&[u8],usize),(u8,u8)>, +- chain!( +- tag_bits!(u8, 3, 0b101) ~ +- x: take_bits!(u8, 4) ~ +- y: take_bits!(u8, 5) , +- || { (x,y) } ++ do_parse!( ++ tag_bits!(u8, 3, 0b101) >> ++ x: take_bits!(u8, 4) >> ++ y: take_bits!(u8, 5) >> ++ (x,y) + ) + ); + + #[test] + fn chain_bits() { +- let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let input = [0b10101010, 0b11110000, 0b00110011]; + let sl = &input[..]; + assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15))); + assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16))); +@@ -212,9 +340,55 @@ mod tests { + named!(ch_bytes<(u8,u8)>, bits!(ch)); + #[test] + fn bits_to_bytes() { +- let input = vec![0b10101010, 0b11110000, 0b00110011]; ++ let input = [0b10101010, 0b11110000, 0b00110011]; + assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15))); + assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2))); +- assert_eq!(ch_bytes(&input[1..]), IResult::Error(Err::Position(ErrorKind::TagBits, &input[1..]))); ++ assert_eq!(ch_bytes(&input[1..]), IResult::Error(error_position!(ErrorKind::TagBits, &input[1..]))); ++ } ++ ++ #[derive(PartialEq,Debug)] ++ struct FakeUint(u32); ++ ++ impl AddAssign for FakeUint { ++ ++ fn add_assign(&mut self, other: FakeUint) { ++ *self = FakeUint(&self.0 + other.0); ++ } ++ ++ } ++ ++ impl Shr for FakeUint { ++ type Output = FakeUint; ++ ++ fn shr(self, shift: usize) -> FakeUint { ++ FakeUint(&self.0 >> shift) ++ } ++ ++ } ++ ++ impl Shl for FakeUint { ++ type Output = FakeUint; ++ ++ fn shl(self, shift: usize) -> FakeUint { ++ FakeUint(&self.0 << shift) ++ } ++ ++ } ++ ++ impl From for FakeUint { ++ ++ fn from(i: u8) -> FakeUint { ++ FakeUint(u32::from(i)) ++ } ++ } ++ ++ #[test] ++ fn non_privitive_type() { ++ let input = [0b10101010, 0b11110000, 0b00110011]; ++ let sl = &input[..]; ++ ++ assert_eq!(take_bits!( (sl, 0), FakeUint, 20 ), IResult::Done((&sl[2..], 4), FakeUint(700163))); ++ assert_eq!(take_bits!( (sl, 4), FakeUint, 20 ), IResult::Done((&sl[3..], 0), FakeUint(716851))); ++ assert_eq!(take_bits!( (sl, 4), FakeUint, 22 ), IResult::Incomplete(Needed::Size(22))); + } + } +diff --git third_party/rust/nom/src/branch.rs third_party/rust/nom/src/branch.rs +new file mode 100644 +index 000000000000..a925437145a0 +--- /dev/null ++++ third_party/rust/nom/src/branch.rs +@@ -0,0 +1,871 @@ ++/// Try a list of parsers and return the result of the first successful one ++/// ++/// ```rust,ignore ++/// alt!(I -> IResult | I -> IResult | ... | I -> IResult ) => I -> IResult ++/// ``` ++/// All the parsers must have the same return type. ++/// ++/// If one of the parsers returns `Incomplete`, `alt!` will return `Incomplete`, to retry ++/// once you get more input. Note that it is better for performance to know the ++/// minimum size of data you need before you get into `alt!`. ++/// ++/// The `alt!` combinator is used in the following way: ++/// ++/// ```rust,ignore ++/// alt!(parser_1 | parser_2 | ... | parser_n) ++/// ``` ++/// ++/// # Basic example ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # fn main() { ++/// // Create a parser that will match either "dragon" or "beast" ++/// named!( dragon_or_beast, alt!( tag!( "dragon" ) | tag!( "beast" ) ) ); ++/// ++/// // Given the input "dragon slayer", the parser will match "dragon" ++/// // and the rest will be " slayer" ++/// let (rest, result) = dragon_or_beast(b"dragon slayer").unwrap(); ++/// assert_eq!(result, b"dragon"); ++/// assert_eq!(rest, b" slayer"); ++/// ++/// // Given the input "beast of Gevaudan", the parser will match "beast" ++/// // and the rest will be " of Gevaudan" ++/// let (rest, result) = dragon_or_beast(&b"beast of Gevaudan"[..]).unwrap(); ++/// assert_eq!(result, b"beast"); ++/// assert_eq!(rest, b" of Gevaudan"); ++/// # } ++/// ``` ++/// ++/// # Manipulate results ++/// ++/// There exists another syntax for `alt!` that gives you the ability to ++/// manipulate the result from each parser: ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// # ++/// // We create an enum to represent our creatures ++/// #[derive(Debug,PartialEq,Eq)] ++/// enum Creature { ++/// Dragon, ++/// Beast, ++/// Unknown(usize) ++/// } ++/// ++/// // Let's make a helper function that returns true when not a space ++/// // we are required to do this because the `take_while!` macro is limited ++/// // to idents, so we can't negate `ìs_space` at the call site ++/// fn is_not_space(c: u8) -> bool { ! nom::is_space(c) } ++/// ++/// // Our parser will return the `Dragon` variant when matching "dragon", ++/// // the `Beast` variant when matching "beast" and otherwise it will consume ++/// // the input until a space is found and return an `Unknown` creature with ++/// // the size of it's name. ++/// named!(creature, alt!( ++/// tag!("dragon") => { |_| Creature::Dragon } | ++/// tag!("beast") => { |_| Creature::Beast } | ++/// take_while!(is_not_space) => { |r: &[u8]| Creature::Unknown(r.len()) } ++/// // the closure takes the result as argument if the parser is successful ++/// )); ++/// ++/// // Given the input "dragon slayer" the parser will return `Creature::Dragon` ++/// // and the rest will be " slayer" ++/// let (rest, result) = creature(b"dragon slayer").unwrap(); ++/// assert_eq!(result, Creature::Dragon); ++/// assert_eq!(rest, b" slayer"); ++/// ++/// // Given the input "beast of Gevaudan" the parser will return `Creature::Beast` ++/// // and the rest will be " of Gevaudan" ++/// let (rest, result) = creature(b"beast of Gevaudan").unwrap(); ++/// assert_eq!(result, Creature::Beast); ++/// assert_eq!(rest, b" of Gevaudan"); ++/// ++/// // Given the input "demon hunter" the parser will return `Creature::Unkown(5)` ++/// // and the rest will be " hunter" ++/// let (rest, result) = creature(b"demon hunter").unwrap(); ++/// assert_eq!(result, Creature::Unknown(5)); ++/// assert_eq!(rest, b" hunter"); ++/// # } ++/// ``` ++/// ++/// # Behaviour of `alt!` ++/// ++/// **BE CAREFUL** there is a case where the behaviour of `alt!` can be confusing: ++/// ++/// when the alternatives have different lengths, like this case: ++/// ++/// ```ignore ++/// named!( test, alt!( tag!( "abcd" ) | tag!( "ef" ) | tag!( "ghi" ) | tag!( "kl" ) ) ); ++/// ``` ++/// ++/// With this parser, if you pass `"abcd"` as input, the first alternative parses it correctly, ++/// but if you pass `"efg"`, the first alternative will return `Incomplete`, since it needs an input ++/// of 4 bytes. This behaviour of `alt!` is expected: if you get a partial input that isn't matched ++/// by the first alternative, but would match if the input was complete, you want `alt!` to indicate ++/// that it cannot decide with limited information. ++/// ++/// There are two ways to fix this behaviour. The first one consists in ordering the alternatives ++/// by size, like this: ++/// ++/// ```ignore ++/// named!( test, alt!( tag!( "ef" ) | tag!( "kl") | tag!( "ghi" ) | tag!( "abcd" ) ) ); ++/// ``` ++/// ++/// With this solution, the largest alternative will be tested last. ++/// ++/// The other solution uses the `complete!` combinator, which transforms an `Incomplete` in an ++/// `Error`. If one of the alternatives returns `Incomplete` but is wrapped by `complete!`, ++/// `alt!` will try the next alternative. This is useful when you know that ++/// you will not get partial input: ++/// ++/// ```ignore ++/// named!( test, ++/// alt!( ++/// complete!( tag!( "abcd" ) ) | ++/// complete!( tag!( "ef" ) ) | ++/// complete!( tag!( "ghi" ) ) | ++/// complete!( tag!( "kl" ) ) ++/// ) ++/// ); ++/// ``` ++/// ++/// If you want the `complete!` combinator to be applied to all rules then use the convenience ++/// `alt_complete!` macro (see below). ++/// ++/// This behaviour of `alt!` can get especially confusing if multiple alternatives have different ++/// sizes but a common prefix, like this: ++/// ++/// ```ignore ++/// named!( test, alt!( tag!( "abcd" ) | tag!( "ab" ) | tag!( "ef" ) ) ); ++/// ``` ++/// ++/// in that case, if you order by size, passing `"abcd"` as input will always be matched by the ++/// smallest parser, so the solution using `complete!` is better suited. ++/// ++/// You can also nest multiple `alt!`, like this: ++/// ++/// ```ignore ++/// named!( test, ++/// alt!( ++/// preceded!( ++/// tag!("ab"), ++/// alt!( ++/// tag!( "cd" ) | ++/// eof!() ++/// ) ++/// ) ++/// | tag!( "ef" ) ++/// ) ++/// ); ++/// ``` ++/// ++/// `preceded!` will first parse `"ab"` then, if successful, try the alternatives "cd", ++/// or empty input (End Of File). If none of them work, `preceded!` will fail and ++/// "ef" will be tested. ++/// ++#[macro_export] ++macro_rules! alt ( ++ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)* ) => ( ++ compiler_error!("alt uses '|' as separator, not ',': ++ ++ alt!( ++ tag!(\"abcd\") | ++ tag!(\"efgh\") | ++ tag!(\"ijkl\") ++ ) ++ "); ++ ); ++ (__impl $i:expr, $e:ident, $($rest:tt)* ) => ( ++ alt!(__impl $i, call!($e) , $($rest)*); ++ ); ++ (__impl $i:expr, $e:ident | $($rest:tt)*) => ( ++ alt!(__impl $i, call!($e) | $($rest)*); ++ ); ++ ++ (__impl $i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ let res = $subrule!(i_, $($args)*); ++ match res { ++ $crate::IResult::Done(_,_) => res, ++ $crate::IResult::Incomplete(_) => res, ++ $crate::IResult::Error(e) => { ++ let out = alt!(__impl $i, $($rest)*); ++ ++ // Compile-time hack to ensure that res's E type is not under-specified. ++ // This all has no effect at runtime. ++ fn unify_types(_: &T, _: &T) {} ++ if let $crate::IResult::Error(ref e2) = out { ++ unify_types(&e, e2); ++ } ++ ++ out ++ } ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ match $subrule!(i_, $($args)* ) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(e) => { ++ let out = alt!(__impl $i, $($rest)*); ++ ++ // Compile-time hack to ensure that res's E type is not under-specified. ++ // This all has no effect at runtime. ++ fn unify_types(_: &T, _: &T) {} ++ if let $crate::IResult::Error(ref e2) = out { ++ unify_types(&e, e2); ++ } ++ ++ out ++ } ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => ( ++ alt!(__impl $i, call!($e) => { $gen } | $($rest)*); ++ ); ++ ++ (__impl $i:expr, __end) => ( ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Alt,$i)) ++ ); ++ ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ alt!(__impl $i, $($rest)* | __end) ++ } ++ ); ++); ++ ++/// Is equivalent to the `alt!` combinator, except that it will not return `Incomplete` ++/// when one of the constituting parsers returns `Incomplete`. Instead, it will try the ++/// next alternative in the chain. ++/// ++/// You should use this combinator only if you know you ++/// will not receive partial input for the rules you're trying to match (this ++/// is almost always the case for parsing programming languages). ++/// ++/// ```rust,ignore ++/// alt_complete!(I -> IResult | I -> IResult | ... | I -> IResult ) => I -> IResult ++/// ``` ++/// All the parsers must have the same return type. ++/// ++/// If one of the parsers return `Incomplete`, `alt_complete!` will try the next alternative. ++/// If there is no other parser left to try, an `Error` will be returned. ++/// ++/// ```rust,ignore ++/// alt_complete!(parser_1 | parser_2 | ... | parser_n) ++/// ``` ++/// **For more in depth examples, refer to the documentation of `alt!`** ++#[macro_export] ++macro_rules! alt_complete ( ++ // Recursive rules (must include `complete!` around the head) ++ ++ ($i:expr, $e:ident | $($rest:tt)*) => ( ++ alt_complete!($i, complete!(call!($e)) | $($rest)*); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ let res = complete!(i_, $subrule!($($args)*)); ++ match res { ++ $crate::IResult::Done(_,_) => res, ++ e => { ++ let out = alt_complete!($i, $($rest)*); ++ ++ if let (&$crate::IResult::Error(ref e1), &$crate::IResult::Error(ref e2)) = (&e, &out) { ++ // Compile-time hack to ensure that res's E type is not under-specified. ++ // This all has no effect at runtime. ++ fn unify_types(_: &T, _: &T) {} ++ unify_types(e1, e2); ++ } ++ ++ out ++ }, ++ } ++ } ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( ++ { ++ let i_ = $i.clone(); ++ match complete!(i_, $subrule!($($args)*)) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ e => { ++ let out = alt_complete!($i, $($rest)*); ++ ++ if let (&$crate::IResult::Error(ref e1), &$crate::IResult::Error(ref e2)) = (&e, &out) { ++ // Compile-time hack to ensure that res's E type is not under-specified. ++ // This all has no effect at runtime. ++ fn unify_types(_: &T, _: &T) {} ++ unify_types(e1, e2); ++ } ++ ++ out ++ }, ++ } ++ } ++ ); ++ ++ ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => ( ++ alt_complete!($i, complete!(call!($e)) => { $gen } | $($rest)*); ++ ); ++ ++ // Tail (non-recursive) rules ++ ++ ($i:expr, $e:ident => { $gen:expr }) => ( ++ alt_complete!($i, call!($e) => { $gen }); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( ++ alt!(__impl $i, complete!($subrule!($($args)*)) => { $gen } | __end) ++ ); ++ ++ ($i:expr, $e:ident) => ( ++ alt_complete!($i, call!($e)); ++ ); ++ ++ ($i:expr, $subrule:ident!( $($args:tt)*)) => ( ++ alt!(__impl $i, complete!($subrule!($($args)*)) | __end) ++ ); ++); ++ ++/// `switch!(I -> IResult, P => I -> IResult | ... | P => I -> IResult ) => I -> IResult` ++/// choose the next parser depending on the result of the first one, if successful, ++/// and returns the result of the second parser ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::{Position, NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => tag!("XYZ") | ++/// b"efgh" => tag!("123") ++/// ) ++/// ); ++/// ++/// let a = b"abcdXYZ123"; ++/// let b = b"abcdef"; ++/// let c = b"efgh123"; ++/// let d = b"blah"; ++/// ++/// assert_eq!(sw(&a[..]), Done(&b"123"[..], &b"XYZ"[..])); ++/// assert_eq!(sw(&b[..]), Error(error_node_position!(ErrorKind::Switch, &b"abcdef"[..], ++/// error_position!(ErrorKind::Tag, &b"ef"[..])))); ++/// assert_eq!(sw(&c[..]), Done(&b""[..], &b"123"[..])); ++/// assert_eq!(sw(&d[..]), Error(error_position!(ErrorKind::Switch, &b"blah"[..]))); ++/// # } ++/// ``` ++/// ++/// You can specify a default case like with a normal match, using `_` ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => tag!("XYZ") | ++/// _ => value!(&b"default"[..]) ++/// ) ++/// ); ++/// ++/// let a = b"abcdXYZ123"; ++/// let b = b"blah"; ++/// ++/// assert_eq!(sw(&a[..]), Done(&b"123"[..], &b"XYZ"[..])); ++/// assert_eq!(sw(&b[..]), Done(&b""[..], &b"default"[..])); ++/// # } ++/// ``` ++/// ++/// Due to limitations in Rust macros, it is not possible to have simple functions on the right hand ++/// side of pattern, like this: ++/// ++/// ```ignore ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => tag!("XYZ") | ++/// b"efgh" => tag!("123") ++/// ) ++/// ); ++/// ``` ++/// ++/// If you want to pass your own functions instead, you can use the `call!` combinator as follows: ++/// ++/// ```ignore ++/// named!(xyz, tag!("XYZ")); ++/// named!(num, tag!("123")); ++/// named!(sw, ++/// switch!(take!(4), ++/// b"abcd" => call!(xyz) | ++/// b"efgh" => call!(num) ++/// ) ++/// ); ++/// ``` ++/// ++#[macro_export] ++macro_rules! switch ( ++ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => ( ++ { ++ let i_ = $i.clone(); ++ match map!(i_, $submac!($($args)*), |o| Some(o)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(error_node_position!( ++ $crate::ErrorKind::Switch, $i, e ++ )), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ match o { ++ $(Some($p) => match $subrule!(i, $($args2)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(error_node_position!( ++ $crate::ErrorKind::Switch, $i, e ++ )), ++ a => a, ++ }),*, ++ _ => $crate::IResult::Error(error_position!($crate::ErrorKind::Switch,$i)) ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)*), $($rest:tt)*) => ( ++ { ++ switch!(__impl $i, $submac!($($args)*), $($rest)*) ++ } ++ ); ++ ($i:expr, $e:ident, $($rest:tt)*) => ( ++ { ++ switch!(__impl $i, call!($e), $($rest)*) ++ } ++ ); ++); ++ ++/// ++/// ++/// `permutation!(I -> IResult, I -> IResult, ... I -> IResult ) => I -> IResult` ++/// applies its sub parsers in a sequence, but independent from their order ++/// this parser will only succeed if all of its sub parsers succeed ++/// ++/// the tuple of results is in the same order as the parsers are declared ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error,Incomplete}; ++/// # use nom::{ErrorKind,Needed}; ++/// # fn main() { ++/// named!(perm<(&[u8], &[u8], &[u8])>, ++/// permutation!(tag!("abcd"), tag!("efg"), tag!("hi")) ++/// ); ++/// ++/// // whatever the order, if the parser succeeds, each ++/// // tag should have matched correctly ++/// let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); ++/// ++/// let a = &b"abcdefghijk"[..]; ++/// assert_eq!(perm(a), Done(&b"jk"[..], expected)); ++/// let b = &b"efgabcdhijkl"[..]; ++/// assert_eq!(perm(b), Done(&b"jkl"[..], expected)); ++/// let c = &b"hiefgabcdjklm"[..]; ++/// assert_eq!(perm(c), Done(&b"jklm"[..], expected)); ++/// ++/// let d = &b"efgxyzabcdefghi"[..]; ++/// assert_eq!(perm(d), Error(error_position!(ErrorKind::Permutation, &b"xyzabcdefghi"[..]))); ++/// ++/// let e = &b"efgabc"[..]; ++/// assert_eq!(perm(e), Incomplete(Needed::Size(7))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! permutation ( ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ let mut res = permutation_init!((), $($rest)*); ++ let mut input = $i; ++ let mut error = ::std::option::Option::None; ++ let mut needed = ::std::option::Option::None; ++ ++ loop { ++ let mut all_done = true; ++ permutation_iterator!(0, input, all_done, needed, res, $($rest)*); ++ ++ //if we reach that part, it means none of the parsers were able to read anything ++ if !all_done { ++ //FIXME: should wrap the error returned by the child parser ++ error = ::std::option::Option::Some(error_position!($crate::ErrorKind::Permutation, input)); ++ } ++ break; ++ } ++ ++ if let ::std::option::Option::Some(need) = needed { ++ if let $crate::Needed::Size(sz) = need { ++ $crate::IResult::Incomplete( ++ $crate::Needed::Size( ++ $crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&input) + ++ sz ++ ) ++ ) ++ } else { ++ $crate::IResult::Incomplete($crate::Needed::Unknown) ++ } ++ } else if let ::std::option::Option::Some(e) = error { ++ $crate::IResult::Error(e) ++ } else { ++ let unwrapped_res = permutation_unwrap!(0, (), res, $($rest)*); ++ $crate::IResult::Done(input, unwrapped_res) ++ } ++ } ++ ); ++); ++ ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! permutation_init ( ++ ((), $e:ident, $($rest:tt)*) => ( ++ permutation_init!((::std::option::Option::None), $($rest)*) ++ ); ++ ((), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ permutation_init!((::std::option::Option::None), $($rest)*) ++ ); ++ (($($parsed:expr),*), $e:ident, $($rest:tt)*) => ( ++ permutation_init!(($($parsed),* , ::std::option::Option::None), $($rest)*); ++ ); ++ (($($parsed:expr),*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ permutation_init!(($($parsed),* , ::std::option::Option::None), $($rest)*); ++ ); ++ (($($parsed:expr),*), $e:ident) => ( ++ ($($parsed),* , ::std::option::Option::None) ++ ); ++ (($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( ++ ($($parsed),* , ::std::option::Option::None) ++ ); ++ (($($parsed:expr),*),) => ( ++ ($($parsed),*) ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! succ ( ++ (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*)); ++ (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*)); ++ (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*)); ++ (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*)); ++ (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*)); ++ (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*)); ++ (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*)); ++ (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*)); ++ (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*)); ++ (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*)); ++ (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*)); ++ (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*)); ++ (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*)); ++ (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*)); ++ (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*)); ++ (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*)); ++ (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*)); ++ (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*)); ++ (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*)); ++ (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*)); ++); ++ ++// HACK: for some reason, Rust 1.11 does not accept $res.$it in ++// permutation_unwrap. This is a bit ugly, but it will have no ++// impact on the generated code ++#[doc(hidden)] ++#[macro_export] ++macro_rules! acc ( ++ (0, $tup:expr) => ($tup.0); ++ (1, $tup:expr) => ($tup.1); ++ (2, $tup:expr) => ($tup.2); ++ (3, $tup:expr) => ($tup.3); ++ (4, $tup:expr) => ($tup.4); ++ (5, $tup:expr) => ($tup.5); ++ (6, $tup:expr) => ($tup.6); ++ (7, $tup:expr) => ($tup.7); ++ (8, $tup:expr) => ($tup.8); ++ (9, $tup:expr) => ($tup.9); ++ (10, $tup:expr) => ($tup.10); ++ (11, $tup:expr) => ($tup.11); ++ (12, $tup:expr) => ($tup.12); ++ (13, $tup:expr) => ($tup.13); ++ (14, $tup:expr) => ($tup.14); ++ (15, $tup:expr) => ($tup.15); ++ (16, $tup:expr) => ($tup.16); ++ (17, $tup:expr) => ($tup.17); ++ (18, $tup:expr) => ($tup.18); ++ (19, $tup:expr) => ($tup.19); ++ (20, $tup:expr) => ($tup.20); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! permutation_unwrap ( ++ ($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ succ!($it, permutation_unwrap!((acc!($it, $res).unwrap()), $res, $($rest)*)); ++ ); ++ ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($rest:tt)*) => ( ++ succ!($it, permutation_unwrap!(($($parsed),* , acc!($it, $res).unwrap()), $res, $($rest)*)); ++ ); ++ ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ succ!($it, permutation_unwrap!(($($parsed),* , acc!($it, $res).unwrap()), $res, $($rest)*)); ++ ); ++ ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident) => ( ++ ($($parsed),* , { acc!($it, $res).unwrap() }) ++ ); ++ ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )) => ( ++ ($($parsed),* , acc!($it, $res).unwrap() ) ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! permutation_iterator ( ++ ($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => ( ++ permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*); ++ ); ++ ($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { ++ if acc!($it, $res) == ::std::option::Option::None { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ $i = i; ++ acc!($it, $res) = ::std::option::Option::Some(o); ++ continue; ++ }, ++ $crate::IResult::Error(_) => { ++ $all_done = false; ++ }, ++ $crate::IResult::Incomplete(i) => { ++ $needed = ::std::option::Option::Some(i); ++ break; ++ } ++ }; ++ } ++ succ!($it, permutation_iterator!($i, $all_done, $needed, $res, $($rest)*)); ++ }; ++ ($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident) => ( ++ permutation_iterator!($it, $i, $all_done, $res, call!($e)); ++ ); ++ ($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => { ++ if acc!($it, $res) == ::std::option::Option::None { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ $i = i; ++ acc!($it, $res) = ::std::option::Option::Some(o); ++ continue; ++ }, ++ $crate::IResult::Error(_) => { ++ $all_done = false; ++ }, ++ $crate::IResult::Incomplete(i) => { ++ $needed = ::std::option::Option::Some(i); ++ break; ++ } ++ }; ++ } ++ }; ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::{Needed,IResult}; ++ use internal::IResult::*; ++ use util::ErrorKind; ++ ++ // reproduce the tag and take macros, because of module import order ++ macro_rules! tag ( ++ ($i:expr, $inp: expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ ++ tag_bytes!($i,bytes) ++ } ++ ); ++ ); ++ ++ macro_rules! tag_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ use std::cmp::min; ++ let len = $i.len(); ++ let blen = $bytes.len(); ++ let m = min(len, blen); ++ let reduced = &$i[..m]; ++ let b = &$bytes[..m]; ++ ++ let res: $crate::IResult<_,_> = if reduced != b { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i)) ++ } else if m < blen { ++ $crate::IResult::Incomplete($crate::Needed::Size(blen)) ++ } else { ++ $crate::IResult::Done(&$i[blen..], reduced) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ macro_rules! take( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res:$crate::IResult<&[u8],&[u8]> = if $i.len() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ $crate::IResult::Done(&$i[cnt..],&$i[0..cnt]) ++ }; ++ res ++ } ++ ); ++ ); ++ ++#[test] ++ fn alt() { ++ fn work(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ Done(&b""[..], input) ++ } ++ ++ #[allow(unused_variables)] ++ fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8],&'static str> { ++ Error(error_code!(ErrorKind::Custom("abcd"))) ++ } ++ ++ fn work2(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ Done(input, &b""[..]) ++ } ++ ++ fn alt1(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | dont_work) ++ } ++ fn alt2(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | work) ++ } ++ fn alt3(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | dont_work | work2 | dont_work) ++ } ++ //named!(alt1, alt!(dont_work | dont_work)); ++ //named!(alt2, alt!(dont_work | work)); ++ //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work)); ++ ++ let a = &b"abcd"[..]; ++ assert_eq!(alt1(a), Error(error_position!(ErrorKind::Alt, a))); ++ assert_eq!(alt2(a), Done(&b""[..], a)); ++ assert_eq!(alt3(a), Done(a, &b""[..])); ++ ++ named!(alt4, alt!(tag!("abcd") | tag!("efgh"))); ++ let b = &b"efgh"[..]; ++ assert_eq!(alt4(a), Done(&b""[..], a)); ++ assert_eq!(alt4(b), Done(&b""[..], b)); ++ ++ // test the alternative syntax ++ named!(alt5, alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true })); ++ assert_eq!(alt5(a), Done(&b""[..], false)); ++ assert_eq!(alt5(b), Done(&b""[..], true)); ++ ++ // compile-time test guarding against an underspecified E generic type (#474) ++ named!(alt_eof1, alt!(eof!() | eof!())); ++ named!(alt_eof2, alt!(eof!() => {|x| x} | eof!() => {|x| x})); ++ let _ = (alt_eof1, alt_eof2); ++ ++ } ++ ++ #[test] ++ fn alt_incomplete() { ++ named!(alt1, alt!(tag!("a") | tag!("bc") | tag!("def"))); ++ ++ let a = &b""[..]; ++ assert_eq!(alt1(a), Incomplete(Needed::Size(1))); ++ let a = &b"b"[..]; ++ assert_eq!(alt1(a), Incomplete(Needed::Size(2))); ++ let a = &b"bcd"[..]; ++ assert_eq!(alt1(a), Done(&b"d"[..], &b"bc"[..])); ++ let a = &b"cde"[..]; ++ assert_eq!(alt1(a), Error(error_position!(ErrorKind::Alt, a))); ++ let a = &b"de"[..]; ++ assert_eq!(alt1(a), Incomplete(Needed::Size(3))); ++ let a = &b"defg"[..]; ++ assert_eq!(alt1(a), Done(&b"g"[..], &b"def"[..])); ++ } ++ ++ #[test] ++ fn alt_complete() { ++ named!(ac<&[u8], &[u8]>, ++ alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl")) ++ ); ++ ++ let a = &b""[..]; ++ assert_eq!(ac(a), Error(error_position!(ErrorKind::Alt, a))); ++ let a = &b"ef"[..]; ++ assert_eq!(ac(a), Done(&b""[..], &b"ef"[..])); ++ let a = &b"cde"[..]; ++ assert_eq!(ac(a), Error(error_position!(ErrorKind::Alt, a))); ++ } ++ ++ #[allow(unused_variables)] ++ #[test] ++ fn switch() { ++ named!(sw, ++ switch!(take!(4), ++ b"abcd" => take!(2) | ++ b"efgh" => take!(4) ++ ) ++ ); ++ ++ let a = &b"abcdefgh"[..]; ++ assert_eq!(sw(a), Done(&b"gh"[..], &b"ef"[..])); ++ ++ let b = &b"efghijkl"[..]; ++ assert_eq!(sw(b), Done(&b""[..], &b"ijkl"[..])); ++ let c = &b"afghijkl"[..]; ++ assert_eq!(sw(c), Error(error_position!(ErrorKind::Switch, &b"afghijkl"[..]))); ++ } ++ ++ #[test] ++ fn permutation() { ++ //trace_macros!(true); ++ named!(perm<(&[u8], &[u8], &[u8])>, ++ permutation!(tag!("abcd"), tag!("efg"), tag!("hi")) ++ ); ++ //trace_macros!(false); ++ ++ let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); ++ ++ let a = &b"abcdefghijk"[..]; ++ assert_eq!(perm(a), Done(&b"jk"[..], expected)); ++ let b = &b"efgabcdhijk"[..]; ++ assert_eq!(perm(b), Done(&b"jk"[..], expected)); ++ let c = &b"hiefgabcdjk"[..]; ++ assert_eq!(perm(c), Done(&b"jk"[..], expected)); ++ ++ let d = &b"efgxyzabcdefghi"[..]; ++ assert_eq!(perm(d), Error(error_position!(ErrorKind::Permutation, &b"xyzabcdefghi"[..]))); ++ ++ let e = &b"efgabc"[..]; ++ assert_eq!(perm(e), Incomplete(Needed::Size(7))); ++ } ++ ++ /* ++ named!(does_not_compile, ++ alt!(tag!("abcd"), tag!("efgh")) ++ ); ++ */ ++} +diff --git third_party/rust/nom/src/bytes.rs third_party/rust/nom/src/bytes.rs +index 3f31598dc344..462ed0262f67 100644 +--- third_party/rust/nom/src/bytes.rs ++++ third_party/rust/nom/src/bytes.rs +@@ -1,92 +1,81 @@ + //! Byte level parsers and combinators + //! ++#[allow(unused_variables)] + +-/// `recognize!(&[T] -> IResult<&[T], O> ) => &[T] -> IResult<&[T], &[T]>` +-/// if the child parser was successful, return the consumed input as produced value ++/// `tag!(&[T]: nom::AsBytes) => &[T] -> IResult<&[T], &[T]>` ++/// declares a byte array as a suite to recognize ++/// ++/// consumes the recognized characters + /// + /// ``` + /// # #[macro_use] extern crate nom; + /// # use nom::IResult::Done; + /// # fn main() { +-/// named!(x, recognize!(delimited!(tag!("")))); +-/// let r = x(&b" aaa"[..]); +-/// assert_eq!(r, Done(&b" aaa"[..], &b""[..])); ++/// named!(x, tag!("abcd")); ++/// let r = x(&b"abcdefgh"[..]); ++/// assert_eq!(r, Done(&b"efgh"[..], &b"abcd"[..])); + /// # } + /// ``` + #[macro_export] +-macro_rules! recognize ( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++macro_rules! tag ( ++ ($i:expr, $tag: expr) => ( + { +- use $crate::HexDisplay; +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,_) => { +- let index = ($i).offset(i); +- $crate::IResult::Done(i, &($i)[..index]) ++ use $crate::{Compare,CompareResult,InputLength,Slice}; ++ let res: $crate::IResult<_,_> = match ($i).compare($tag) { ++ CompareResult::Ok => { ++ let blen = $tag.input_len(); ++ $crate::IResult::Done($i.slice(blen..), $i.slice(..blen)) + }, +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } ++ CompareResult::Incomplete => { ++ $crate::IResult::Incomplete($crate::Needed::Size($tag.input_len())) ++ }, ++ CompareResult::Error => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i)) ++ } ++ }; ++ res + } + ); +- ($i:expr, $f:expr) => ( +- recognize!($i, call!($f)) +- ); + ); + +-/// `tag!(&[T]: nom::AsBytes) => &[T] -> IResult<&[T], &[T]>` +-/// declares a byte array as a suite to recognize ++/// `tag_no_case!(&[T]) => &[T] -> IResult<&[T], &[T]>` ++/// declares a case insensitive ascii string as a suite to recognize + /// + /// consumes the recognized characters + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; ++/// # use nom::IResult::{self,Done}; + /// # fn main() { +-/// named!(x, tag!("abcd")); +-/// let r = x(&b"abcdefgh"[..]); +-/// assert_eq!(r, Done(&b"efgh"[..], &b"abcd"[..])); ++/// named!(test, tag_no_case!("ABcd")); ++/// ++/// let r = test(&b"aBCdefgh"[..]); ++/// assert_eq!(r, Done(&b"efgh"[..], &b"aBCd"[..])); + /// # } + /// ``` + #[macro_export] +-macro_rules! tag ( +- ($i:expr, $inp: expr) => ( +- { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $inp; +- let bytes = as_bytes(&expected); +- +- tag_bytes!($i,bytes) +- } +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! tag_bytes ( +- ($i:expr, $bytes: expr) => ( ++macro_rules! tag_no_case ( ++ ($i:expr, $tag: expr) => ( + { +- let len = $i.len(); +- let blen = $bytes.len(); +- let m = if len < blen { len } else { blen }; +- let reduced = &$i[..m]; +- let b = &$bytes[..m]; +- +- let res: $crate::IResult<_,_> = if reduced != b { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Tag, $i)) +- } else if m < blen { +- $crate::IResult::Incomplete($crate::Needed::Size(blen)) +- } else { +- $crate::IResult::Done(&$i[blen..], reduced) ++ use $crate::{Compare,CompareResult,InputLength,Slice}; ++ let res: $crate::IResult<_,_> = match ($i).compare_no_case($tag) { ++ CompareResult::Ok => { ++ let blen = $tag.input_len(); ++ $crate::IResult::Done($i.slice(blen..), $i.slice(..blen)) ++ }, ++ CompareResult::Incomplete => { ++ $crate::IResult::Incomplete($crate::Needed::Size($tag.input_len())) ++ }, ++ CompareResult::Error => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i)) ++ } + }; + res + } + ); + ); + ++ + /// `is_not!(&[T:AsBytes]) => &[T] -> IResult<&[T], &[T]>` + /// returns the longest list of bytes that do not appear in the provided array + /// +@@ -103,39 +92,22 @@ macro_rules! tag_bytes ( + #[macro_export] + macro_rules! is_not( + ($input:expr, $arr:expr) => ( +- { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $arr; +- let bytes = as_bytes(&expected); +- +- is_not_bytes!($input, bytes) +- } +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! is_not_bytes ( +- ($input:expr, $bytes:expr) => ( + { + use $crate::InputLength; +- let res: $crate::IResult<_,_> = match $input.iter().position(|c| { +- for &i in $bytes.iter() { +- if *c == i { return true } +- } +- false ++ use $crate::InputIter; ++ use $crate::FindToken; ++ use $crate::Slice; ++ ++ let res: $crate::IResult<_,_> = match $input.position(|c| { ++ c.find_token($arr) + }) { +- Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsNot,$input)), ++ Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::IsNot,$input)), + Some(n) => { +- let res = $crate::IResult::Done(&$input[n..], &$input[..n]); ++ let res = $crate::IResult::Done($input.slice(n..), $input.slice(..n)); + res + }, + None => { +- $crate::IResult::Done(&$input[$input.input_len()..], $input) ++ $crate::IResult::Done($input.slice($input.input_len()..), $input) + } + }; + res +@@ -162,39 +134,22 @@ macro_rules! is_not_bytes ( + #[macro_export] + macro_rules! is_a ( + ($input:expr, $arr:expr) => ( +- { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $arr; +- let bytes = as_bytes(&expected); +- +- is_a_bytes!($input, bytes) +- } +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! is_a_bytes ( +- ($input:expr, $bytes:expr) => ( + { + use $crate::InputLength; +- let res: $crate::IResult<_,_> = match $input.iter().position(|c| { +- for &i in $bytes.iter() { +- if *c == i { return false } +- } +- true ++ use $crate::InputIter; ++ use $crate::FindToken; ++ use $crate::Slice; ++ ++ let res: $crate::IResult<_,_> = match $input.position(|c| { ++ !c.find_token($arr) + }) { +- Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsA,$input)), ++ Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::IsA,$input)), + Some(n) => { +- let res: $crate::IResult<_,_> = $crate::IResult::Done(&$input[n..], &$input[..n]); ++ let res: $crate::IResult<_,_> = $crate::IResult::Done($input.slice(n..), $input.slice(..n)); + res + }, + None => { +- $crate::IResult::Done(&$input[($input).input_len()..], $input) ++ $crate::IResult::Done($input.slice(($input).input_len()..), $input) + } + }; + res +@@ -213,77 +168,55 @@ macro_rules! is_a_bytes ( + /// # use nom::IResult::Done; + /// # use nom::alpha; + /// # fn main() { +-/// named!(esc, escaped!(call!(alpha), '\\', is_a_bytes!(&b"\"n\\"[..]))); ++/// named!(esc, escaped!(call!(alpha), '\\', one_of!("\"n\\"))); + /// assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], &b"abcd"[..])); + /// assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], &b"ab\\\"cd"[..])); + /// # } + /// ``` + #[macro_export] + macro_rules! escaped ( +- ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( +- { +- escaped1!($i, $submac!($($args)*), $control_char, $($rest)*) +- } +- ); +- +- ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( +- escaped1!($i, call!($f), $control_char, $($rest)*) +- ); +-); +- +-/// Internal parser, do not use directly +-#[doc(hidden)] +-#[macro_export] +-macro_rules! escaped1 ( +- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( +- { +- escaped_impl!($i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) +- } +- ); +- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( +- escaped_impl!($i, $submac1!($($args)*), $control_char, call!($g)) +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! escaped_impl ( +- ($i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $escapable:ident!( $($args2:tt)* )) => ( ++ // Internal parser, do not use directly ++ (__impl $i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $escapable:ident!( $($args2:tt)* )) => ( + { + use $crate::InputLength; +- let cl = || { +- use $crate::HexDisplay; ++ use $crate::Slice; ++ let cl = || -> $crate::IResult<_,_,_> { ++ use $crate::Offset; + let mut index = 0; + +- while index < $i.len() { +- if let $crate::IResult::Done(i,_) = $normal!(&$i[index..], $($args)*) { +- if i.is_empty() { +- return $crate::IResult::Done(&$i[$i.input_len()..], $i) +- } else { +- index = $i.offset(i); +- } +- } else if $i[index] == $control_char as u8 { +- if index + 1 >= $i.len() { +- return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Escaped,&$i[index..])); +- } else { +- match $escapable!(&$i[index+1..], $($args2)*) { +- $crate::IResult::Done(i,_) => { +- if i.is_empty() { +- return $crate::IResult::Done(&$i[$i.input_len()..], $i) +- } else { +- index = $i.offset(i); ++ while index < $i.input_len() { ++ match $normal!($i.slice(index..), $($args)*) { ++ $crate::IResult::Done(i, _) => { ++ if i.is_empty() { ++ return $crate::IResult::Done($i.slice($i.input_len()..), $i) ++ } else { ++ index = $i.offset(i); ++ } ++ }, ++ $crate::IResult::Incomplete(i) => { ++ return $crate::IResult::Incomplete(i) ++ }, ++ $crate::IResult::Error(e) => { ++ if $i[index] == $control_char as u8 { ++ if index + 1 >= $i.input_len() { ++ return $crate::IResult::Incomplete($crate::Needed::Unknown) ++ } else { ++ match $escapable!($i.slice(index+1..), $($args2)*) { ++ $crate::IResult::Done(i,_) => { ++ if i.is_empty() { ++ return $crate::IResult::Done($i.slice($i.input_len()..), $i) ++ } else { ++ index = $i.offset(i); ++ } ++ }, ++ $crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i), ++ $crate::IResult::Error(e2) => return $crate::IResult::Error(e2) + } +- }, +- $crate::IResult::Incomplete(i) => return $crate::IResult::Incomplete(i), +- $crate::IResult::Error(e) => return $crate::IResult::Error(e) ++ } ++ } else { ++ return $crate::IResult::Done($i.slice(index..), $i.slice(..index)); + } + } +- } else { +- if index == 0 { +- return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Escaped,&$i[index..])) +- } else { +- return $crate::IResult::Done(&$i[index..], &$i[..index]) +- } + } + } + $crate::IResult::Done(&$i[index..], &$i[..index]) +@@ -292,22 +225,46 @@ macro_rules! escaped_impl ( + $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), + $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), + $crate::IResult::Error(e) => { +- return $crate::IResult::Error($crate::Err::NodePosition($crate::ErrorKind::Escaped, $i, Box::new(e))) ++ return $crate::IResult::Error(error_node_position!($crate::ErrorKind::Escaped, $i, e)) + } + } + } + ); ++ // Internal parser, do not use directly ++ (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( ++ { ++ escaped!(__impl $i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) ++ } ++ ); ++ // Internal parser, do not use directly ++ (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( ++ escaped!(__impl $i, $submac1!($($args)*), $control_char, call!($g)) ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( ++ { ++ let input: &[u8] = $i; ++ ++ escaped!(__impl_1 input, $submac!($($args)*), $control_char, $($rest)*) ++ } ++ ); ++ ++ ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( ++ escaped!(__impl_1 $i, call!($f), $control_char, $($rest)*) ++ ); + ); + + /// `escaped_transform!(&[T] -> IResult<&[T], &[T]>, T, &[T] -> IResult<&[T], &[T]>) => &[T] -> IResult<&[T], Vec>` + /// matches a byte string with escaped characters. + /// + /// The first argument matches the normal characters (it must not match the control character), the second argument is the control character (like `\` in most languages), +-/// the third argument matches the escaped characters and trnasforms them. ++/// the third argument matches the escaped characters and transforms them. + /// + /// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) + /// +-/// ``` ++/// WARNING: if you do not use the `verbose-errors` feature, this combinator will currently fail to build ++/// because of a type inference error ++/// ++/// ```ignore + /// # #[macro_use] extern crate nom; + /// # use nom::IResult::Done; + /// # use nom::alpha; +@@ -333,59 +290,32 @@ macro_rules! escaped_impl ( + /// ``` + #[macro_export] + macro_rules! escaped_transform ( +- ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( +- { +- escaped_transform1!($i, $submac!($($args)*), $control_char, $($rest)*) +- } +- ); +- +- ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( +- escaped_transform1!($i, call!($f), $control_char, $($rest)*) +- ); +-); +- +-/// Internal parser, do not use directly +-#[doc(hidden)] +-#[macro_export] +-macro_rules! escaped_transform1 ( +- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( +- { +- escaped_transform_impl!($i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) +- } +- ); +- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( +- escaped_transform_impl!($i, $submac1!($($args)*), $control_char, call!($g)) +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! escaped_transform_impl ( +- ($i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $transform:ident!( $($args2:tt)* )) => ( ++ // Internal parser, do not use directly ++ (__impl $i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $transform:ident!( $($args2:tt)* )) => ( + { +- use $crate::InputLength; ++ use $crate::{InputLength,Slice}; + let cl = || { +- use $crate::HexDisplay; ++ use $crate::Offset; + let mut index = 0; + let mut res = Vec::new(); + +- while index < $i.len() { +- if let $crate::IResult::Done(i,o) = $normal!(&$i[index..], $($args)*) { ++ while index < $i.input_len() { ++ if let $crate::IResult::Done(i,o) = $normal!($i.slice(index..), $($args)*) { + res.extend(o.iter().cloned()); + if i.is_empty() { +- return $crate::IResult::Done(&$i[$i.input_len()..], res) ++ return $crate::IResult::Done($i.slice($i.input_len()..), res); + } else { + index = $i.offset(i); + } + } else if $i[index] == $control_char as u8 { +- if index + 1 >= $i.len() { +- return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::EscapedTransform,&$i[index..])); ++ if index + 1 >= $i.input_len() { ++ return $crate::IResult::Error(error_position!($crate::ErrorKind::EscapedTransform,$i.slice(index..))); + } else { +- match $transform!(&$i[index+1..], $($args2)*) { ++ match $transform!($i.slice(index+1..), $($args2)*) { + $crate::IResult::Done(i,o) => { + res.extend(o.iter().cloned()); + if i.is_empty() { +- return $crate::IResult::Done(&$i[$i.input_len()..], res) ++ return $crate::IResult::Done($i.slice($i.input_len()..), res) + } else { + index = $i.offset(i); + } +@@ -396,23 +326,44 @@ macro_rules! escaped_transform_impl ( + } + } else { + if index == 0 { +- return $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::EscapedTransform,&$i[index..])) ++ return $crate::IResult::Error(error_position!($crate::ErrorKind::EscapedTransform,$i.slice(index..))) + } else { +- return $crate::IResult::Done(&$i[index..], res) ++ return $crate::IResult::Done($i.slice(index..), res) + } + } + } +- $crate::IResult::Done(&$i[index..], res) ++ $crate::IResult::Done($i.slice(index..), res) + }; + match cl() { + $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), + $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), + $crate::IResult::Error(e) => { +- return $crate::IResult::Error($crate::Err::NodePosition($crate::ErrorKind::EscapedTransform, $i, Box::new(e))) ++ return $crate::IResult::Error(error_node_position!($crate::ErrorKind::EscapedTransform, $i, e)) + } + } + } +- ) ++ ); ++ // Internal parser, do not use directly ++ (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( ++ { ++ escaped_transform!(__impl $i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) ++ } ++ ); ++ // Internal parser, do not use directly ++ (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( ++ escaped_transform_impl!($i, $submac1!($($args)*), $control_char, call!($g)) ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( ++ { ++ let input: &[u8] = $i; ++ ++ escaped_transform!(__impl_1 input, $submac!($($args)*), $control_char, $($rest)*) ++ } ++ ); ++ ++ ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( ++ escaped_transform!(__impl_1 $i, call!($f), $control_char, $($rest)*) ++ ); + ); + + /// `take_while!(T -> bool) => &[T] -> IResult<&[T], &[T]>` +@@ -435,13 +386,16 @@ macro_rules! escaped_transform_impl ( + macro_rules! take_while ( + ($input:expr, $submac:ident!( $($args:tt)* )) => ( + { +- match $input.iter().position(|c| !$submac!(*c, $($args)*)) { ++ use $crate::{InputLength,InputIter,Slice}; ++ let input = $input; ++ ++ match input.position(|c| !$submac!(c, $($args)*)) { + Some(n) => { +- let res:$crate::IResult<_,_> = $crate::IResult::Done(&$input[n..], &$input[..n]); ++ let res:$crate::IResult<_,_> = $crate::IResult::Done(input.slice(n..), input.slice(..n)); + res + }, + None => { +- $crate::IResult::Done(&$input[($input).len()..], $input) ++ $crate::IResult::Done(input.slice(input.input_len()..), input) + } + } + } +@@ -451,7 +405,7 @@ macro_rules! take_while ( + ); + ); + +-/// `take_while1!(&[T] -> bool) => &[T] -> IResult<&[T], &[T]>` ++/// `take_while1!(T -> bool) => &[T] -> IResult<&[T], &[T]>` + /// returns the longest (non empty) list of bytes until the provided function fails. + /// + /// The argument is either a function `&[T] -> bool` or a macro returning a `bool +@@ -459,17 +413,21 @@ macro_rules! take_while ( + macro_rules! take_while1 ( + ($input:expr, $submac:ident!( $($args:tt)* )) => ( + { ++ let input = $input; ++ + use $crate::InputLength; +- if ($input).input_len() == 0 { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1,$input)) ++ use $crate::InputIter; ++ use $crate::Slice; ++ if input.input_len() == 0 { ++ $crate::IResult::Incomplete($crate::Needed::Size(1)) + } else { +- match $input.iter().position(|c| !$submac!(*c, $($args)*)) { +- Some(0) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1,$input)), ++ match input.position(|c| !$submac!(c, $($args)*)) { ++ Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::TakeWhile1,input)), + Some(n) => { +- $crate::IResult::Done(&$input[n..], &$input[..n]) ++ $crate::IResult::Done(input.slice(n..), input.slice(..n)) + }, + None => { +- $crate::IResult::Done(&$input[($input).len()..], $input) ++ $crate::IResult::Done(input.slice(input.input_len()..), input) + } + } + } +@@ -488,10 +446,14 @@ macro_rules! take_while1 ( + macro_rules! take_till ( + ($input:expr, $submac:ident!( $($args:tt)* )) => ( + { ++ let input = $input; ++ + use $crate::InputLength; +- match $input.iter().position(|c| $submac!(c, $($args)*)) { +- Some(n) => $crate::IResult::Done(&$input[n..], &$input[..n]), +- None => $crate::IResult::Done(&$input[($input).input_len()..], $input) ++ use $crate::InputIter; ++ use $crate::Slice; ++ match input.position(|c| $submac!(c, $($args)*)) { ++ Some(n) => $crate::IResult::Done(input.slice(n..), input.slice(..n)), ++ None => $crate::IResult::Done(input.slice(input.input_len()..), input) + } + } + ); +@@ -500,6 +462,35 @@ macro_rules! take_till ( + ); + ); + ++/// `take_till1!(T -> bool) => &[T] -> IResult<&[T], &[T]>` ++/// returns the longest non empty list of bytes until the provided function succeeds ++/// ++/// The argument is either a function `&[T] -> bool` or a macro returning a `bool ++#[macro_export] ++macro_rules! take_till1 ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ let input = $input; ++ ++ use $crate::InputLength; ++ use $crate::InputIter; ++ use $crate::Slice; ++ if input.input_len() == 0 { ++ $crate::IResult::Incomplete($crate::Needed::Size(1)) ++ } else { ++ match input.position(|c| $submac!(c, $($args)*)) { ++ Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::TakeTill1,input)), ++ Some(n) => $crate::IResult::Done(input.slice(n..), input.slice(..n)), ++ None => $crate::IResult::Done(input.slice(input.input_len()..), input) ++ } ++ } ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_till1!($input, call!($f)); ++ ); ++); ++ + /// `take!(nb) => &[T] -> IResult<&[T], &[T]>` + /// generates a parser consuming the specified number of bytes + /// +@@ -519,69 +510,80 @@ macro_rules! take_till ( + macro_rules! take ( + ($i:expr, $count:expr) => ( + { ++ use $crate::InputIter; ++ use $crate::Slice; ++ let input = $i; ++ + let cnt = $count as usize; +- let res: $crate::IResult<_,_> = if $i.len() < cnt { +- $crate::IResult::Incomplete($crate::Needed::Size(cnt)) +- } else { +- $crate::IResult::Done(&$i[cnt..],&$i[0..cnt]) ++ ++ let res: $crate::IResult<_,_> = match input.slice_index(cnt) { ++ None => $crate::IResult::Incomplete($crate::Needed::Size(cnt)), ++ //FIXME: use the InputTake trait ++ Some(index) => $crate::IResult::Done(input.slice(index..), input.slice(..index)) + }; + res + } + ); + ); + +-/// `take!(nb) => &[T] -> IResult<&[T], &str>` ++/// `take_str!(nb) => &[T] -> IResult<&[T], &str>` + /// same as take! but returning a &str + #[macro_export] + macro_rules! take_str ( +- ( $i:expr, $size:expr ) => ( map_res!($i, take!($size), ::std::str::from_utf8) ); ++ ( $i:expr, $size:expr ) => ( ++ { ++ let input: &[u8] = $i; ++ ++ map_res!(input, take!($size), ::std::str::from_utf8) ++ } ++ ); + ); + + /// `take_until_and_consume!(tag) => &[T] -> IResult<&[T], &[T]>` + /// generates a parser consuming bytes until the specified byte sequence is found, and consumes it + #[macro_export] +-macro_rules! take_until_and_consume( +- ($i:expr, $inp:expr) => ( ++macro_rules! take_until_and_consume ( ++ ($i:expr, $substr:expr) => ( + { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } ++ use $crate::InputLength; ++ use $crate::FindSubstring; ++ use $crate::Slice; + +- let expected = $inp; +- let bytes = as_bytes(&expected); +- take_until_and_consume_bytes!($i, bytes) ++ let res: $crate::IResult<_,_> = if $substr.input_len() > $i.input_len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($substr.input_len())) ++ } else { ++ match ($i).find_substring($substr) { ++ None => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilAndConsume,$i)) ++ }, ++ Some(index) => { ++ $crate::IResult::Done($i.slice(index+$substr.input_len()..), $i.slice(0..index)) ++ }, ++ } ++ }; ++ res + } + ); + ); + +-#[doc(hidden)] ++/// `take_until_and_consume1!(tag) => &[T] -> IResult<&[T], &[T]>` ++/// generates a parser consuming bytes (at least 1) until the specified byte sequence is found, and consumes it + #[macro_export] +-macro_rules! take_until_and_consume_bytes ( +- ($i:expr, $bytes:expr) => ( ++macro_rules! take_until_and_consume1 ( ++ ($i:expr, $substr:expr) => ( + { +- let res: $crate::IResult<_,_> = if $bytes.len() > $i.len() { +- $crate::IResult::Incomplete($crate::Needed::Size($bytes.len())) +- } else { +- let mut index = 0; +- let mut parsed = false; +- +- for idx in 0..$i.len() { +- if idx + $bytes.len() > $i.len() { +- index = idx; +- break; +- } +- if &$i[idx..idx + $bytes.len()] == $bytes { +- parsed = true; +- index = idx; +- break; +- } +- } ++ use $crate::InputLength; + +- if parsed { +- $crate::IResult::Done(&$i[(index + $bytes.len())..], &$i[0..index]) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilAndConsume,$i)) ++ let res: $crate::IResult<_,_> = if 1 + $substr.input_len() > $i.input_len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($substr.input_len())) ++ } else { ++ match ($i).find_substring($substr) { ++ None => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilAndConsume,$i)) ++ }, ++ Some(index) => { ++ $crate::IResult::Done($i.slice(index+$substr.input_len()..), $i.slice(0..index)) ++ }, + } + }; + res +@@ -592,48 +594,50 @@ macro_rules! take_until_and_consume_bytes ( + /// `take_until!(tag) => &[T] -> IResult<&[T], &[T]>` + /// consumes data until it finds the specified tag + #[macro_export] +-macro_rules! take_until( +- ($i:expr, $inp:expr) => ( ++macro_rules! take_until ( ++ ($i:expr, $substr:expr) => ( + { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } ++ use $crate::InputLength; ++ use $crate::FindSubstring; ++ use $crate::Slice; + +- let expected = $inp; +- let bytes = as_bytes(&expected); +- take_until_bytes!($i, bytes) ++ let res: $crate::IResult<_,_> = if $substr.input_len() > $i.input_len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($substr.input_len())) ++ } else { ++ match ($i).find_substring($substr) { ++ None => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntil,$i)) ++ }, ++ Some(index) => { ++ $crate::IResult::Done($i.slice(index..), $i.slice(0..index)) ++ }, ++ } ++ }; ++ res + } + ); + ); + +-#[doc(hidden)] ++/// `take_until1!(tag) => &[T] -> IResult<&[T], &[T]>` ++/// consumes data until it finds the specified tag + #[macro_export] +-macro_rules! take_until_bytes( +- ($i:expr, $bytes:expr) => ( ++macro_rules! take_until1 ( ++ ($i:expr, $substr:expr) => ( + { +- let res: $crate::IResult<_,_> = if $bytes.len() > $i.len() { +- $crate::IResult::Incomplete($crate::Needed::Size($bytes.len())) +- } else { +- let mut index = 0; +- let mut parsed = false; +- +- for idx in 0..$i.len() { +- if idx + $bytes.len() > $i.len() { +- index = idx; +- break; +- } +- if &$i[idx..idx+$bytes.len()] == $bytes { +- parsed = true; +- index = idx; +- break; +- } +- } ++ use $crate::InputLength; ++ use $crate::FindSubstring; ++ use $crate::Slice; + +- if parsed { +- $crate::IResult::Done(&$i[index..], &$i[0..index]) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntil,$i)) ++ let res: $crate::IResult<_,_> = if 1+$substr.input_len() > $i.input_len() { ++ $crate::IResult::Incomplete($crate::Needed::Size($substr.input_len())) ++ } else { ++ match ($i).find_substring($substr) { ++ None => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntil,$i)) ++ }, ++ Some(index) => { ++ $crate::IResult::Done($i.slice(index..), $i.slice(0..index)) ++ }, + } + }; + res +@@ -644,136 +648,78 @@ macro_rules! take_until_bytes( + /// `take_until_either_and_consume!(tag) => &[T] -> IResult<&[T], &[T]>` + /// consumes data until it finds any of the specified characters, and consume it + #[macro_export] +-macro_rules! take_until_either_and_consume( +- ($i:expr, $inp:expr) => ( ++macro_rules! take_until_either_and_consume ( ++ ($input:expr, $arr:expr) => ( + { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $inp; +- let bytes = as_bytes(&expected); +- take_until_either_and_consume_bytes!($i, bytes) +- } +- ); +-); ++ use $crate::InputLength; ++ use $crate::InputIter; ++ use $crate::FindToken; ++ use $crate::Slice; + +-#[doc(hidden)] +-#[macro_export] +-macro_rules! take_until_either_and_consume_bytes( +- ($i:expr, $bytes:expr) => ( +- { +- let res: $crate::IResult<_,_> = if 1 > $i.len() { ++ if $input.input_len() == 0 { + $crate::IResult::Incomplete($crate::Needed::Size(1)) + } else { +- let mut index = 0; +- let mut parsed = false; +- +- for idx in 0..$i.len() { +- if idx + 1 > $i.len() { +- index = idx; +- break; +- } +- for &t in $bytes.iter() { +- if $i[idx] == t { +- parsed = true; +- index = idx; +- break; +- } ++ let res: $crate::IResult<_,_> = match $input.position(|c| { ++ c.find_token($arr) ++ }) { ++ Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilEitherAndConsume,$input)), ++ Some(n) => { ++ let res = $crate::IResult::Done($input.slice(n+1..), $input.slice(..n)); ++ res ++ }, ++ None => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilEitherAndConsume,$input)) + } +- if parsed { break; } +- } +- +- if parsed { +- $crate::IResult::Done(&$i[(index+1)..], &$i[0..index]) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilEitherAndConsume,$i)) +- } +- }; +- res ++ }; ++ res ++ } + } + ); + ); + + /// `take_until_either!(tag) => &[T] -> IResult<&[T], &[T]>` + #[macro_export] +-macro_rules! take_until_either( +- ($i:expr, $inp:expr) => ( ++macro_rules! take_until_either ( ++ ($input:expr, $arr:expr) => ( + { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $inp; +- let bytes = as_bytes(&expected); +- take_until_either_bytes!($i, bytes) +- } +- ); +-); ++ use $crate::InputLength; ++ use $crate::InputIter; ++ use $crate::FindToken; ++ use $crate::Slice; + +-#[doc(hidden)] +-#[macro_export] +-macro_rules! take_until_either_bytes( +- ($i:expr, $bytes:expr) => ( +- { +- let res: $crate::IResult<_,_> = if 1 > $i.len() { ++ if $input.input_len() == 0 { + $crate::IResult::Incomplete($crate::Needed::Size(1)) + } else { +- let mut index = 0; +- let mut parsed = false; +- +- for idx in 0..$i.len() { +- if idx + 1 > $i.len() { +- index = idx; +- break; +- } +- for &t in $bytes.iter() { +- if $i[idx] == t { +- parsed = true; +- index = idx; +- break; +- } ++ let res: $crate::IResult<_,_> = match $input.position(|c| { ++ c.find_token($arr) ++ }) { ++ Some(0) => $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilEither,$input)), ++ Some(n) => { ++ let res = $crate::IResult::Done($input.slice(n..), $input.slice(..n)); ++ res ++ }, ++ None => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TakeUntilEither,$input)) + } +- if parsed { break; } +- } +- +- if parsed { +- $crate::IResult::Done(&$i[index..], &$i[0..index]) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilEither,$i)) +- } +- }; +- res ++ }; ++ res ++ } + } + ); + ); + +-/// `length_bytes!(&[T] -> IResult<&[T], nb>) => &[T] -> IResult<&[T], &[T]> +-/// gets a number from the first parser, then extracts that many bytes from the ++/// `length_bytes!(&[T] -> IResult<&[T], nb>) => &[T] -> IResult<&[T], &[T]>` ++/// Gets a number from the first parser, then extracts that many bytes from the + /// remaining stream + #[macro_export] + macro_rules! length_bytes( + ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i1,nb) => { +- let nb = nb as usize; +- let length_remaining = i1.len(); +- if length_remaining < nb { +- $crate::IResult::Incomplete($crate::Needed::Size(nb - length_remaining)) +- } else { +- $crate::IResult::Done(&i1[nb..], &i1[..nb]) +- } +- } +- } ++ length_data!($i, $submac!($($args)*)) + } + ); + ($i:expr, $f:expr) => ( +- length_bytes!($i, call!($f)) ++ length_data!($i, call!($f)) + ) + ); + +@@ -781,10 +727,53 @@ macro_rules! length_bytes( + mod tests { + use internal::Needed; + use internal::IResult::*; +- use internal::Err::*; + use util::ErrorKind; + use nom::{alpha, digit, hex_digit, oct_digit, alphanumeric, space, multispace}; + ++ macro_rules! one_of ( ++ ($i:expr, $inp: expr) => ( ++ { ++ if $i.is_empty() { ++ $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) ++ } else { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ one_of_bytes!($i, bytes) ++ } ++ } ++ ); ++ ); ++ ++ macro_rules! one_of_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ if $i.is_empty() { ++ $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) ++ } else { ++ let mut found = false; ++ ++ for &i in $bytes { ++ if i == $i[0] { ++ found = true; ++ break; ++ } ++ } ++ ++ if found { ++ $crate::IResult::Done(&$i[1..], $i[0] as char) ++ } else { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::OneOf, $i)) ++ } ++ } ++ } ++ ); ++ ); ++ + #[test] + fn is_a() { + named!(a_or_b, is_a!(&b"ab"[..])); +@@ -796,7 +785,7 @@ mod tests { + assert_eq!(a_or_b(b), Done(&b"cde"[..], &b"b"[..])); + + let c = &b"cdef"[..]; +- assert_eq!(a_or_b(c), Error(Position(ErrorKind::IsA,c))); ++ assert_eq!(a_or_b(c), Error(error_position!(ErrorKind::IsA,c))); + + let d = &b"bacdef"[..]; + assert_eq!(a_or_b(d), Done(&b"cdef"[..], &b"ba"[..])); +@@ -813,7 +802,7 @@ mod tests { + assert_eq!(a_or_b(b), Done(&b"bde"[..], &b"c"[..])); + + let c = &b"abab"[..]; +- assert_eq!(a_or_b(c), Error(Position(ErrorKind::IsNot,c))); ++ assert_eq!(a_or_b(c), Error(error_position!(ErrorKind::IsNot,c))); + + let d = &b"cdefba"[..]; + assert_eq!(a_or_b(d), Done(&b"ba"[..], &b"cdef"[..])); +@@ -825,27 +814,34 @@ mod tests { + assert_eq!(a_or_b(f), Done(&b""[..], &b"fghi"[..])); + } + ++ #[allow(unused_variables)] + #[test] + fn escaping() { +- named!(esc, escaped!(call!(alpha), '\\', is_a_bytes!(&b"\"n\\"[..]))); ++ named!(esc, escaped!(call!(alpha), '\\', one_of!("\"n\\"))); + assert_eq!(esc(&b"abcd"[..]), Done(&b""[..], &b"abcd"[..])); + assert_eq!(esc(&b"ab\\\"cd"[..]), Done(&b""[..], &b"ab\\\"cd"[..])); + assert_eq!(esc(&b"\\\"abcd"[..]), Done(&b""[..], &b"\\\"abcd"[..])); + assert_eq!(esc(&b"\\n"[..]), Done(&b""[..], &b"\\n"[..])); + assert_eq!(esc(&b"ab\\\"12"[..]), Done(&b"12"[..], &b"ab\\\""[..])); +- assert_eq!(esc(&b"AB\\"[..]), Error(NodePosition(ErrorKind::Escaped, &b"AB\\"[..], Box::new(Position(ErrorKind::Escaped, &b"\\"[..]))))); +- assert_eq!(esc(&b"AB\\A"[..]), Error(NodePosition(ErrorKind::Escaped, &b"AB\\A"[..], Box::new(Position(ErrorKind::IsA, &b"A"[..]))))); ++ assert_eq!(esc(&b"AB\\"[..]), Incomplete(Needed::Unknown)); ++ assert_eq!(esc(&b"AB\\A"[..]), Error(error_node_position!(ErrorKind::Escaped, &b"AB\\A"[..], ++ error_position!(ErrorKind::OneOf, &b"A"[..])))); ++ ++ named!(esc2, escaped!(call!(digit), '\\', one_of!("\"n\\"))); ++ assert_eq!(esc2(&b"12\\nnn34"[..]), Done(&b"nn34"[..], &b"12\\n"[..])); + } + ++ #[cfg(feature = "verbose-errors")] + fn to_s(i:Vec) -> String { + String::from_utf8_lossy(&i).into_owned() + } + ++ #[cfg(feature = "verbose-errors")] + #[test] + fn escape_transform() { + use std::str; + +- named!(esc< String >, map!(escaped_transform!(alpha, '\\', ++ named!(esc, map!(escaped_transform!(alpha, '\\', + alt!( + tag!("\\") => { |_| &b"\\"[..] } + | tag!("\"") => { |_| &b"\""[..] } +@@ -858,8 +854,9 @@ mod tests { + assert_eq!(esc(&b"\\\"abcd"[..]), Done(&b""[..], String::from("\"abcd"))); + assert_eq!(esc(&b"\\n"[..]), Done(&b""[..], String::from("\n"))); + assert_eq!(esc(&b"ab\\\"12"[..]), Done(&b"12"[..], String::from("ab\""))); +- assert_eq!(esc(&b"AB\\"[..]), Error(NodePosition(ErrorKind::EscapedTransform, &b"AB\\"[..], Box::new(Position(ErrorKind::EscapedTransform, &b"\\"[..]))))); +- assert_eq!(esc(&b"AB\\A"[..]), Error(NodePosition(ErrorKind::EscapedTransform, &b"AB\\A"[..], Box::new(Position(ErrorKind::Alt, &b"A"[..]))))); ++ assert_eq!(esc(&b"AB\\"[..]), Error(error_node_position!(ErrorKind::EscapedTransform, &b"AB\\"[..], error_position!(ErrorKind::EscapedTransform, &b"\\"[..])))); ++ assert_eq!(esc(&b"AB\\A"[..]), Error(error_node_position!(ErrorKind::EscapedTransform, &b"AB\\A"[..], ++ error_position!(ErrorKind::Alt, &b"A"[..])))); + + let e = "è"; + let a = "à"; +@@ -893,6 +890,7 @@ mod tests { + } + + #[test] ++ #[cfg(feature = "std")] + fn take_until_test() { + named!(x, take_until_and_consume!("efgh")); + let r = x(&b"abcdabcdefghijkl"[..]); +@@ -905,7 +903,7 @@ mod tests { + + println!("Done 2\n"); + let r3 = x(&b"abcefg"[..]); +- assert_eq!(r3, Error(Position(ErrorKind::TakeUntilAndConsume, &b"abcefg"[..]))); ++ assert_eq!(r3, Error(error_position!(ErrorKind::TakeUntilAndConsume, &b"abcefg"[..]))); + + assert_eq!( + x(&b"ab"[..]), +@@ -913,15 +911,34 @@ mod tests { + ); + } + ++ #[test] ++ fn take_until_either() { ++ named!(x, take_until_either!("!.")); ++ assert_eq!( ++ x(&b"123!abc"[..]), ++ Done(&b"!abc"[..], &b"123"[..]) ++ ); ++ } ++ + #[test] + fn take_until_either_incomplete() { + named!(x, take_until_either!("!.")); + assert_eq!( + x(&b"123"[..]), +- Error(Position(ErrorKind::TakeUntilEither, &b"123"[..])) ++ Error(error_position!(ErrorKind::TakeUntilEither, &b"123"[..])) ++ ); ++ } ++ ++ #[test] ++ fn take_until_either_and_consume() { ++ named!(x, take_until_either_and_consume!("!.")); ++ assert_eq!( ++ x(&b"123.abc"[..]), ++ Done(&b"abc"[..], &b"123"[..]) + ); + } + ++ + #[test] + fn take_until_incomplete() { + named!(y, take_until!("end")); +@@ -931,7 +948,7 @@ mod tests { + ); + assert_eq!( + y(&b"123"[..]), +- Error(Position(ErrorKind::TakeUntil, &b"123"[..])) ++ Error(error_position!(ErrorKind::TakeUntil, &b"123"[..])) + ); + } + +@@ -996,10 +1013,40 @@ mod tests { + let c = b"abcd123"; + let d = b"123"; + +- assert_eq!(f(&a[..]), Error(Position(ErrorKind::TakeWhile1, &b""[..]))); ++ assert_eq!(f(&a[..]), Incomplete(Needed::Size(1))); + assert_eq!(f(&b[..]), Done(&a[..], &b[..])); + assert_eq!(f(&c[..]), Done(&b"123"[..], &b[..])); +- assert_eq!(f(&d[..]), Error(Position(ErrorKind::TakeWhile1, &d[..]))); ++ assert_eq!(f(&d[..]), Error(error_position!(ErrorKind::TakeWhile1, &d[..]))); ++ } ++ ++ #[test] ++ fn take_till() { ++ use nom::is_alphabetic; ++ named!(f, take_till!(is_alphabetic)); ++ let a = b""; ++ let b = b"abcd"; ++ let c = b"123abcd"; ++ let d = b"123"; ++ ++ assert_eq!(f(&a[..]), Done(&b""[..], &b""[..])); ++ assert_eq!(f(&b[..]), Done(&b"abcd"[..], &b""[..])); ++ assert_eq!(f(&c[..]), Done(&b"abcd"[..], &b"123"[..])); ++ assert_eq!(f(&d[..]), Done(&b""[..], &b"123"[..])); ++ } ++ ++ #[test] ++ fn take_till1() { ++ use nom::is_alphabetic; ++ named!(f, take_till1!(is_alphabetic)); ++ let a = b""; ++ let b = b"abcd"; ++ let c = b"123abcd"; ++ let d = b"123"; ++ ++ assert_eq!(f(&a[..]), Incomplete(Needed::Size(1))); ++ assert_eq!(f(&b[..]), Error(error_position!(ErrorKind::TakeTill1, &b[..]))); ++ assert_eq!(f(&c[..]), Done(&b"abcd"[..], &b"123"[..])); ++ assert_eq!(f(&d[..]), Done(&b""[..], &b"123"[..])); + } + + #[cfg(feature = "nightly")] +@@ -1016,6 +1063,7 @@ mod tests { + } + + #[test] ++ #[cfg(feature = "std")] + fn recognize_take_while() { + use nom::is_alphanumeric; + named!(x, take_while!(is_alphanumeric)); +@@ -1024,4 +1072,48 @@ mod tests { + println!("X: {:?}", x(&b"ab"[..])); + assert_eq!(y(&b"ab"[..]), Done(&[][..], &b"ab"[..])); + } ++ ++ #[test] ++ fn length_bytes() { ++ use nom::le_u8; ++ named!(x, length_bytes!(le_u8)); ++ assert_eq!(x(b"\x02..>>"), Done(&b">>"[..], &b".."[..])); ++ assert_eq!(x(b"\x02.."), Done(&[][..], &b".."[..])); ++ assert_eq!(x(b"\x02."), Incomplete(Needed::Size(3))); ++ assert_eq!(x(b"\x02"), Incomplete(Needed::Size(3))); ++ ++ named!(y, do_parse!(tag!("magic") >> b: length_bytes!(le_u8) >> (b))); ++ assert_eq!(y(b"magic\x02..>>"), Done(&b">>"[..], &b".."[..])); ++ assert_eq!(y(b"magic\x02.."), Done(&[][..], &b".."[..])); ++ assert_eq!(y(b"magic\x02."), Incomplete(Needed::Size(8))); ++ assert_eq!(y(b"magic\x02"), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ fn case_insensitive() { ++ named!(test, tag_no_case!("ABcd")); ++ assert_eq!(test(&b"aBCdefgh"[..]), Done(&b"efgh"[..], &b"aBCd"[..])); ++ assert_eq!(test(&b"abcdefgh"[..]), Done(&b"efgh"[..], &b"abcd"[..])); ++ assert_eq!(test(&b"ABCDefgh"[..]), Done(&b"efgh"[..], &b"ABCD"[..])); ++ assert_eq!(test(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(test(&b"Hello"[..]), Error(error_position!(ErrorKind::Tag, &b"Hello"[..]))); ++ assert_eq!(test(&b"Hel"[..]), Error(error_position!(ErrorKind::Tag, &b"Hel"[..]))); ++ ++ named!(test2<&str, &str>, tag_no_case!("ABcd")); ++ assert_eq!(test2("aBCdefgh"), Done("efgh", "aBCd")); ++ assert_eq!(test2("abcdefgh"), Done("efgh", "abcd")); ++ assert_eq!(test2("ABCDefgh"), Done("efgh", "ABCD")); ++ assert_eq!(test2("ab"), Incomplete(Needed::Size(4))); ++ assert_eq!(test2("Hello"), Error(error_position!(ErrorKind::Tag, &"Hello"[..]))); ++ assert_eq!(test2("Hel"), Error(error_position!(ErrorKind::Tag, &"Hel"[..]))); ++ } ++ ++ #[test] ++ fn tag_fixed_size_array() { ++ named!(test, tag!([0x42])); ++ named!(test2, tag!(&[0x42])); ++ let input = [0x42, 0x00]; ++ assert_eq!(test(&input), Done(&b"\x00"[..], &b"\x42"[..])); ++ assert_eq!(test2(&input), Done(&b"\x00"[..], &b"\x42"[..])); ++ } + } +diff --git third_party/rust/nom/src/character.rs third_party/rust/nom/src/character.rs +index 781065b35270..6748e0790b68 100644 +--- third_party/rust/nom/src/character.rs ++++ third_party/rust/nom/src/character.rs +@@ -1,51 +1,39 @@ + /// Character level parsers + +-use internal::{IResult,Needed,Err}; +-use util::ErrorKind; ++use internal::{IResult,Needed}; ++use traits::{AsChar,InputIter,InputLength,Slice}; ++use std::ops::RangeFrom; + + /// matches one of the provided characters ++/// ++/// # Example ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult; ++/// # fn main() { ++/// named!(simple, one_of!(&b"abc"[..])); ++/// assert_eq!(simple(b"a123"), IResult::Done(&b"123"[..], 'a')); ++/// ++/// named!(a_or_b<&str, char>, one_of!("ab汉")); ++/// assert_eq!(a_or_b("汉jiosfe"), IResult::Done("jiosfe", '汉')); ++/// # } ++/// ``` + #[macro_export] + macro_rules! one_of ( + ($i:expr, $inp: expr) => ( + { +- if $i.is_empty() { +- $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) +- } else { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $inp; +- let bytes = as_bytes(&expected); +- one_of_bytes!($i, bytes) +- } +- } +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! one_of_bytes ( +- ($i:expr, $bytes: expr) => ( +- { +- if $i.is_empty() { +- $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) +- } else { +- let mut found = false; +- +- for &i in $bytes { +- if i == $i[0] { +- found = true; +- break; +- } +- } +- +- if found { +- $crate::IResult::Done(&$i[1..], $i[0] as char) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::OneOf, $i)) +- } ++ use $crate::Slice; ++ use $crate::AsChar; ++ use $crate::FindToken; ++ use $crate::InputIter; ++ ++ match ($i).iter_elements().next().map(|c| { ++ (c, c.find_token($inp)) ++ }) { ++ None => $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)), ++ Some((_, false)) => $crate::IResult::Error(error_position!($crate::ErrorKind::OneOf, $i)), ++ //the unwrap should be safe here ++ Some((c, true)) => $crate::IResult::Done($i.slice(c.len()..), $i.iter_elements().next().unwrap().as_char()) + } + } + ); +@@ -56,44 +44,18 @@ macro_rules! one_of_bytes ( + macro_rules! none_of ( + ($i:expr, $inp: expr) => ( + { +- if $i.is_empty() { +- $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) +- } else { +- #[inline(always)] +- fn as_bytes(b: &T) -> &[u8] { +- b.as_bytes() +- } +- +- let expected = $inp; +- let bytes = as_bytes(&expected); +- none_of_bytes!($i, bytes) +- } +- } +- ); +-); +- +-#[doc(hidden)] +-#[macro_export] +-macro_rules! none_of_bytes ( +- ($i:expr, $bytes: expr) => ( +- { +- if $i.is_empty() { +- $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)) +- } else { +- let mut found = false; +- +- for &i in $bytes { +- if i == $i[0] { +- found = true; +- break; +- } +- } +- +- if !found { +- $crate::IResult::Done(&$i[1..], $i[0] as char) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::NoneOf, $i)) +- } ++ use $crate::Slice; ++ use $crate::AsChar; ++ use $crate::FindToken; ++ use $crate::InputIter; ++ ++ match ($i).iter_elements().next().map(|c| { ++ (c, !c.find_token($inp)) ++ }) { ++ None => $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)), ++ Some((_, false)) => $crate::IResult::Error(error_position!($crate::ErrorKind::NoneOf, $i)), ++ //the unwrap should be safe here ++ Some((c, true)) => $crate::IResult::Done($i.slice(c.len()..), $i.iter_elements().next().unwrap().as_char()) + } + } + ); +@@ -104,49 +66,39 @@ macro_rules! none_of_bytes ( + macro_rules! char ( + ($i:expr, $c: expr) => ( + { +- if $i.is_empty() { +- let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1)); +- res +- } else { +- if $i[0] == $c as u8 { +- $crate::IResult::Done(&$i[1..], $i[0] as char) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Char, $i)) +- } ++ use $crate::Slice; ++ use $crate::AsChar; ++ use $crate::InputIter; ++ ++ match ($i).iter_elements().next().map(|c| { ++ (c, c.as_char() == $c) ++ }) { ++ None => $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1)), ++ Some((_, false)) => $crate::IResult::Error(error_position!($crate::ErrorKind::Char, $i)), ++ //the unwrap should be safe here ++ Some((c, true)) => $crate::IResult::Done($i.slice(c.len()..), $i.iter_elements().next().unwrap().as_char()) + } + } + ); + ); + +-named!(pub newline, char!('\n')); ++named!(#[doc="Matches a newline character '\\n'"], pub newline, char!('\n')); + +-pub fn crlf(input:&[u8]) -> IResult<&[u8], char> { +- if input.len() < 2 { +- IResult::Incomplete(Needed::Size(2)) +- } else { +- if &input[0..2] == &b"\r\n"[..] { +- IResult::Done(&input[2..], '\n') +- } else { +- IResult::Error(Err::Position(ErrorKind::CrLf, input)) +- } +- } +-} +- +-named!(pub eol, alt!(crlf | newline)); +-named!(pub tab, char!('\t')); ++named!(#[doc="Matches a tab character '\\t'"], pub tab, char!('\t')); + +-pub fn anychar(input:&[u8]) -> IResult<&[u8], char> { +- if input.is_empty() { ++pub fn anychar(input: T) -> IResult where ++ T: InputIter+InputLength+Slice>, ++ ::Item: AsChar { ++ if input.input_len() == 0 { + IResult::Incomplete(Needed::Size(1)) + } else { +- IResult::Done(&input[1..], input[0] as char) ++ IResult::Done(input.slice(1..), input.iter_elements().next().expect("slice should contain at least one element").as_char()) + } + } + + #[cfg(test)] + mod tests { + use internal::IResult::*; +- use internal::Err::*; + use util::ErrorKind; + + #[test] +@@ -157,7 +109,13 @@ mod tests { + assert_eq!(f(a), Done(&b"bcd"[..], 'a')); + + let b = &b"cde"[..]; +- assert_eq!(f(b), Error(Position(ErrorKind::OneOf, b))); ++ assert_eq!(f(b), Error(error_position!(ErrorKind::OneOf, b))); ++ ++ named!(utf8(&str) -> char, ++ one_of!("+\u{FF0B}")); ++ ++ assert!(utf8("+").is_done()); ++ assert!(utf8("\u{FF0B}").is_done()); + } + + #[test] +@@ -165,7 +123,7 @@ mod tests { + named!(f, none_of!("ab")); + + let a = &b"abcd"[..]; +- assert_eq!(f(a), Error(Position(ErrorKind::NoneOf, a))); ++ assert_eq!(f(a), Error(error_position!(ErrorKind::NoneOf, a))); + + let b = &b"cde"[..]; + assert_eq!(f(b), Done(&b"de"[..], 'c')); +@@ -176,9 +134,10 @@ mod tests { + named!(f, char!('c')); + + let a = &b"abcd"[..]; +- assert_eq!(f(a), Error(Position(ErrorKind::Char, a))); ++ assert_eq!(f(a), Error(error_position!(ErrorKind::Char, a))); + + let b = &b"cde"[..]; + assert_eq!(f(b), Done(&b"de"[..], 'c')); + } ++ + } +diff --git third_party/rust/nom/src/internal.rs third_party/rust/nom/src/internal.rs +index deb39a86654d..c5a51ee2bb09 100644 +--- third_party/rust/nom/src/internal.rs ++++ third_party/rust/nom/src/internal.rs +@@ -2,27 +2,15 @@ + + use self::IResult::*; + use self::Needed::*; +-use util::ErrorKind; + +-#[cfg(feature = "core")] ++#[cfg(not(feature = "std"))] + use std::prelude::v1::*; +-use std::boxed::Box; + +-/// Contains the error that a parser can return +-/// +-/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data. +-/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32) +-#[derive(Debug,PartialEq,Eq,Clone)] +-pub enum Err{ +- /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E +- Code(ErrorKind), +- /// An error code, and the next error +- Node(ErrorKind, Box>), +- /// An error code, and the input position +- Position(ErrorKind, P), +- /// An error code, the input position and the next error +- NodePosition(ErrorKind, P, Box>) +-} ++#[cfg(feature = "verbose-errors")] ++use verbose_errors::Err; ++ ++#[cfg(not(feature = "verbose-errors"))] ++use simple_errors::Err; + + /// Contains information on needed data if a parser returned `Incomplete` + #[derive(Debug,PartialEq,Eq,Clone,Copy)] +@@ -48,10 +36,23 @@ impl Needed { + } + } + ++#[cfg(feature = "verbose-errors")] + /// Holds the result of parsing functions + /// + /// It depends on I, the input type, O, the output type, and E, the error type (by default u32) + /// ++/// Depending on a compilation flag, the content of the `Error` variant ++/// can change. By default, it will be a `ErrorKind` (with `E` configurable). ++/// ++/// If you activate the `verbose-errors` compilation flags, it will be an ++/// enum that contains an error code, optionally, an input position, ++/// and an error sent by child parsers. ++/// ++/// The verbose errors feature allows very flexible error management: ++/// you can know precisely which parser got to which part of the input. ++/// The main drawback is that it is a lot slower than default error ++/// management. ++/// + #[derive(Debug,PartialEq,Eq,Clone)] + pub enum IResult { + /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data +@@ -62,6 +63,41 @@ pub enum IResult { + Incomplete(Needed) + } + ++#[cfg(not(feature = "verbose-errors"))] ++/// Holds the result of parsing functions ++/// ++/// It depends on I, the input type, O, the output type, and E, the error type (by default u32) ++/// ++#[derive(Debug,PartialEq,Eq,Clone)] ++pub enum IResult { ++ /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data ++ Done(I,O), ++ /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree ++ Error(Err), ++ /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown ++ Incomplete(Needed) ++} ++ ++#[cfg(feature = "verbose-errors")] ++/// This is the same as IResult, but without Done ++/// ++/// This is used as the Error type when converting to std::result::Result ++#[derive(Debug,PartialEq,Eq,Clone)] ++pub enum IError { ++ Error(Err), ++ Incomplete(Needed) ++} ++ ++#[cfg(not(feature = "verbose-errors"))] ++/// This is the same as IResult, but without Done ++/// ++/// This is used as the Error type when converting to std::result::Result ++#[derive(Debug,PartialEq,Eq,Clone)] ++pub enum IError { ++ Error(Err), ++ Incomplete(Needed) ++} ++ + impl IResult { + pub fn is_done(&self) -> bool { + match *self { +@@ -84,6 +120,14 @@ impl IResult { + } + } + ++ pub fn or(self, other: IResult) -> IResult { ++ if self.is_done() { ++ self ++ } else { ++ other ++ } ++ } ++ + /// Maps a `IResult` to `IResult` by appling a function + /// to a contained `Done` value, leaving `Error` and `Incomplete` value + /// untouched. +@@ -109,19 +153,6 @@ impl IResult { + } + } + +- /// Maps a `IResult` to `IResult` by appling a function +- /// to a contained `Error` value, leaving `Done` and `Incomplete` value +- /// untouched. +- #[inline] +- pub fn map_err(self, f: F) -> IResult +- where F: FnOnce(Err) -> Err { +- match self { +- Error(e) => Error(f(e)), +- Incomplete(n) => Incomplete(n), +- Done(i, o) => Done(i, o), +- } +- } +- + /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not + /// `Done`. + pub fn unwrap(self) -> (I, O) { +@@ -132,23 +163,23 @@ impl IResult { + } + } + +- /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not ++ /// Unwrap the contained `Done(I, O)` value or a default if the `IResult` is not + /// `Done`. +- pub fn unwrap_inc(self) -> Needed { ++ pub fn unwrap_or(self, default: (I, O)) -> (I, O) { + match self { +- Incomplete(n) => n, +- Done(_, _) => panic!("unwrap_inc() called on an IResult that is Done"), +- Error(_) => panic!("unwrap_inc() called on an IResult that is Error") ++ Done(i, o) => (i, o), ++ Incomplete(_) => default, ++ Error(_) => default + } + } + +- /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not +- /// `Done`. +- pub fn unwrap_err(self) -> Err { ++ /// Unwrap the contained `Incomplete(n)` value, or panic if the `IResult` is not ++ /// `Incomplete`. ++ pub fn unwrap_inc(self) -> Needed { + match self { +- Error(e) => e, +- Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"), +- Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"), ++ Incomplete(n) => n, ++ Done(_, _) => panic!("unwrap_inc() called on an IResult that is Done"), ++ Error(_) => panic!("unwrap_inc() called on an IResult that is Error") + } + } + } +@@ -215,35 +246,130 @@ impl<'a,I,E> GetOutput<&'a str> for IResult { + } + } + +-#[cfg(not(feature = "core"))] +-use std::any::Any; +-#[cfg(not(feature = "core"))] +-use std::{error,fmt}; +-#[cfg(not(feature = "core"))] +-use std::fmt::Debug; +-#[cfg(not(feature = "core"))] +-impl error::Error for Err { +- fn description(&self) -> &str { +- let kind = match *self { +- Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e ++#[cfg(feature = "verbose-errors")] ++/// creates a parse error from a `nom::ErrorKind` ++#[macro_export] ++macro_rules! error_code( ++ ($code:expr) => ($crate::Err::Code($code)); ++); ++ ++#[cfg(not(feature = "verbose-errors"))] ++/// creates a parse error from a `nom::ErrorKind` ++#[macro_export] ++macro_rules! error_code( ++ ($code:expr) => ($code); ++); ++ ++#[cfg(feature = "verbose-errors")] ++/// creates a parse error from a `nom::ErrorKind` ++/// and the next error in the parsing tree. ++/// if "verbose-errors" is not activated, ++/// it default to only the error code ++#[macro_export] ++macro_rules! error_node( ++ ($code:expr, $next:expr) => { ++ let next_errors = match $next { ++ $crate::Err::Code(e) => { ++ let mut v = ::std::vec::Vec::new(); ++ v.push($crate::Err::Code(e)); ++ v ++ }, ++ $crate::Err::Position(e, p) => { ++ let mut v = ::std::vec::Vec::new(); ++ v.push($crate::Err::Position(e,p)); ++ v ++ }, ++ $crate::Err::Node(e, mut next) => { ++ next.push($crate::Err::Code(e)); ++ next ++ }, ++ $crate::Err::NodePosition(e, p, mut next) => { ++ next.push($crate::Err::Position(e,p)); ++ next ++ }, + }; +- kind.description() +- } +-} +- +-#[cfg(not(feature = "core"))] +-impl fmt::Display for Err { +- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +- match *self { +- Err::Code(ref e) | Err::Node(ref e, _) => { +- write!(f, "{:?}", e) ++ $crate::Err::Node($code, next_errors) ++ }; ++); ++ ++#[cfg(not(feature = "verbose-errors"))] ++/// creates a parse error from a `nom::ErrorKind` ++/// and the next error in the parsing tree. ++/// if "verbose-errors" is not activated, ++/// it default to only the error code ++#[allow(unused_variables)] ++#[macro_export] ++macro_rules! error_node( ++ ($code:expr, $next:expr) => ($code); ++); ++ ++#[cfg(feature = "verbose-errors")] ++/// creates a parse error from a `nom::ErrorKind` ++/// and the position in the input ++/// if "verbose-errors" is not activated, ++/// it default to only the error code ++#[macro_export] ++macro_rules! error_position( ++ ($code:expr, $input:expr) => ($crate::Err::Position($code, $input)); ++); ++ ++#[cfg(not(feature = "verbose-errors"))] ++/// creates a parse error from a `nom::ErrorKind` ++/// and the position in the input ++/// if "verbose-errors" is not activated, ++/// it default to only the error code ++#[allow(unused_variables)] ++#[macro_export] ++macro_rules! error_position( ++ ($code:expr, $input:expr) => ($code); ++); ++ ++#[cfg(feature = "verbose-errors")] ++/// creates a parse error from a `nom::ErrorKind`, ++/// the position in the input and the next error in ++/// the parsing tree. ++/// if "verbose-errors" is not activated, ++/// it default to only the error code ++#[macro_export] ++macro_rules! error_node_position( ++ ($code:expr, $input:expr, $next:expr) => { ++ { ++ let next_errors = match $next { ++ $crate::Err::Code(e) => { ++ let mut v = ::std::vec::Vec::new(); ++ v.push($crate::Err::Code(e)); ++ v + }, +- Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => { +- write!(f, "{:?}:{:?}", p, e) ++ $crate::Err::Position(e, p) => { ++ let mut v = ::std::vec::Vec::new(); ++ v.push($crate::Err::Position(e,p)); ++ v ++ }, ++ $crate::Err::Node(e, mut next) => { ++ next.push($crate::Err::Code(e)); ++ next ++ }, ++ $crate::Err::NodePosition(e, p, mut next) => { ++ next.push($crate::Err::Position(e,p)); ++ next + } ++ }; ++ $crate::Err::NodePosition($code, $input, next_errors) + } + } +-} ++); ++ ++#[cfg(not(feature = "verbose-errors"))] ++/// creates a parse error from a `nom::ErrorKind`, ++/// the position in the input and the next error in ++/// the parsing tree. ++/// if "verbose-errors" is not activated, ++/// it default to only the error code ++#[allow(unused_variables)] ++#[macro_export] ++macro_rules! error_node_position( ++ ($code:expr, $input: expr, $next:expr) => ($code); ++); + + #[cfg(test)] + mod tests { +@@ -252,9 +378,16 @@ mod tests { + + const REST: [u8; 0] = []; + const DONE: IResult<&'static [u8], u32> = IResult::Done(&REST, 5); +- const ERROR: IResult<&'static [u8], u32> = IResult::Error(Err::Code(ErrorKind::Tag)); ++ const ERROR: IResult<&'static [u8], u32> = IResult::Error(error_code!(ErrorKind::Tag)); + const INCOMPLETE: IResult<&'static [u8], u32> = IResult::Incomplete(Needed::Unknown); + ++ #[test] ++ fn iresult_or() { ++ assert_eq!(DONE.or(ERROR), DONE); ++ assert_eq!(ERROR.or(DONE), DONE); ++ assert_eq!(INCOMPLETE.or(ERROR), ERROR); ++ } ++ + #[test] + fn needed_map() { + let unknown = Needed::Unknown; +@@ -267,7 +400,7 @@ mod tests { + #[test] + fn iresult_map() { + assert_eq!(DONE.map(|x| x * 2), IResult::Done(&b""[..], 10)); +- assert_eq!(ERROR.map(|x| x * 2), IResult::Error(Err::Code(ErrorKind::Tag))); ++ assert_eq!(ERROR.map(|x| x * 2), IResult::Error(error_code!(ErrorKind::Tag))); + assert_eq!(INCOMPLETE.map(|x| x * 2), IResult::Incomplete(Needed::Unknown)); + } + +@@ -277,17 +410,18 @@ mod tests { + let inc_size: IResult<&[u8], u32> = IResult::Incomplete(Needed::Size(5)); + + assert_eq!(DONE.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Done(&b""[..], 5)); +- assert_eq!(ERROR.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Error(Err::Code(ErrorKind::Tag))); ++ assert_eq!(ERROR.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Error(error_code!(ErrorKind::Tag))); + assert_eq!(inc_unknown.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Unknown)); + assert_eq!(inc_size.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Size(6))); + } + + #[test] ++ #[cfg(feature = "std")] + fn iresult_map_err() { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Error(u32); + +- let error_kind = Err::Code(ErrorKind::Custom(Error(5))); ++ let error_kind = error_code!(ErrorKind::Custom(Error(5))); + + assert_eq!(DONE.map_err(|_| error_kind.clone()), IResult::Done(&b""[..], 5)); + assert_eq!(ERROR.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Error(error_kind.clone())); +@@ -311,6 +445,21 @@ mod tests { + INCOMPLETE.unwrap(); + } + ++ #[test] ++ fn iresult_unwrap_or_on_done() { ++ assert_eq!(DONE.unwrap_or((&b""[..], 2)), (&b""[..], 5)); ++ } ++ ++ #[test] ++ fn iresult_unwrap_or_on_err() { ++ assert_eq!(ERROR.unwrap_or((&b""[..], 2)), (&b""[..], 2)); ++ } ++ ++ #[test] ++ fn iresult_unwrap_or_on_inc() { ++ assert_eq!(INCOMPLETE.unwrap_or((&b""[..], 2)), (&b""[..], 2)); ++ } ++ + #[test] + #[should_panic] + fn iresult_unwrap_err_on_done() { +@@ -319,7 +468,7 @@ mod tests { + + #[test] + fn iresult_unwrap_err_on_err() { +- assert_eq!(ERROR.unwrap_err(), Err::Code(ErrorKind::Tag)); ++ assert_eq!(ERROR.unwrap_err(), error_code!(ErrorKind::Tag)); + } + + #[test] +@@ -344,4 +493,23 @@ mod tests { + fn iresult_unwrap_inc_on_inc() { + assert_eq!(INCOMPLETE.unwrap_inc(), Needed::Unknown); + } ++ ++ #[test] ++ fn iresult_to_result() { ++ assert_eq!(DONE.to_result(), Ok(5)); ++ assert_eq!(ERROR.to_result(), Err(error_code!(ErrorKind::Tag))); ++ } ++ ++ #[test] ++ #[should_panic] ++ fn iresult_to_result_on_incomplete() { ++ INCOMPLETE.to_result().unwrap(); ++ } ++ ++ #[test] ++ fn iresult_to_full_result() { ++ assert_eq!(DONE.to_full_result(), Ok(5)); ++ assert_eq!(INCOMPLETE.to_full_result(), Err(IError::Incomplete(Needed::Unknown))); ++ assert_eq!(ERROR.to_full_result(), Err(IError::Error(error_code!(ErrorKind::Tag)))); ++ } + } +diff --git third_party/rust/nom/src/lib.rs third_party/rust/nom/src/lib.rs +index 11b475d59517..150ef85fce57 100644 +--- third_party/rust/nom/src/lib.rs ++++ third_party/rust/nom/src/lib.rs +@@ -5,6 +5,318 @@ + //! + //! The code is available on [Github](https://github.com/Geal/nom) + //! ++//! There are a few [guides](http://rust.unhandledexpression.com/nom/home.html) with more details ++//! about [the design of nom](http://rust.unhandledexpression.com/nom/how_nom_macros_work.html), ++//! [how to write parsers](http://rust.unhandledexpression.com/nom/making_a_new_parser_from_scratch.html), ++//! or the [error management system](http://rust.unhandledexpression.com/nom/error_management.html). ++//! ++//! If you are upgrading to nom 2.0, please read the ++//! [migration document](http://rust.unhandledexpression.com/nom/upgrading_to_nom_2.html). ++//! ++//! See also the [FAQ](http://rust.unhandledexpression.com/nom/FAQ.html). ++//! ++//! # What are parser combinators? ++//! ++//! Parser combinators are a way to build parsers out of small functions. instead of ++//! writing a huge grammar file then generaing code, like you would do with lex and yacc, ++//! you write small functions, to parse small things like a character, or a number, ++//! and then you assemble them in larger and larger functions, that can parse larger ++//! parts of your formats. ++//! ++//! You end up with a list of small functions that you can reuse everywhere you need. Each ++//! of them can be unit tested anf fuzzed separately. ++//! ++//! # nom parser design ++//! ++//! All nom parsers follow the same convention. They are all functions with the following signature: ++//! ++//! ```ignore ++//! fn parser(input: I) -> IResult { ... } ++//! ``` ++//! ++//! Here is the definition of that `IResult` type: ++//! ++//! ``` ++//! # #[macro_use] extern crate nom; ++//! # use nom::{Err,Needed}; ++//! # fn main() {} ++//! pub enum IResult { ++//! Done(I,O), ++//! Error(Err), // indicates the parser encountered an error. E is a custom error type you can redefine ++//! /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown ++//! Incomplete(Needed) // if the parser did not have enough data to decide ++//! } ++//! ``` ++//! ++//! What it means: ++//! ++//! * `Done(i,o)` means the parser was successful. `i` is the remaining part of the input, `o` is the correctly parsed value ++//! The remaining part can then be used as input for other parsers called in a sequence ++//! * `Error(e)` indicates the parser encountered an error. The `Err` type is an enum of possible parser errors, ++//! that can also contain a custom error that you'd specify, by redefining the `E` error type ++//! * `Incomplete(i)` means the parser did not have enough information to decide, and tells you, if possible, ++//! how much data it needs ++//! ++//! That way, you could write your own parser that recognizes the letter 'a' like this: ++//! ++//! ``` ++//! #[macro_use] extern crate nom; ++//! use nom::{IResult,Needed,Err,ErrorKind}; ++//! # fn main() {} ++//! ++//! fn a(input: &[u8]) -> IResult<&[u8], char> { ++//! // if there is not enough data, we return Ìncomplete ++//! if input.len() == 0 { ++//! IResult::Incomplete(Needed::Size(1)) ++//! } else { ++//! if input[0] == 'a' as u8 { ++//! // the first part of the returned value is the remaining slice ++//! IResult::Done(&input[1..], 'a') ++//! } else { ++//! IResult::Error(error_code!(ErrorKind::Custom(42))) ++//! } ++//! } ++//! } ++//! ``` ++//! ++//! Writing all the parsers manually, like this, is dangerous, despite Rust's safety features. There ++//! are still a lot of mistakes one can make. That's why nom provides a list of macros to help in ++//! developing parsers. As an example, here is a parser that would recognize the phrase ++//! "Hello " and return the name of the person we hail: ++//! ++//! ``` ++//! #[macro_use] extern crate nom; ++//! use nom::alpha; ++//! ++//! named!(hello, preceded!(tag!("Hello "), alpha)); ++//! # use nom::IResult; ++//! # fn main() { ++//! # assert_eq!(hello(b"Hello nom."), IResult::Done(&b"."[..], &b"nom"[..])); ++//! # } ++//! ``` ++//! ++//! Let's deconstruct it: ++//! ++//! * `named!` generates a function with the correct type. Without `named` here, we could write the parser ++//! as follows: ++//! ++//! ``` ++//! #[macro_use] extern crate nom; ++//! use nom::{alpha,IResult}; ++//! ++//! fn hello(input: &[u8]) -> IResult<&[u8], &[u8]> { ++//! preceded!(input, ++//! tag!("Hello "), alpha) ++//! } ++//! # fn main() { ++//! # assert_eq!(hello(b"Hello nom."), IResult::Done(&b"."[..], &b"nom"[..])); ++//! # } ++//! ``` ++//! ++//! By default, `named` makes a function that takes `&[u8]` as input type, and returns `&[u8]` as output type. ++//! You can override it like this: ++//! ++//! * `named!(hello<&str>, ...):` would take `&[u8]` as input type, and return `&str` as output type. ++//! * `named!(hello<&str, &str>, ...):` would take `&str` as input type, and return `&str` as output type. ++//! ++//! *Note* : when we don't use `named!`, we must pass the input as first argument of the top ++//! level combinator (see the line `preceded!(input,` in the preceding code example). This is a macro trick ++//! in nom to pass input from one combinator to the next by rewriting the call. ++//! ++//! Next part of the parser: `preceded!(tag!("Hello "), alpha))`. Here, `tag!` is a combinator that recognizes ++//! a specific serie of bytes or characters. `alpha` is a function that recognizes alphabetical characters. ++//! The `preceded!` combinator assembles them in a more complex parser: if both parsers are successful, ++//! it returns the result of the second one (`alpha` is preceded by `tag!`). ++//! ++//! *Note* : combinators can assemble other combinators (macros), or parser functions, as long as they follow ++//! the same interface. Here, `alpha` is a parser function already implemented in nom. ++//! ++//! # List of parsers and combinators ++//! ++//! ## Basic elements ++//! ++//! Those are used to recognize the lowest level elements of your grammar, like, "here is a dot", or ++//! "here is an big endian integer". ++//! ++//! * **char!**: matches one character: `char!('a')` will make a parser that recognizes the letter 'a' (works with non ASCII chars too) ++//! * **eof!**: `eof!()` returns its input if it is at the end of input data ++//! * **is_a!, is_a_s!**: matches a sequence of any of the characters passed as arguments. `is_a!("ab1")` could recognize `ababa` or `1bb`. `is_a_s!` is a legacy combinator, it does exactly the same thing as `is_a` ++//! * **is_not!, is_not_s!**: matches a sequence of none of the characters passed as arguments ++//! * **one_of!**: matches one of the provided characters. `one_of!("abc")` could recognize 'a', 'b', or 'c'. It also works with non ASCII characters ++//! * **none_of!**: matches anything but the provided characters ++//! * **tag!, tag_s!**: recognizes a specific suite of characters or bytes. `tag!("hello")` matches "hello" ++//! * **tag_no_case!**: recognizes a suite of ASCII characters, case insensitive. `tag_no_case!("hello")` could match "hello", "Hello" or even "HeLlO" ++//! * **tag_no_case_s!** works like `tag_no_case` but on UTF-8 characters too (uses `&str` as input). Note that case insensitive comparison is not well defined for unicode, and that you might have bad surprises. Also, this combinator allocates a new string for the comparison. Ponder for a bit before using this combinator ++//! * **take!, take_s!**: takes a specific number of bytes or characters. `take!(5)` would return "hello" from the string "hello world" ++//! * **take_str!**: same as `take!` but returning a `&str` ++//! * **take_till!, take_till_s!**: returns the longest list of bytes until the provided function succeeds. `take_till!(is_alphabetic)` with input "123abc" would return "123" ++//! * **take_till1!, take_till1_s!**: same as `take_till!`, but the result must not be empty: `take_till1!(is_alphabetic)` would fail on "abc" ++//! * **take_until!, take_until_s!**: returns the longest list of bytes until the provided tag is found. `take_until!("world")` with input "Hello world!" would return "Hello " and leave "world!" as remaining input ++//! * **take_until1!**: same as `take_until!`, but cannot return an empty result ++//! * **take_until_and_consume!, take_until_and_consume_s!**: same as `take_until!` but consumes the tag. `take_until_and_consume!("world")` with input "Hello world!" would return "Hello " and leave "!" as remaining input ++//! * **take_until_and_consume1!**: same as `take_until_and_consume!`, but cannot return an empty result ++//! * **take_until_either!**: returns the longest list of bytes until any of the provided characters are found ++//! * **take_until_either_and_consume!**: same as `take_until_either!`, but consumes the terminating character ++//! * **take_while!, take_while_s!**: returns the longest list of bytes for which the function is true. `take_while!(is_alphabetic)` with input "abc123" would return "abc" ++//! * **take_while1!, take_while1_s!**: same as `take_while!`, but cannot return an empty result ++//! * **value!**: you can use `value!` to always return the same result value without consuming input, like this: `value!(42)`. Or you can replace the result of a child parser with a predefined value, like this: `value!(42, tag!("abcd"))` which would replace, if successful, the return value from "abcd", to 42 ++//! ++//! Parsing integers from binary formats can be done in two ways: with parser functions, or combinators with configurable endianness: ++//! ++//! * configurable endianness: **i16!, i32!, i64!, u16!, u32!, u64!** are combinators that take as argument a `nom::Endianness`, ++//! like this: `i16!(endianness)`. If the parameter is nom::Endianness::Big, parse a big endian i16 integer, otherwise a little endian i16 integer ++//! * fixed endianness: the functions are prefixed by "be_" for big endian numbers, and by "le_" for little endian numbers, and the suffix is the type they parse to. As an example, "be_u32" parses a big endian unsigned integer stored in 32 bits. ++//! * **be_f32, be_f64, le_f32, le_f64**: recognize floating point numbers ++//! * **be_i8, be_i16, be_i32, be_i24, be_i32, be_i64**: big endian signed integers ++//! * **be_u8, be_u16, be_u32, be_u24, be_u32, be_u64**: big endian unsigned integers ++//! * **le_i8, le_i16, le_i32, le_i24, le_i32, le_i64**: little endian signed integers ++//! * **le_u8, le_u16, le_u32, le_u24, le_u32, le_u64**: little endian unsigned integers ++//! ++//! ## Modifiers ++//! ++//! * **complete!**: replaces a Incomplete returned by the child parser with an Error ++//! * **cond!**: conditional combinator ++//! * **cond_reduce!**: Conditional combinator with error ++//! * **cond_with_error!**: Conditional combinator ++//! * **expr_opt!**: evaluates an expression that returns a Option and returns a IResult::Done(I,T) if Some ++//! * **expr_res!**: evaluates an expression that returns a Result and returns a IResult::Done(I,T) if Ok ++//! * **flat_map!**: ++//! * **map!**: maps a function on the result of a parser ++//! * **map_opt!**: maps a function returning an Option on the output of a parser ++//! * **map_res!**: maps a function returning a Result on the output of a parser ++//! * **not!**: returns a result only if the embedded parser returns Error or Incomplete does not consume the input ++//! * **opt!**: make the underlying parser optional ++//! * **opt_res!**: make the underlying parser optional ++//! * **parse_to!**: uses the parse method from std::str::FromStr to convert the current input to the specified type ++//! * **peek!**: returns a result without consuming the input ++//! * **recognize!**: if the child parser was successful, return the consumed input as produced value ++//! * **return_error!**: prevents backtracking if the child parser fails ++//! * **tap!**: allows access to the parser's result without affecting it ++//! * **verify!**: returns the result of the child parser if it satisfies a verification function ++//! ++//! ## Error management and debugging ++//! ++//! * **add_return_error!**: Add an error if the child parser fails ++//! * **dbg!**: Prints a message if the parser fails ++//! * **dbg_dmp!**: Prints a message and the input if the parser fails ++//! * **error_code!**: creates a parse error from a nom::ErrorKind ++//! * **error_node!**: creates a parse error from a nom::ErrorKind and the next error in the parsing tree. if "verbose-errors" is not activated, it default to only the error code ++//! * **error_node_position!**: creates a parse error from a nom::ErrorKind, the position in the input and the next error in the parsing tree. if "verbose-errors" is not activated, it default to only the error code ++//! * **error_position!**: creates a parse error from a nom::ErrorKind and the position in the input if "verbose-errors" is not activated, it default to only the error code ++//! * **fix_error!**: translate parser result from IResult to IResult with a custom type ++//! ++//! ## Choice combinators ++//! ++//! * **alt!**: try a list of parsers and return the result of the first successful one ++//! * **alt_complete!**: is equivalent to the alt! combinator, except that it will not return Incomplete when one of the constituting parsers returns Incomplete. Instead, it will try the next alternative in the chain. ++//! * **switch!**: choose the next parser depending on the result of the first one, if successful, and returns the result of the second parser ++//! ++//! # Sequence combinators ++//! ++//! * **delimited!**: delimited(opening, X, closing) returns X ++//! * **do_parse!**: do_parse applies sub parsers in a sequence. it can store intermediary results and make them available for later parsers ++//! * **pair!**: pair(X,Y), returns (x,y) ++//! * **permutation!**: applies its sub parsers in a sequence, but independent from their order this parser will only succeed if all of its sub parsers succeed ++//! * **preceded!**: preceded(opening, X) returns X ++//! * **separated_pair!**: separated_pair(X,sep,Y) returns (x,y) ++//! * **terminated!**: terminated(X, closing) returns X ++//! * **tuple!**: chains parsers and assemble the sub results in a tuple. ++//! ++//! ## Applying a parser multiple times ++//! ++//! * **count!**: Applies the child parser a specified number of times ++//! * **count_fixed!**: Applies the child parser a fixed number of times and returns a fixed size array The type must be specified and it must be Copy ++//! * **fold_many0!**: Applies the parser 0 or more times and folds the list of return values ++//! * **fold_many1!**: Applies the parser 1 or more times and folds the list of return values ++//! * **fold_many_m_n!**: Applies the parser between m and n times (n included) and folds the list of return value ++//! * **length_count!**: gets a number from the first parser, then applies the second parser that many times ++//! * **many0!**: Applies the parser 0 or more times and returns the list of results in a Vec ++//! * **many1!**: Applies the parser 1 or more times and returns the list of results in a Vec ++//! * **many_m_n!**: Applies the parser between m and n times (n included) and returns the list of results in a Vec ++//! * **many_till!**: Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second. ++//! * **separated_list!**: separated_list(sep, X) returns Vec will return Incomplete if there may be more elements ++//! * **separated_list_complete!**: This is equivalent to the separated_list! combinator, except that it will return Error when either the separator or element subparser returns Incomplete. ++//! * **separated_nonempty_list!**: separated_nonempty_list(sep, X) returns Vec will return Incomplete if there may be more elements ++//! * **separated_nonempty_list_complete!**: This is equivalent to the separated_nonempty_list! combinator, except that it will return Error when either the separator or element subparser returns Incomplete. ++//! ++//! ## Text parsing ++//! ++//! * **escaped!**: matches a byte string with escaped characters. ++//! * **escaped_transform!**: matches a byte string with escaped characters, and returns a new string with the escaped characters replaced ++//! ++//! ## Binary format parsing ++//! ++//! * **length_data!**: gets a number from the first parser, than takes a subslice of the input of that size, and returns that subslice ++//! * **length_bytes!**: alias for `length_data` ++//! * **length_value!**: gets a number from the first parser, takes a subslice of the input of that size, then applies the second parser on that subslice. If the second parser returns Incomplete, length_value will return an error ++//! ++//! ## Bit stream parsing ++//! ++//! * **bits!**: transforms the current input type (byte slice `&[u8]`) to a bit stream on which bit specific parsers and more general combinators can be applied ++//! * **bytes!**: transforms its bits stream input back into a byte slice for the underlying parsers. ++//! * **tag_bits!**: matches an integer pattern to a bitstream. The number of bits of the input to compare must be specified ++//! * **take_bits!**: generates a parser consuming the specified number of bits ++//! ++//! ## Whitespace delimited formats parsing ++//! ++//! * **eat_separator!**: helper macros to build a separator parser ++//! * **sep!**: sep is the parser rewriting macro for whitespace separated formats ++//! * **wrap_sep!**: ++//! * **ws!**: ++//! ++//! ## Remaining combinators ++//! ++//! * **apply!**: emulate function currying: apply!(my_function, arg1, arg2, ...) becomes my_function(input, arg1, arg2, ...) ++//! * **apply_m!**: emulate function currying for method calls on structs apply_m!(self.my_function, arg1, arg2, ...) becomes self.my_function(input, arg1, arg2, ...) ++//! * **call!**: Used to wrap common expressions and function as macros ++//! * **call_m!**: Used to called methods then move self back into self ++//! * **closure!**: Wraps a parser in a closure ++//! * **method!**: Makes a method from a parser combination ++//! * **named!**: Makes a function from a parser combination ++//! * **named_args!**: Makes a function from a parser combination with arguments. ++//! * **named_attr!**: Makes a function from a parser combination, with attributes ++//! * **try_parse!**: A bit like std::try!, this macro will return the remaining input and parsed value if the child parser returned Done, and will do an early return for Error and Incomplete this can provide more flexibility than do_parse! if needed ++//! ++//! ## Character test functions ++//! ++//! use those functions with a combinator like `take_while!`: ++//! ++//! * **is_alphabetic**: Tests if byte is ASCII alphabetic: A-Z, a-z ++//! * **is_alphanumeric**: Tests if byte is ASCII alphanumeric: A-Z, a-z, 0-9 ++//! * **is_digit**: Tests if byte is ASCII digit: 0-9 ++//! * **is_hex_digit**: Tests if byte is ASCII hex digit: 0-9, A-F, a-f ++//! * **is_oct_digit**: Tests if byte is ASCII octal digit: 0-7 ++//! * **is_space**: Tests if byte is ASCII space or tab ++//! ++//! ## Remaining functions (sort those out in the other categories) ++//! ++//! * **alpha**: Recognizes one or more lowercase and uppercase alphabetic characters: a-zA-Z ++//! * **alphanumeric**: Recognizes one or more numerical and alphabetic characters: 0-9a-zA-Z ++//! * **anychar**: ++//! * **begin**: ++//! * **crlf**: ++//! * **digit**: Recognizes one or more numerical characters: 0-9 ++//! * **double**: Recognizes floating point number in a byte string and returns a f64 ++//! * **double_s**: Recognizes floating point number in a string and returns a f64 ++//! * **eol**: ++//! * **float**: Recognizes floating point number in a byte string and returns a f32 ++//! * **float_s**: Recognizes floating point number in a string and returns a f32 ++//! * **hex_digit**: Recognizes one or more hexadecimal numerical characters: 0-9, A-F, a-f ++//! * **hex_u32**: Recognizes a hex-encoded integer ++//! * **line_ending**: Recognizes an end of line (both '\n' and "\r\n") ++//! * **multispace**: Recognizes one or more spaces, tabs, carriage returns and line feeds ++//! * **newline**: Matches a newline character '\n' ++//! * **non_empty**: Recognizes non empty buffers ++//! * **not_line_ending**: ++//! * **oct_digit**: Recognizes one or more octal characters: 0-7 ++//! * **rest**: Return the remaining input. ++//! * **rest_s**: Return the remaining input, for strings. ++//! * **shift**: ++//! * **sized_buffer**: ++//! * **space**: Recognizes one or more spaces and tabs ++//! * **tab**: Matches a tab character '\t' ++//! * **tag_cl**: ++//! + //! # Example + //! + //! ``` +@@ -12,65 +324,57 @@ + //! extern crate nom; + //! + //! use nom::{IResult,digit}; +-//! use nom::IResult::*; + //! + //! // Parser definition + //! + //! use std::str; + //! use std::str::FromStr; + //! +-//! named!(parens, delimited!( +-//! char!('('), +-//! expr, +-//! char!(')') +-//! ) +-//! ); ++//! // We parse any expr surrounded by parens, ignoring all whitespaces around those ++//! named!(parens, ws!(delimited!( tag!("("), expr, tag!(")") )) ); + //! +-//! named!(i64_digit, +-//! map_res!( ++//! // We transform an integer string into a i64, ignoring surrounding whitespaces ++//! // We look for a digit suite, and try to convert it. ++//! // If either str::from_utf8 or FromStr::from_str fail, ++//! // we fallback to the parens parser defined above ++//! named!(factor, alt!( + //! map_res!( +-//! digit, +-//! str::from_utf8 +-//! ), +-//! FromStr::from_str +-//! ) +-//! ); +-//! +-//! // We transform an integer string into a i64 +-//! // we look for a digit suite, and try to convert it. +-//! // if either str::from_utf8 or FromStr::from_str fail, +-//! // the parser will fail +-//! named!(factor, +-//! alt!( +-//! i64_digit ++//! map_res!( ++//! ws!(digit), ++//! str::from_utf8 ++//! ), ++//! FromStr::from_str ++//! ) + //! | parens + //! ) + //! ); + //! +-//! // we define acc as mutable to update its value whenever a new term is found +-//! named!(term , +-//! chain!( +-//! mut acc: factor ~ +-//! many0!( +-//! alt!( +-//! tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) | +-//! tap!(div: preceded!(tag!("/"), factor) => acc = acc / div) +-//! ) +-//! ), +-//! || { return acc } ++//! // We read an initial factor and for each time we find ++//! // a * or / operator followed by another factor, we do ++//! // the math by folding everything ++//! named!(term , do_parse!( ++//! init: factor >> ++//! res: fold_many0!( ++//! pair!(alt!(tag!("*") | tag!("/")), factor), ++//! init, ++//! |acc, (op, val): (&[u8], i64)| { ++//! if (op[0] as char) == '*' { acc * val } else { acc / val } ++//! } ++//! ) >> ++//! (res) + //! ) + //! ); + //! +-//! named!(expr , +-//! chain!( +-//! mut acc: term ~ +-//! many0!( +-//! alt!( +-//! tap!(add: preceded!(tag!("+"), term) => acc = acc + add) | +-//! tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub) +-//! ) +-//! ), +-//! || { return acc } ++//! named!(expr , do_parse!( ++//! init: term >> ++//! res: fold_many0!( ++//! pair!(alt!(tag!("+") | tag!("-")), term), ++//! init, ++//! |acc, (op, val): (&[u8], i64)| { ++//! if (op[0] as char) == '+' { acc + val } else { acc - val } ++//! } ++//! ) >> ++//! (res) + //! ) + //! ); + //! +@@ -84,25 +388,38 @@ + //! assert_eq!(expr(b"2*2/(5-1)+3"), IResult::Done(&b""[..], 4)); + //! } + //! ``` +-#![cfg_attr(feature = "core", feature(no_std))] +-#![cfg_attr(feature = "core", feature(collections))] +-#![cfg_attr(feature = "core", no_std)] ++#![cfg_attr(not(feature = "std"), feature(no_std))] ++#![cfg_attr(not(feature = "std"), feature(collections))] ++#![cfg_attr(not(feature = "std"), no_std)] + #![cfg_attr(feature = "nightly", feature(test))] + #![cfg_attr(feature = "nightly", feature(const_fn))] ++#![cfg_attr(feature = "nightly", feature(plugin))] ++#![cfg_attr(feature = "nightly", plugin(compiler_error))] ++//#![warn(missing_docs)] + +-#[cfg(feature = "core")] ++#[cfg(not(feature = "std"))] + extern crate collections; + #[cfg(feature = "regexp")] + extern crate regex; + #[cfg(feature = "regexp_macros")] + #[macro_use] extern crate lazy_static; ++extern crate memchr; + #[cfg(feature = "nightly")] + extern crate test; + +-#[cfg(feature = "core")] ++#[cfg(not(feature = "nightly"))] ++#[allow(unused_macros)] ++#[macro_export] ++macro_rules! compiler_error { ++ ($e:expr) => { ++ INVALID_NOM_SYNTAX_PLEASE_SEE_FAQ //https://github.com/Geal/nom/blob/master/doc/FAQ.md#using-nightly-to-get-better-error-messages ++ } ++} ++ ++#[cfg(not(feature = "std"))] + mod std { + #[macro_use] +- pub use core::{fmt, iter, option, ops, slice, mem}; ++ pub use core::{fmt, cmp, iter, option, result, ops, slice, str, mem, convert}; + pub use collections::{boxed, vec, string}; + pub mod prelude { + pub use core::prelude as v1; +@@ -110,8 +427,19 @@ mod std { + } + + pub use self::util::*; ++pub use self::traits::*; ++ ++#[cfg(feature = "verbose-errors")] ++pub use self::verbose_errors::*; ++ ++#[cfg(not(feature = "verbose-errors"))] ++pub use self::simple_errors::*; ++ + pub use self::internal::*; + pub use self::macros::*; ++pub use self::branch::*; ++pub use self::sequence::*; ++pub use self::multi::*; + pub use self::methods::*; + pub use self::bytes::*; + pub use self::bits::*; +@@ -119,33 +447,45 @@ pub use self::bits::*; + pub use self::nom::*; + pub use self::character::*; + ++pub use self::whitespace::*; ++ + #[cfg(feature = "regexp")] + pub use self::regexp::*; + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] + #[cfg(feature = "stream")] + pub use self::stream::*; + +-#[cfg(not(feature = "core"))] + pub use self::str::*; + + #[macro_use] mod util; +-mod internal; ++mod traits; ++ ++#[cfg(feature = "verbose-errors")] #[macro_use] pub mod verbose_errors; ++ ++#[cfg(not(feature = "verbose-errors"))] #[macro_use] pub mod simple_errors; ++ ++#[macro_use] mod internal; + #[macro_use] mod macros; +-#[macro_use] mod methods; ++#[macro_use] mod branch; ++#[macro_use] mod sequence; ++#[macro_use] mod multi; ++#[macro_use] pub mod methods; + #[macro_use] mod bytes; +-#[macro_use] mod bits; ++#[macro_use] pub mod bits; + + #[macro_use] mod nom; + #[macro_use] mod character; + ++#[macro_use] ++pub mod whitespace; ++ + #[cfg(feature = "regexp")] + #[macro_use] mod regexp; + + #[macro_use] +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] + #[cfg(feature = "stream")] + mod stream; + +-#[cfg(not(feature = "core"))] + mod str; +diff --git third_party/rust/nom/src/macros.rs third_party/rust/nom/src/macros.rs +index 3e346a94f522..2bbe4bca412d 100644 +--- third_party/rust/nom/src/macros.rs ++++ third_party/rust/nom/src/macros.rs +@@ -61,7 +61,8 @@ + //! take_while!($input, call!($f)); + //! ); + //! ); +-//! ++//! ``` ++#[allow(unused_variables)] + + /// Wraps a parser in a closure + #[macro_export] +@@ -93,52 +94,168 @@ macro_rules! closure ( + /// ``` + #[macro_export] + macro_rules! named ( ++ (#$($args:tt)*) => ( ++ named_attr!(#$($args)*); ++ ); + ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( i: $i ) -> $crate::IResult<$i,$o,u32> { + $submac!(i, $($args)*) + } + ); + ($name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { + $submac!(i, $($args)*) + } + ); + ($name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { + $submac!(i, $($args)*) + } + ); + ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name<'a>( i: &'a[u8] ) -> $crate::IResult<&'a [u8], $o, u32> { + $submac!(i, $($args)*) + } + ); + ($name:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], u32> { + $submac!(i, $($args)*) + } + ); + (pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { + $submac!(i, $($args)*) + } + ); + (pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { + $submac!(i, $($args)*) + } + ); + (pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { + $submac!(i, $($args)*) + } + ); + (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { + $submac!(i, $($args)*) + } + ); + (pub $name:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] ++ pub fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++); ++ ++/// Makes a function from a parser combination with arguments. ++#[macro_export] ++macro_rules! named_args { ++ (pub $func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { ++ pub fn $func_name(input: &[u8], $( $arg : $typ ),*) -> $crate::IResult<&[u8], $return_type> { ++ $submac!(input, $($args)*) ++ } ++ }; ++ (pub $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { ++ pub fn $func_name<'this_is_probably_unique_i_hope_please, 'a>(input: &'this_is_probably_unique_i_hope_please [u8], $( $arg : $typ ),*) -> $crate::IResult<&'this_is_probably_unique_i_hope_please [u8], $return_type> { ++ $submac!(input, $($args)*) ++ } ++ }; ++ ($func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { ++ fn $func_name(input: &[u8], $( $arg : $typ ),*) -> $crate::IResult<&[u8], $return_type> { ++ $submac!(input, $($args)*) ++ } ++ }; ++ ($func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { ++ fn $func_name<'this_is_probably_unique_i_hope_please, 'a>(input: &'this_is_probably_unique_i_hope_please [u8], $( $arg : $typ ),*) -> $crate::IResult<&'this_is_probably_unique_i_hope_please [u8], $return_type> { ++ $submac!(input, $($args)*) ++ } ++ }; ++} ++ ++/// Makes a function from a parser combination, with attributes ++/// ++/// The usage of this macro is almost identical to `named!`, except that ++/// you also pass attributes to be attached to the generated function. ++/// This is ideal for adding documentation to your parser. ++/// ++/// ```ignore ++/// // Create my_function as if you wrote it with the doc comment /// My Func ++/// named_attr!(#[doc = "My Func"], my_function( &[u8] ) -> &[u8], tag!("abcd")); ++/// // Also works for pub functions, and multiple lines ++/// named!(#[doc = "My Func\nRecognise abcd"], pub my_function, tag!("abcd")); ++/// // Multiple attributes can be passed if required ++/// named!(#[doc = "My Func"] #[inline(always)], pub my_function, tag!("abcd")); ++/// ``` ++#[macro_export] ++macro_rules! named_attr ( ++ ($(#[$attr:meta])*, $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ fn $name( i: $i ) -> $crate::IResult<$i,$o,u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ fn $name<'a>( i: &'a[u8] ) -> $crate::IResult<&'a [u8], $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, $name:ident, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ pub fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ pub fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ pub fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* ++ pub fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($(#[$attr:meta])*, pub $name:ident, $submac:ident!( $($args:tt)* )) => ( ++ $(#[$attr])* + pub fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], u32> { + $submac!(i, $($args)*) + } +@@ -154,7 +271,7 @@ macro_rules! named ( + /// fn take_wrapper(input: &[u8], i: u8) -> IResult<&[u8],&[u8]> { take!(input, i * 10) } + /// + /// // will make a parser taking 20 bytes +-/// named!(parser, apply!(take_wrapper, 2)); ++/// named!(parser, call!(take_wrapper, 2)); + /// # } + /// ``` + #[macro_export] +@@ -185,7 +302,7 @@ macro_rules! apply ( + /// This parser will do an early return instead of sending + /// its result to the parent parser. + /// +-/// If another `error!` combinator is present in the parent ++/// If another `return_error!` combinator is present in the parent + /// chain, the error will be wrapped and another early + /// return will be made. + /// +@@ -200,16 +317,17 @@ macro_rules! apply ( + /// # #[macro_use] extern crate nom; + /// # use std::collections; + /// # use nom::IResult::Error; ++/// # #[cfg(feature = "verbose-errors")] + /// # use nom::Err::{Position,NodePosition}; + /// # use nom::ErrorKind; + /// # fn main() { + /// named!(err_test, alt!( + /// tag!("abcd") | +-/// preceded!(tag!("efgh"), error!(ErrorKind::Custom(42), +-/// chain!( +-/// tag!("ijkl") ~ +-/// res: error!(ErrorKind::Custom(128), tag!("mnop")) , +-/// || { res } ++/// preceded!(tag!("efgh"), return_error!(ErrorKind::Custom(42), ++/// do_parse!( ++/// tag!("ijkl") >> ++/// res: return_error!(ErrorKind::Custom(128), tag!("mnop")) >> ++/// (res) + /// ) + /// ) + /// ) +@@ -223,131 +341,73 @@ macro_rules! apply ( + /// let res_a = err_test(a); + /// let res_b = err_test(b); + /// let res_c = err_test(c); +-/// assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), blah, Box::new(Position(ErrorKind::Tag, blah))))); +-/// assert_eq!(res_b, Error(NodePosition(ErrorKind::Custom(42), &b"ijklblah"[..], +-/// Box::new(NodePosition(ErrorKind::Custom(128), blah, Box::new(Position(ErrorKind::Tag, blah)))))) ++/// assert_eq!(res_a, Error(error_node_position!(ErrorKind::Custom(42), blah, error_position!(ErrorKind::Tag, blah)))); ++/// assert_eq!(res_b, Error(error_node_position!(ErrorKind::Custom(42), &b"ijklblah"[..], ++/// error_node_position!(ErrorKind::Custom(128), blah, error_position!(ErrorKind::Tag, blah)))) + /// ); + /// # } + /// ``` + /// + #[macro_export] +-macro_rules! error ( ++macro_rules! return_error ( + ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => ( + { ++ let i_ = $i.clone(); + let cl = || { +- $submac!($i, $($args)*) ++ $submac!(i_, $($args)*) + }; + + match cl() { + $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), + $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), + $crate::IResult::Error(e) => { +- return $crate::IResult::Error($crate::Err::NodePosition($code, $i, Box::new(e))) ++ return $crate::IResult::Error(error_node_position!($code, $i, e)) + } + } + } + ); + ($i:expr, $code:expr, $f:expr) => ( +- error!($i, $code, call!($f)); ++ return_error!($i, $code, call!($f)); + ); + ); + + /// Add an error if the child parser fails + /// + /// While error! does an early return and avoids backtracking, +-/// add_error! backtracks normally. It just provides more context ++/// add_return_error! backtracks normally. It just provides more context + /// for an error + /// + /// ``` + /// # #[macro_use] extern crate nom; + /// # use std::collections; + /// # use nom::IResult::Error; ++/// # #[cfg(feature = "verbose-errors")] + /// # use nom::Err::{Position,NodePosition}; + /// # use nom::ErrorKind; + /// # fn main() { +-/// named!(err_test, add_error!(ErrorKind::Custom(42), tag!("abcd"))); ++/// named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd"))); + /// + /// let a = &b"efghblah"[..]; + /// let res_a = err_test(a); +-/// assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), a, Box::new(Position(ErrorKind::Tag, a))))); ++/// assert_eq!(res_a, Error(error_node_position!(ErrorKind::Custom(42), a, error_position!(ErrorKind::Tag, a)))); + /// # } + /// ``` + /// + #[macro_export] +-macro_rules! add_error ( ++macro_rules! add_return_error ( + ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => ( + { + match $submac!($i, $($args)*) { + $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), + $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), + $crate::IResult::Error(e) => { +- $crate::IResult::Error($crate::Err::NodePosition($code, $i, Box::new(e))) ++ $crate::IResult::Error(error_node_position!($code, $i, e)) + } + } + } + ); + ($i:expr, $code:expr, $f:expr) => ( +- add_error!($i, $code, call!($f)); +- ); +-); +- +- +-/// translate parser result from IResult to IResult with a custom type +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use std::collections; +-/// # use nom::IResult::Error; +-/// # use nom::Err::{Position,NodePosition}; +-/// # use nom::ErrorKind; +-/// # fn main() { +-/// // will add a Custom(42) error to the error chain +-/// named!(err_test, add_error!(ErrorKind::Custom(42), tag!("abcd"))); +-/// // Convert to IREsult<&[u8], &[u8], &str> +-/// named!(parser<&[u8], &[u8], &str>, add_error!(ErrorKind::Custom("custom error message"), fix_error!(&str, err_test))); +-/// +-/// let a = &b"efghblah"[..]; +-/// let res_a = parser(a); +-/// assert_eq!(res_a, Error(NodePosition( ErrorKind::Custom("custom error message"), a, Box::new(Position(ErrorKind::Fix, a))))); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! fix_error ( +- ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), +- $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), +- $crate::IResult::Error(e) => { +- let err = match e { +- $crate::Err::Code($crate::ErrorKind::Custom(_)) | +- $crate::Err::Node($crate::ErrorKind::Custom(_), _) => { +- let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; +- $crate::Err::Code(e) +- }, +- $crate::Err::Position($crate::ErrorKind::Custom(_), p) | +- $crate::Err::NodePosition($crate::ErrorKind::Custom(_), p, _) => { +- let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; +- $crate::Err::Position(e, p) +- }, +- $crate::Err::Code(_) | +- $crate::Err::Node(_, _) => { +- let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; +- $crate::Err::Code(e) +- }, +- $crate::Err::Position(_, p) | +- $crate::Err::NodePosition(_, p, _) => { +- let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; +- $crate::Err::Position(e, p) +- }, +- }; +- $crate::IResult::Error(err) +- } +- } +- } +- ); +- ($i:expr, $t:ty, $f:expr) => ( +- fix_error!($i, $t, call!($f)); ++ add_return_error!($i, $code, call!($f)); + ); + ); + +@@ -358,6 +418,7 @@ macro_rules! fix_error ( + /// # #[macro_use] extern crate nom; + /// # use std::collections; + /// # use nom::IResult::Error; ++/// # #[cfg(feature = "verbose-errors")] + /// # use nom::Err::{Position,NodePosition}; + /// # use nom::ErrorKind; + /// # fn main() { +@@ -365,7 +426,7 @@ macro_rules! fix_error ( + /// + /// let a = &b"abcd"[..]; + /// let res_a = take_5(a); +-/// assert_eq!(res_a, Error(Position(ErrorKind::Complete, a))); ++/// assert_eq!(res_a, Error(error_position!(ErrorKind::Complete, a))); + /// # } + /// ``` + /// +@@ -373,11 +434,12 @@ macro_rules! fix_error ( + macro_rules! complete ( + ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- match $submac!($i, $($args)*) { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { + $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), + $crate::IResult::Error(e) => $crate::IResult::Error(e), + $crate::IResult::Incomplete(_) => { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Complete, $i)) ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Complete, $i)) + }, + } + } +@@ -389,11 +451,12 @@ macro_rules! complete ( + + /// A bit like `std::try!`, this macro will return the remaining input and parsed value if the child parser returned `Done`, + /// and will do an early return for `Error` and `Incomplete` +-/// this can provide more flexibility than `chain!` if needed ++/// this can provide more flexibility than `do_parse!` if needed + /// + /// ``` + /// # #[macro_use] extern crate nom; + /// # use nom::IResult::{self, Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] + /// # use nom::Err::Position; + /// # use nom::{be_u8,ErrorKind}; + /// +@@ -411,7 +474,7 @@ macro_rules! complete ( + /// let arr2 = [0xFE, 2, 3, 4, 5]; + /// // size is overflowing + /// let r1 = take_add(&arr2[..], 42); +-/// assert_eq!(r1, Error(Position(ErrorKind::ExprOpt,&[2,3,4,5][..]))); ++/// assert_eq!(r1, Error(error_position!(ErrorKind::ExprOpt,&[2,3,4,5][..]))); + /// # } + /// ``` + #[macro_export] +@@ -428,153 +491,159 @@ macro_rules! try_parse ( + ); + ); + +-/// `flat_map!(R -> IResult, S -> IResult) => R -> IResult` +-/// +-/// combines a parser R -> IResult and +-/// a parser S -> IResult to return another +-/// parser R -> IResult ++/// `map!(I -> IResult, O -> P) => I -> IResult` ++/// maps a function on the result of a parser + #[macro_export] +-macro_rules! flat_map( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++macro_rules! map( ++ // Internal parser, do not use directly ++ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( + { ++ pub fn _unify R>(f: F, t: T) -> R { ++ f(t) ++ } + match $submac!($i, $($args)*) { + $crate::IResult::Error(e) => $crate::IResult::Error(e), + $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), + $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), +- $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { +- $crate::IResult::Error(e) => { +- let err = match e { +- $crate::Err::Code(k) | $crate::Err::Node(k, _) | $crate::Err::Position(k, _) | $crate::Err::NodePosition(k, _, _) => { +- $crate::Err::Position(k, $i) +- } +- }; +- $crate::IResult::Error(err) +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(ref i2)) => $crate::IResult::Incomplete($crate::Needed::Size(*i2)), +- $crate::IResult::Done(_, o2) => $crate::IResult::Done(i, o2) +- } ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, _unify($g, o)) + } + } + ); + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- flat_map!($i, $submac!($($args)*), call!($g)); +- ); +- ($i:expr, $f:expr, $g:expr) => ( +- flat_map!($i, call!($f), call!($g)); +- ); +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- flat_map!($i, call!($f), $submac!($($args)*)); +- ); +-); +- +-/// `map!(I -> IResult, O -> P) => I -> IResult` +-/// maps a function on the result of a parser +-#[macro_export] +-macro_rules! map( +- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- map_impl!($i, $submac!($($args)*), call!($g)); +- ); +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( +- map_impl!($i, $submac!($($args)*), $submac2!($($args2)*)); ++ map!(__impl $i, $submac!($($args)*), $g); + ); + ($i:expr, $f:expr, $g:expr) => ( +- map_impl!($i, call!($f), call!($g)); +- ); +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- map_impl!($i, call!($f), $submac!($($args)*)); ++ map!(__impl $i, call!($f), $g); + ); + ); + +-/// Internal parser, do not use directly +-#[doc(hidden)] ++/// `map_res!(I -> IResult, O -> Result

) => I -> IResult` ++/// maps a function returning a Result on the output of a parser + #[macro_export] +-macro_rules! map_impl( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++macro_rules! map_res ( ++ // Internal parser, do not use directly ++ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( + { +- match $submac!($i, $($args)*) { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { + $crate::IResult::Error(e) => $crate::IResult::Error(e), + $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), + $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), +- $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $submac2!(o, $($args2)*)) ++ $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { ++ Ok(output) => $crate::IResult::Done(i, output), ++ Err(_) => $crate::IResult::Error(error_position!($crate::ErrorKind::MapRes, $i)) ++ } + } + } + ); +-); +- +-/// `map_res!(I -> IResult, O -> Result

) => I -> IResult` +-/// maps a function returning a Result on the output of a parser +-#[macro_export] +-macro_rules! map_res ( + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- map_res_impl!($i, $submac!($($args)*), call!($g)); ++ map_res!(__impl $i, $submac!($($args)*), call!($g)); + ); + ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( +- map_res_impl!($i, $submac!($($args)*), $submac2!($($args2)*)); ++ map_res!(__impl $i, $submac!($($args)*), $submac2!($($args2)*)); + ); + ($i:expr, $f:expr, $g:expr) => ( +- map_res_impl!($i, call!($f), call!($g)); ++ map_res!(__impl $i, call!($f), call!($g)); + ); + ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- map_res_impl!($i, call!($f), $submac!($($args)*)); ++ map_res!(__impl $i, call!($f), $submac!($($args)*)); + ); + ); + +-/// Internal parser, do not use directly +-#[doc(hidden)] ++/// `map_opt!(I -> IResult, O -> Option

) => I -> IResult` ++/// maps a function returning an Option on the output of a parser + #[macro_export] +-macro_rules! map_res_impl ( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++macro_rules! map_opt ( ++ // Internal parser, do not use directly ++ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( + { +- match $submac!($i, $($args)*) { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { + $crate::IResult::Error(e) => $crate::IResult::Error(e), + $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), + $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), + $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { +- Ok(output) => $crate::IResult::Done(i, output), +- Err(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::MapRes, $i)) ++ ::std::option::Option::Some(output) => $crate::IResult::Done(i, output), ++ ::std::option::Option::None => $crate::IResult::Error(error_position!($crate::ErrorKind::MapOpt, $i)) + } + } + } + ); +-); +- +- +-/// `map_opt!(I -> IResult, O -> Option

) => I -> IResult` +-/// maps a function returning an Option on the output of a parser +-#[macro_export] +-macro_rules! map_opt ( + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- map_opt_impl!($i, $submac!($($args)*), call!($g)); ++ map_opt!(__impl $i, $submac!($($args)*), call!($g)); + ); + ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( +- map_opt_impl!($i, $submac!($($args)*), $submac2!($($args2)*)); ++ map_opt!(__impl $i, $submac!($($args)*), $submac2!($($args2)*)); + ); + ($i:expr, $f:expr, $g:expr) => ( +- map_opt_impl!($i, call!($f), call!($g)); ++ map_opt!(__impl $i, call!($f), call!($g)); + ); + ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- map_opt_impl!($i, call!($f), $submac!($($args)*)); ++ map_opt!(__impl $i, call!($f), $submac!($($args)*)); + ); + ); + +-/// Internal parser, do not use directly +-#[doc(hidden)] ++/// `parse_to!(O) => I -> IResult` ++/// uses the `parse` method from `std::str::FromStr` to convert the current ++/// input to the specified type ++/// ++/// this will completely consume the input + #[macro_export] +-macro_rules! map_opt_impl ( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++macro_rules! parse_to ( ++ ($i:expr, $t:ty ) => ( + { +- match $submac!($i, $($args)*) { ++ use $crate::ParseTo; ++ use $crate::Slice; ++ use $crate::InputLength; ++ match ($i).parse_to() { ++ ::std::option::Option::Some(output) => $crate::IResult::Done($i.slice(..$i.input_len()), output), ++ ::std::option::Option::None => $crate::IResult::Error(error_position!($crate::ErrorKind::MapOpt, $i)) ++ } ++ } ++ ); ++); ++ ++/// `verify!(I -> IResult, O -> bool) => I -> IResult` ++/// returns the result of the child parser if it satisfies a verification function ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # use nom::be_u32; ++/// # fn main() { ++/// named!(check, verify!(be_u32, |val:u32| val >= 0 && val < 3)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! verify ( ++ // Internal parser, do not use directly ++ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { + $crate::IResult::Error(e) => $crate::IResult::Error(e), + $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), + $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), +- $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { +- ::std::option::Option::Some(output) => $crate::IResult::Done(i, output), +- ::std::option::Option::None => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::MapOpt, $i)) ++ $crate::IResult::Done(i, o) => if $submac2!(o, $($args2)*) { ++ $crate::IResult::Done(i, o) ++ } else { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Verify, $i)) + } + } + } + ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ verify!(__impl $i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ verify!(__impl $i, $submac!($($args)*), $submac2!($($args2)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ verify!(__impl $i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ verify!(__impl $i, call!($f), $submac!($($args)*)); ++ ); + ); + + /// `value!(T, R -> IResult ) => R -> IResult` +@@ -603,7 +672,8 @@ macro_rules! value ( + { + match $submac!($i, $($args)*) { + $crate::IResult::Done(i,_) => { +- $crate::IResult::Done(i, $res) ++ let res: $crate::IResult<_,_> = $crate::IResult::Done(i, $res); ++ res + }, + $crate::IResult::Error(e) => $crate::IResult::Error(e), + $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +@@ -614,7 +684,10 @@ macro_rules! value ( + value!($i, $res, call!($f)) + ); + ($i:expr, $res:expr) => ( +- $crate::IResult::Done($i, $res) ++ { ++ let res: $crate::IResult<_,_> = $crate::IResult::Done($i, $res); ++ res ++ } + ); + ); + +@@ -628,7 +701,7 @@ macro_rules! expr_res ( + { + match $e { + Ok(output) => $crate::IResult::Done($i, output), +- Err(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ExprRes, $i)) ++ Err(_) => $crate::IResult::Error(error_position!($crate::ErrorKind::ExprRes, $i)) + } + } + ); +@@ -642,15 +715,16 @@ macro_rules! expr_res ( + /// ``` + /// # #[macro_use] extern crate nom; + /// # use nom::IResult::{self, Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] + /// # use nom::Err::Position; + /// # use nom::{be_u8,ErrorKind}; + /// + /// fn take_add(input:&[u8], size: u8) -> IResult<&[u8],&[u8]> { +-/// chain!(input, +-/// sz: be_u8 ~ +-/// length: expr_opt!(size.checked_add(sz)) ~ // checking for integer overflow (returns an Option) +-/// data: take!(length) , +-/// ||{ data } ++/// do_parse!(input, ++/// sz: be_u8 >> ++/// length: expr_opt!(size.checked_add(sz)) >> // checking for integer overflow (returns an Option) ++/// data: take!(length) >> ++/// (data) + /// ) + /// } + /// # fn main() { +@@ -661,7 +735,7 @@ macro_rules! expr_res ( + /// let arr2 = [0xFE, 2, 3, 4, 5]; + /// // size is overflowing + /// let r1 = take_add(&arr2[..], 42); +-/// assert_eq!(r1, Error(Position(ErrorKind::ExprOpt,&[2,3,4,5][..]))); ++/// assert_eq!(r1, Error(error_position!(ErrorKind::ExprOpt,&[2,3,4,5][..]))); + /// # } + /// ``` + #[macro_export] +@@ -670,2011 +744,423 @@ macro_rules! expr_opt ( + { + match $e { + ::std::option::Option::Some(output) => $crate::IResult::Done($i, output), +- ::std::option::Option::None => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ExprOpt, $i)) ++ ::std::option::Option::None => $crate::IResult::Error(error_position!($crate::ErrorKind::ExprOpt, $i)) + } + } + ); + ); + +-/// `chain!(I->IResult ~ I->IResult ~ ... I->IResult , || { return O } ) => I -> IResult` +-/// chains parsers and assemble the results through a closure +-/// +-/// The input type `I` must implement `nom::InputLength`. ++/// `opt!(I -> IResult) => I -> IResult>` ++/// make the underlying parser optional + /// +-/// This combinator will count how much data is consumed by every child parser and take it into account if +-/// there is not enough data ++/// returns an Option of the returned type. This parser returns `Some(result)` if the child parser ++/// succeeds,`None` if it fails, and `Incomplete` if it did not have enough data to decide + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{self, Done, Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; +-/// #[derive(PartialEq,Eq,Debug)] +-/// struct B { +-/// a: u8, +-/// b: Option +-/// } +-/// +-/// named!(y, tag!("efgh")); +-/// +-/// fn ret_int(i:&[u8]) -> IResult<&[u8], u8> { Done(i, 1) } +-/// named!(ret_y<&[u8], u8>, map!(y, |_| 1)); // return 1 if the "efgh" tag is found +-/// +-/// named!(z<&[u8], B>, +-/// chain!( +-/// tag!("abcd") ~ // the '~' character is used as separator +-/// aa: ret_int ~ // the result of that parser will be used in the closure +-/// tag!("abcd")? ~ // this parser is optional +-/// bb: ret_y? , // the result of that parser is an option +-/// // the last parser in the chain is followed by a ',' +-/// ||{B{a: aa, b: bb}} +-/// ) +-/// ); +-/// ++/// # use nom::IResult::Done; + /// # fn main() { +-/// // the first "abcd" tag is not present, we have an error +-/// let r1 = z(&b"efgh"[..]); +-/// assert_eq!(r1, Error(Position(ErrorKind::Tag,&b"efgh"[..]))); +-/// +-/// // everything is present, everything is parsed +-/// let r2 = z(&b"abcdabcdefgh"[..]); +-/// assert_eq!(r2, Done(&b""[..], B{a: 1, b: Some(1)})); +-/// +-/// // the second "abcd" tag is optional +-/// let r3 = z(&b"abcdefgh"[..]); +-/// assert_eq!(r3, Done(&b""[..], B{a: 1, b: Some(1)})); ++/// named!( o<&[u8], Option<&[u8]> >, opt!( tag!( "abcd" ) ) ); + /// +-/// // the result of ret_y is optional, as seen in the B structure +-/// let r4 = z(&b"abcdabcdwxyz"[..]); +-/// assert_eq!(r4, Done(&b"wxyz"[..], B{a: 1, b: None})); +-/// # } ++/// let a = b"abcdef"; ++/// let b = b"bcdefg"; ++/// assert_eq!(o(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); ++/// assert_eq!(o(&b[..]), Done(&b"bcdefg"[..], None)); ++/// # } + /// ``` + #[macro_export] +-macro_rules! chain ( +- ($i:expr, $($rest:tt)*) => ( +- { +- chaining_parser!($i, 0usize, $($rest)*) +- } +- ); +-); +- +-/// Internal parser, do not use directly +-#[doc(hidden)] +-#[macro_export] +-macro_rules! chaining_parser ( +- ($i:expr, $consumed:expr, $e:ident ~ $($rest:tt)*) => ( +- chaining_parser!($i, $consumed, call!($e) ~ $($rest)*); +- ); +- ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ~ $($rest:tt)*) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,_) => { +- chaining_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), $($rest)*) +- } +- } +- } +-); +- +- ($i:expr, $consumed:expr, $e:ident ? ~ $($rest:tt)*) => ( +- chaining_parser!($i, $consumed, call!($e) ? ~ $($rest)*); +- ); +- +- ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ? ~ $($rest:tt)*) => ( ++macro_rules! opt( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- let res = $submac!($i, $($args)*); +- if let $crate::IResult::Incomplete(inc) = res { +- match inc { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- } +- } else { +- let input = if let $crate::IResult::Done(i,_) = res { +- i +- } else { +- $i +- }; +- chaining_parser!(input, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input)), $($rest)*) ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ _ => { ++ let res: $crate::IResult<_,_> = $crate::IResult::Done($i, ::std::option::Option::None); ++ res ++ }, + } + } + ); +- +- ($i:expr, $consumed:expr, $field:ident : $e:ident ~ $($rest:tt)*) => ( +- chaining_parser!($i, $consumed, $field: call!($e) ~ $($rest)*); ++ ($i:expr, $f:expr) => ( ++ opt!($i, call!($f)); + ); ++); + +- ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ~ $($rest:tt)*) => ( ++/// `opt_res!(I -> IResult) => I -> IResult>` ++/// make the underlying parser optional ++/// ++/// returns a Result, with Err containing the parsing error ++/// ++/// ```ignore ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!( o<&[u8], Result<&[u8], nom::Err<&[u8]> > >, opt_res!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdef"; ++/// let b = b"bcdefg"; ++/// assert_eq!(o(&a[..]), Done(&b"ef"[..], Ok(&b"abcd"[..]))); ++/// assert_eq!(o(&b[..]), Done(&b"bcdefg"[..], Err(error_position!(ErrorKind::Tag, &b[..])))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! opt_res ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- let $field = o; +- chaining_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), $($rest)*) +- } ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::result::Result::Ok(o)), ++ $crate::IResult::Error(e) => $crate::IResult::Done($i, ::std::result::Result::Err(e)), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) + } + } + ); +- +- ($i:expr, $consumed:expr, mut $field:ident : $e:ident ~ $($rest:tt)*) => ( +- chaining_parser!($i, $consumed, mut $field: call!($e) ~ $($rest)*); ++ ($i:expr, $f:expr) => ( ++ opt_res!($i, call!($f)); + ); ++); + +- ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) ~ $($rest:tt)*) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- let mut $field = o; +- chaining_parser!(i, $consumed + $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i), $($rest)*) +- } +- } +- } +- ); +- +- ($i:expr, $consumed:expr, $field:ident : $e:ident ? ~ $($rest:tt)*) => ( +- chaining_parser!($i, $consumed, $field : call!($e) ? ~ $($rest)*); +- ); +- +- ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ? ~ $($rest:tt)*) => ( +- { +- let res = $submac!($i, $($args)*); +- if let $crate::IResult::Incomplete(inc) = res { +- match inc { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- } +- } else { +- let ($field,input) = if let $crate::IResult::Done(i,o) = res { +- (::std::option::Option::Some(o),i) +- } else { +- (::std::option::Option::None,$i) +- }; +- chaining_parser!(input, $consumed + $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input), $($rest)*) +- } +- } +- ); +- +- ($i:expr, $consumed:expr, mut $field:ident : $e:ident ? ~ $($rest:tt)*) => ( +- chaining_parser!($i, $consumed, mut $field : call!($e) ? ~ $($rest)*); +- ); +- +- ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) ? ~ $($rest:tt)*) => ( +- { +- let res = $submac!($i, $($args)*); +- if let $crate::IResult::Incomplete(inc) = res { +- match inc { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- } +- } else { +- let (mut $field,input) = if let $crate::IResult::Done(i,o) = res { +- (::std::option::Option::Some(o),i) +- } else { +- (::std::option::Option::None,$i) +- }; +- chaining_parser!(input, $consumed + $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input), $($rest)*) +- } +- } +- ); +- +- // ending the chain +- ($i:expr, $consumed:expr, $e:ident, $assemble:expr) => ( +- chaining_parser!($i, $consumed, call!($e), $assemble); +- ); +- +- ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ), $assemble:expr) => ( +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,_) => { +- $crate::IResult::Done(i, $assemble()) +- } +- } +- ); +- +- ($i:expr, $consumed:expr, $e:ident ?, $assemble:expr) => ( +- chaining_parser!($i, $consumed, call!($e) ?, $assemble); +- ); +- +- ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ?, $assemble:expr) => ({ +- let res = $submac!($i, $($args)*); +- if let $crate::IResult::Incomplete(inc) = res { +- match inc { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- } +- } else { +- let input = if let $crate::IResult::Done(i,_) = res { +- i +- } else { +- $i +- }; +- $crate::IResult::Done(input, $assemble()) +- } +- }); +- +- ($i:expr, $consumed:expr, $field:ident : $e:ident, $assemble:expr) => ( +- chaining_parser!($i, $consumed, $field: call!($e), $assemble); +- ); +- +- ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ), $assemble:expr) => ( +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- let $field = o; +- $crate::IResult::Done(i, $assemble()) +- } +- } +- ); +- +- ($i:expr, $consumed:expr, mut $field:ident : $e:ident, $assemble:expr) => ( +- chaining_parser!($i, $consumed, mut $field: call!($e), $assemble); +- ); +- +- ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ), $assemble:expr) => ( +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- let mut $field = o; +- $crate::IResult::Done(i, $assemble()) +- } +- } +- ); +- +- ($i:expr, $consumed:expr, $field:ident : $e:ident ? , $assemble:expr) => ( +- chaining_parser!($i, $consumed, $field : call!($e) ? , $assemble); +- ); +- +- ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ? , $assemble:expr) => ({ +- let res = $submac!($i, $($args)*); +- if let $crate::IResult::Incomplete(inc) = res { +- match inc { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- } +- } else { +- let ($field,input) = if let $crate::IResult::Done(i,o) = res { +- (::std::option::Option::Some(o), i) +- } else { +- (::std::option::Option::None, $i) +- }; +- $crate::IResult::Done(input, $assemble()) +- } +- }); +- +- ($i:expr, $consumed:expr, mut $field:ident : $e:ident ? , $assemble:expr) => ( +- chaining_parser!($i, $consumed, $field : call!($e) ? , $assemble); +- ); +- +- ($i:expr, $consumed:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) ? , $assemble:expr) => ({ +- let res = $submac!($i, $($args)*); +- if let $crate::IResult::Incomplete(inc) = res { +- match inc { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(i) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- } +- } else { +- let (mut $field,input) = if let $crate::IResult::Done(i,o) = res { +- (::std::option::Option::Some(o), i) +- } else { +- (::std::option::Option::None, $i) +- }; +- $crate::IResult::Done(input, $assemble()) +- } +- }); +- +- ($i:expr, $consumed:expr, $assemble:expr) => ( +- $crate::IResult::Done($i, $assemble()) +- ) +-); +- +- +-/// `tuple!(I->IResult, I->IResult, ... I->IResult) => I -> IResult` +-/// chains parsers and assemble the sub results in a tuple. +-/// +-/// The input type `I` must implement `nom::InputLength`. +-/// +-/// This combinator will count how much data is consumed by every child parser and take it into account if +-/// there is not enough data +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{self, Done, Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; +-/// # use nom::be_u16; +-/// // the return type depends of the children parsers +-/// named!(parser<&[u8], (u16, &[u8], &[u8]) >, +-/// tuple!( +-/// be_u16 , +-/// take!(3), +-/// tag!("fg") +-/// ) +-/// ); +-/// +-/// # fn main() { +-/// assert_eq!( +-/// parser(&b"abcdefgh"[..]), +-/// Done( +-/// &b"h"[..], +-/// (0x6162u16, &b"cde"[..], &b"fg"[..]) +-/// ) +-/// ); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! tuple ( +- ($i:expr, $($rest:tt)*) => ( +- { +- tuple_parser!($i, 0usize, (), $($rest)*) +- } +- ); +-); +- +-/// Internal parser, do not use directly +-#[doc(hidden)] +-#[macro_export] +-macro_rules! tuple_parser ( +- ($i:expr, $consumed:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => ( +- tuple_parser!($i, $consumed, ($($parsed),*), call!($e), $($rest)*); +- ); +- ($i:expr, $consumed:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- tuple_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), (o), $($rest)*) +- } +- } +- } +- ); +- ($i:expr, $consumed:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- tuple_parser!(i, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), ($($parsed)* , o), $($rest)*) +- } +- } +- } +- ); +- ($i:expr, $consumed:expr, ($($parsed:tt),*), $e:ident) => ( +- tuple_parser!($i, $consumed, ($($parsed),*), call!($e)); +- ); +- ($i:expr, $consumed:expr, (), $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- $crate::IResult::Done(i, (o)) +- } +- } +- } +- ); +- ($i:expr, $consumed:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), +- $crate::IResult::Done(i,o) => { +- $crate::IResult::Done(i, ($($parsed),* , o)) +- } +- } +- } +- ); +- ($i:expr, $consumed:expr, ($($parsed:expr),*)) => ( +- { +- $crate::IResult::Done($i, ($($parsed),*)) +- } +- ); +-); +-/// `alt!(I -> IResult | I -> IResult | ... | I -> IResult ) => I -> IResult` +-/// try a list of parsers, return the result of the first successful one +-/// +-/// If one of the parser returns Incomplete, alt will return Incomplete, to retry +-/// once you get more input. Note that it is better for performance to know the +-/// minimum size of data you need before you get into alt. +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # fn main() { +-/// named!( test, alt!( tag!( "abcd" ) | tag!( "efgh" ) ) ); +-/// let r1 = test(b"abcdefgh"); +-/// assert_eq!(r1, Done(&b"efgh"[..], &b"abcd"[..])); +-/// let r2 = test(&b"efghijkl"[..]); +-/// assert_eq!(r2, Done(&b"ijkl"[..], &b"efgh"[..])); +-/// # } +-/// ``` +-/// +-/// There is another syntax for alt allowing a block to manipulate the result: +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # fn main() { +-/// #[derive(Debug,PartialEq,Eq)] +-/// enum Tagged { +-/// Abcd, +-/// Efgh, +-/// Took(usize) +-/// } +-/// named!(test, alt!( +-/// tag!("abcd") => { |_| Tagged::Abcd } +-/// | tag!("efgh") => { |_| Tagged::Efgh } +-/// | take!(5) => { |res: &[u8]| Tagged::Took(res.len()) } // the closure takes the result as argument if the parser is successful +-/// )); +-/// let r1 = test(b"abcdefgh"); +-/// assert_eq!(r1, Done(&b"efgh"[..], Tagged::Abcd)); +-/// let r2 = test(&b"efghijkl"[..]); +-/// assert_eq!(r2, Done(&b"ijkl"[..], Tagged::Efgh)); +-/// let r3 = test(&b"mnopqrst"[..]); +-/// assert_eq!(r3, Done(&b"rst"[..], Tagged::Took(5))); +-/// # } +-/// ``` +-/// +-/// **BE CAREFUL** there is a case where the behaviour of `alt!` can be confusing: +-/// +-/// when the alternatives have different lengths, like this case: +-/// +-/// ```ignore +-/// named!( test, alt!( tag!( "abcd" ) | tag!( "ef" ) | tag!( "ghi" ) | tag!( "kl" ) ) ); +-/// ``` +-/// +-/// With this parser, if you pass `"abcd"` as input, the first alternative parses it correctly, +-/// but if you pass `"efg"`, the first alternative will return `Incomplete`, since it needs an input +-/// of 4 bytes. This behaviour of `alt!` is expected: if you get a partial input that isn't matched +-/// by the first alternative, but would match if the input was complete, you want `alt!` to indicate +-/// that it cannot decide with limited information. +-/// +-/// There are two ways to fix this behaviour. The first one consists in ordering the alternatives +-/// by size, like this: +-/// +-/// ```ignore +-/// named!( test, alt!( tag!( "ef" ) | tag!( "kl") | tag!( "ghi" ) | tag!( "abcd" ) ) ); +-/// ``` +-/// +-/// With this solution, the largest alternative will be tested last. +-/// +-/// The other solution uses the `complete!` combinator, which transforms an `Incomplete` in an +-/// `Error`. If one of the alternatives returns `Incomplete` but is wrapped by `complete!`, +-/// `alt!` will try the next alternative. This is useful when you know that +-/// you will not get partial input: +-/// +-/// ```ignore +-/// named!( test, +-/// alt!( +-/// complete!( tag!( "abcd" ) ) | +-/// complete!( tag!( "ef" ) ) | +-/// complete!( tag!( "ghi" ) ) | +-/// complete!( tag!( "kl" ) ) +-/// ) +-/// ); +-/// ``` +-/// +-/// If you want the `complete!` combinator to be applied to all rules then use the convenience +-/// `alt_complete!` macro (see below). +-/// +-/// This behaviour of `alt!` can get especially confusing if multiple alternatives have different +-/// sizes but a common prefix, like this: +-/// +-/// ```ignore +-/// named!( test, alt!( tag!( "abcd" ) | tag!( "ab" ) | tag!( "ef" ) ) ); +-/// ``` +-/// +-/// in that case, if you order by size, passing `"abcd"` as input will always be matched by the +-/// smallest parser, so the solution using `complete!` is better suited. +-/// +-/// You can also nest multiple `alt!`, like this: +-/// +-/// ```ignore +-/// named!( test, +-/// alt!( +-/// preceded!( +-/// tag!("ab"), +-/// alt!( +-/// tag!( "cd" ) | +-/// eof +-/// ) +-/// ) +-/// | tag!( "ef" ) +-/// ) +-/// ); +-/// ``` +-/// +-/// `preceded!` will first parse `"ab"` then, if successful, try the alternatives "cd", +-/// or empty input (End Of File). If none of them work, `preceded!` will fail and +-/// "ef" will be tested. +-/// +-#[macro_export] +-macro_rules! alt ( +- ($i:expr, $($rest:tt)*) => ( +- { +- alt_parser!($i, $($rest)*) +- } +- ); +-); +- +-/// Internal parser, do not use directly +-#[doc(hidden)] +-#[macro_export] +-macro_rules! alt_parser ( +- ($i:expr, $e:ident | $($rest:tt)*) => ( +- alt_parser!($i, call!($e) | $($rest)*); +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( +- { +- let res = $subrule!($i, $($args)*); +- match res { +- $crate::IResult::Done(_,_) => res, +- $crate::IResult::Incomplete(_) => res, +- _ => alt_parser!($i, $($rest)*) +- } +- } +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( +- { +- match $subrule!( $i, $($args)* ) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), +- $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), +- $crate::IResult::Error(_) => { +- alt_parser!($i, $($rest)*) +- } +- } +- } +- ); +- +- ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => ( +- alt_parser!($i, call!($e) => { $gen } | $($rest)*); +- ); +- +- ($i:expr, $e:ident => { $gen:expr }) => ( +- alt_parser!($i, call!($e) => { $gen }); +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( +- { +- match $subrule!( $i, $($args)* ) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), +- $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), +- $crate::IResult::Error(_) => { +- alt_parser!($i) +- } +- } +- } +- ); +- +- ($i:expr, $e:ident) => ( +- alt_parser!($i, call!($e)); +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)*)) => ( +- { +- match $subrule!( $i, $($args)* ) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i,o), +- $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), +- $crate::IResult::Error(_) => { +- alt_parser!($i) +- } +- } +- } +- ); +- +- ($i:expr) => ( +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Alt,$i)) +- ); +-); +- +-/// This is a combination of the `alt!` and `complete!` combinators. Rather +-/// than returning `Incomplete` on partial input, `alt_complete!` will try the +-/// next alternative in the chain. You should use this only if you know you +-/// will not receive partial input for the rules you're trying to match (this +-/// is almost always the case for parsing programming languages). +-#[macro_export] +-macro_rules! alt_complete ( +- // Recursive rules (must include `complete!` around the head) +- +- ($i:expr, $e:ident | $($rest:tt)*) => ( +- alt_complete!($i, complete!(call!($e)) | $($rest)*); +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( +- { +- let res = complete!($i, $subrule!($($args)*)); +- match res { +- $crate::IResult::Done(_,_) => res, +- _ => alt_complete!($i, $($rest)*), +- } +- } +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( +- { +- match complete!($i, $subrule!($($args)*)) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), +- _ => alt_complete!($i, $($rest)*), +- } +- } +- ); +- +- ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => ( +- alt_complete!($i, complete!(call!($e)) => { $gen } | $($rest)*); +- ); +- +- // Tail (non-recursive) rules +- +- ($i:expr, $e:ident => { $gen:expr }) => ( +- alt_complete!($i, call!($e) => { $gen }); +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( +- alt_parser!($i, $subrule!($($args)*) => { $gen }) +- ); +- +- ($i:expr, $e:ident) => ( +- alt_complete!($i, call!($e)); +- ); +- +- ($i:expr, $subrule:ident!( $($args:tt)*)) => ( +- alt_parser!($i, $subrule!($($args)*)) +- ); +-); +- +-/// `switch!(I -> IResult, P => I -> IResult | ... | P => I -> IResult ) => I -> IResult` +-/// choose the next parser depending on the result of the first one, if successful, +-/// and returns the result of the second parser +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done,Error}; +-/// # use nom::Err::{Position, NodePosition}; +-/// # use nom::ErrorKind; +-/// # fn main() { +-/// named!(sw, +-/// switch!(take!(4), +-/// b"abcd" => tag!("XYZ") | +-/// b"efgh" => tag!("123") +-/// ) +-/// ); +-/// +-/// let a = b"abcdXYZ123"; +-/// let b = b"abcdef"; +-/// let c = b"efgh123"; +-/// let d = b"blah"; +-/// +-/// assert_eq!(sw(&a[..]), Done(&b"123"[..], &b"XYZ"[..])); +-/// assert_eq!(sw(&b[..]), Error(NodePosition(ErrorKind::Switch, &b"abcdef"[..], Box::new(Position(ErrorKind::Tag, &b"ef"[..]))))); +-/// assert_eq!(sw(&c[..]), Done(&b""[..], &b"123"[..])); +-/// assert_eq!(sw(&d[..]), Error(Position(ErrorKind::Switch, &b"blah"[..]))); +-/// # } +-/// ``` +-/// +-/// Due to limitations in Rust macros, it is not possible to have simple functions on the right hand +-/// side of pattern, like this: +-/// +-/// ```ignore +-/// named!(sw, +-/// switch!(take!(4), +-/// b"abcd" => tag!("XYZ") | +-/// b"efgh" => tag!("123") +-/// ) +-/// ); +-/// ``` +-/// +-/// If you want to pass your own functions instead, you can use the `call!` combinator as follows: +-/// +-/// ```ignore +-/// named!(xyz, tag!("XYZ")); +-/// named!(num, tag!("123")); +-/// named!(sw, +-/// switch!(take!(4), +-/// b"abcd" => call!(xyz) | +-/// b"efgh" => call!(num) +-/// ) +-/// ); +-/// ``` +-/// +-#[macro_export] +-macro_rules! switch ( +- ($i:expr, $submac:ident!( $($args:tt)*), $($rest:tt)*) => ( +- { +- switch_impl!($i, $submac!($($args)*), $($rest)*) +- } +- ); +- ($i:expr, $e:ident, $($rest:tt)*) => ( +- { +- switch_impl!($i, call!($e), $($rest)*) +- } +- ); +-); +- +-/// Internal parser, do not use directly +-#[doc(hidden)] +-#[macro_export] +-macro_rules! switch_impl ( +- ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error($crate::Err::NodePosition( +- $crate::ErrorKind::Switch, $i, ::std::boxed::Box::new(e) +- )), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i, o) => { +- match o { +- $($p => match $subrule!(i, $($args2)*) { +- $crate::IResult::Error(e) => $crate::IResult::Error($crate::Err::NodePosition( +- $crate::ErrorKind::Switch, $i, ::std::boxed::Box::new(e) +- )), +- a => a, +- }),*, +- _ => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Switch,$i)) +- } +- } +- } +- } +- ); +-); +-/// `opt!(I -> IResult) => I -> IResult>` +-/// make the underlying parser optional +-/// +-/// returns an Option of the returned type. This parser returns `Some(result)` if the child parser +-/// succeeds,`None` if it fails, and `Incomplete` if it did not have enough data to decide +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # fn main() { +-/// named!( o<&[u8], Option<&[u8]> >, opt!( tag!( "abcd" ) ) ); +-/// +-/// let a = b"abcdef"; +-/// let b = b"bcdefg"; +-/// assert_eq!(o(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); +-/// assert_eq!(o(&b[..]), Done(&b"bcdefg"[..], None)); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! opt( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), +- $crate::IResult::Error(_) => $crate::IResult::Done($i, ::std::option::Option::None), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } +- ); +- ($i:expr, $f:expr) => ( +- opt!($i, call!($f)); +- ); +-); +- +-/// `opt_res!(I -> IResult) => I -> IResult>` +-/// make the underlying parser optional +-/// +-/// returns a Result, with Err containing the parsing error +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; +-/// # fn main() { +-/// named!( o<&[u8], Result<&[u8], nom::Err<&[u8]> > >, opt_res!( tag!( "abcd" ) ) ); +-/// +-/// let a = b"abcdef"; +-/// let b = b"bcdefg"; +-/// assert_eq!(o(&a[..]), Done(&b"ef"[..], Ok(&b"abcd"[..]))); +-/// assert_eq!(o(&b[..]), Done(&b"bcdefg"[..], Err(Position(ErrorKind::Tag, &b[..])))); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! opt_res ( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i, Ok(o)), +- $crate::IResult::Error(e) => $crate::IResult::Done($i, Err(e)), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } +- ); +- ($i:expr, $f:expr) => ( +- opt_res!($i, call!($f)); +- ); +-); +- +-/// `cond_with_error!(bool, I -> IResult) => I -> IResult>` +-/// Conditional combinator +-/// +-/// Wraps another parser and calls it if the +-/// condition is met. This combinator returns +-/// an Option of the return type of the child +-/// parser. +-/// +-/// This is especially useful if a parser depends +-/// on the value return by a preceding parser in +-/// a `chain!`. +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # use nom::IResult; +-/// # fn main() { +-/// let b = true; +-/// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], +-/// cond!( b, tag!("abcd") )) +-/// ); +-/// +-/// let a = b"abcdef"; +-/// assert_eq!(f(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); +-/// +-/// let b2 = false; +-/// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], +-/// cond!( b2, tag!("abcd") )) +-/// ); +-/// assert_eq!(f2(&a[..]), Done(&b"abcdef"[..], None)); +-/// # } +-/// ``` +-/// +-#[macro_export] +-macro_rules! cond_with_error( +- ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- if $cond { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } else { +- $crate::IResult::Done($i, ::std::option::Option::None) +- } +- } +- ); +- ($i:expr, $cond:expr, $f:expr) => ( +- cond!($i, $cond, call!($f)); +- ); +-); +- +-/// `cond!(bool, I -> IResult) => I -> IResult>` +-/// Conditional combinator +-/// +-/// Wraps another parser and calls it if the +-/// condition is met. This combinator returns +-/// an Option of the return type of the child +-/// parser. +-/// +-/// This is especially useful if a parser depends +-/// on the value return by a preceding parser in +-/// a `chain!`. +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # use nom::IResult; +-/// # fn main() { +-/// let b = true; +-/// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], +-/// cond!( b, tag!("abcd") )) +-/// ); +-/// +-/// let a = b"abcdef"; +-/// assert_eq!(f(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); +-/// +-/// let b2 = false; +-/// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], +-/// cond!( b2, tag!("abcd") )) +-/// ); +-/// assert_eq!(f2(&a[..]), Done(&b"abcdef"[..], None)); +-/// # } +-/// ``` +-/// +-#[macro_export] +-macro_rules! cond( +- ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- if $cond { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), +- $crate::IResult::Error(_) => $crate::IResult::Done($i, ::std::option::Option::None), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } else { +- $crate::IResult::Done($i, ::std::option::Option::None) +- } +- } +- ); +- ($i:expr, $cond:expr, $f:expr) => ( +- cond!($i, $cond, call!($f)); +- ); +-); +- +-/// `cond_reduce!(bool, I -> IResult) => I -> IResult` +-/// Conditional combinator with error +-/// +-/// Wraps another parser and calls it if the +-/// condition is met. This combinator returns +-/// an error if the condition is false +-/// +-/// This is especially useful if a parser depends +-/// on the value return by a preceding parser in +-/// a `chain!`. +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done,Error}; +-/// # use nom::{Err,ErrorKind}; +-/// # fn main() { +-/// let b = true; +-/// let f = closure!(&'static[u8], +-/// cond_reduce!( b, tag!("abcd") ) +-/// ); +-/// +-/// let a = b"abcdef"; +-/// assert_eq!(f(&a[..]), Done(&b"ef"[..], &b"abcd"[..])); +-/// +-/// let b2 = false; +-/// let f2 = closure!(&'static[u8], +-/// cond_reduce!( b2, tag!("abcd") ) +-/// ); +-/// assert_eq!(f2(&a[..]), Error(Err::Position(ErrorKind::CondReduce, &a[..]))); +-/// # } +-/// ``` +-/// +-#[macro_export] +-macro_rules! cond_reduce( +- ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- if $cond { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,o) => $crate::IResult::Done(i, o), +- $crate::IResult::Error(e) => $crate::IResult::Error(e), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::CondReduce, $i)) +- } +- } +- ); +- ($i:expr, $cond:expr, $f:expr) => ( +- cond_reduce!($i, $cond, call!($f)); +- ); +-); +- +-/// `peek!(I -> IResult) => I -> IResult` +-/// returns a result without consuming the input +-/// +-/// the embedded parser may return Incomplete +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # fn main() { +-/// named!(ptag, peek!( tag!( "abcd" ) ) ); +-/// +-/// let r = ptag(&b"abcdefgh"[..]); +-/// assert_eq!(r, Done(&b"abcdefgh"[..], &b"abcd"[..])); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! peek( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(_,o) => $crate::IResult::Done($i, o), +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } +- ); +- ($i:expr, $f:expr) => ( +- peek!($i, call!($f)); +- ); +-); +- +-/// `not!(I -> IResult) => I -> IResult` +-/// returns a result only if the embedded parser returns Error or Incomplete +-/// does not consume the input +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done, Error}; +-/// # use nom::Err::{Position}; +-/// # use nom::ErrorKind; +-/// # fn main() { +-/// named!(not_e, chain!( +-/// res: tag!("abc") ~ +-/// not!(char!('e')), +-/// || { res })); +-/// +-/// let r = not_e(&b"abcd"[..]); +-/// assert_eq!(r, Done(&b"d"[..], &b"abc"[..])); +-/// +-/// let r2 = not_e(&b"abce"[..]); +-/// assert_eq!(r2, Error(Position(ErrorKind::Not, &b"e"[..]))); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! not( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(_, _) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Not, $i)), +- $crate::IResult::Error(_) => $crate::IResult::Done($i, &($i)[..0]), +- $crate::IResult::Incomplete(_) => $crate::IResult::Done($i, &($i)[..0]) +- } +- } +- ); +-); +- +-/// `tap!(name: I -> IResult => { block }) => I -> IResult` +-/// allows access to the parser's result without affecting it +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::Done; +-/// # use std::str; +-/// # fn main() { +-/// named!(ptag, tap!(res: tag!( "abcd" ) => { println!("recognized {}", str::from_utf8(res).unwrap()) } ) ); +-/// +-/// let r = ptag(&b"abcdefgh"[..]); +-/// assert_eq!(r, Done(&b"efgh"[..], &b"abcd"[..])); +-/// # } +-/// ``` +-#[macro_export] +-macro_rules! tap ( +- ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => ( +- { +- match $submac!($i, $($args)*) { +- $crate::IResult::Done(i,o) => { +- let $name = o; +- $e; +- $crate::IResult::Done(i, $name) +- }, +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) +- } +- } +- ); +- ($i:expr, $name: ident: $f:expr => $e:expr) => ( +- tap!($i, $name: call!($f) => $e); +- ); +-); +- +-/// `pair!(I -> IResult, I -> IResult) => I -> IResult` +-/// pair(X,Y), returns (x,y) +-/// +-#[macro_export] +-macro_rules! pair( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( +- { +- tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) +- } +- ); +- +- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- pair!($i, $submac!($($args)*), call!($g)); +- ); +- +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- pair!($i, call!($f), $submac!($($args)*)); +- ); +- +- ($i:expr, $f:expr, $g:expr) => ( +- pair!($i, call!($f), call!($g)); +- ); +-); +- +-/// `separated_pair!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` +-/// separated_pair(X,sep,Y) returns (x,y) +-#[macro_export] +-macro_rules! separated_pair( +- ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( +- { +- match tuple_parser!($i, 0usize, (), $submac!($($args)*), $($rest)*) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i1, (o1, _, o2)) => { +- $crate::IResult::Done(i1, (o1, o2)) +- } +- } +- } +- ); +- +- ($i:expr, $f:expr, $($rest:tt)+) => ( +- separated_pair!($i, call!($f), $($rest)*); +- ); +-); +- +-/// `preceded!(I -> IResult, I -> IResult) => I -> IResult` +-/// preceded(opening, X) returns X +-#[macro_export] +-macro_rules! preceded( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( +- { +- match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(remaining, (_,o)) => { +- $crate::IResult::Done(remaining, o) +- } +- } +- } +- ); +- +- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- preceded!($i, $submac!($($args)*), call!($g)); +- ); +- +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- preceded!($i, call!($f), $submac!($($args)*)); +- ); +- +- ($i:expr, $f:expr, $g:expr) => ( +- preceded!($i, call!($f), call!($g)); +- ); +-); +- +-/// `terminated!(I -> IResult, I -> IResult) => I -> IResult` +-/// terminated(X, closing) returns X +-#[macro_export] +-macro_rules! terminated( +- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( +- { +- match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(remaining, (o,_)) => { +- $crate::IResult::Done(remaining, o) +- } +- } +- } +- ); +- +- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- terminated!($i, $submac!($($args)*), call!($g)); +- ); +- +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- terminated!($i, call!($f), $submac!($($args)*)); +- ); +- +- ($i:expr, $f:expr, $g:expr) => ( +- terminated!($i, call!($f), call!($g)); +- ); +-); +- +-/// `delimited!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` +-/// delimited(opening, X, closing) returns X +-#[macro_export] +-macro_rules! delimited( +- ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( +- { +- match tuple_parser!($i, 0usize, (), $submac!($($args)*), $($rest)*) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i1, (_, o, _)) => { +- $crate::IResult::Done(i1, o) +- } +- } +- } +- ); +- +- ($i:expr, $f:expr, $($rest:tt)+) => ( +- delimited!($i, call!($f), $($rest)*); +- ); +-); +- +-/// `separated_list!(I -> IResult, I -> IResult) => I -> IResult>` +-/// separated_list(sep, X) returns Vec +-#[macro_export] +-macro_rules! separated_list( +- ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( +- { +- let mut res = ::std::vec::Vec::new(); +- let mut input = $i; +- +- // get the first element +- match $submac!(input, $($args2)*) { +- $crate::IResult::Error(_) => $crate::IResult::Done(input, ::std::vec::Vec::new()), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i,o) => { +- if i.len() == input.len() { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::SeparatedList,input)) +- } else { +- res.push(o); +- input = i; +- +- loop { +- // get the separator first +- if let $crate::IResult::Done(i2,_) = $sep!(input, $($args)*) { +- if i2.len() == input.len() { +- break; +- } +- +- // get the element next +- if let $crate::IResult::Done(i3,o3) = $submac!(i2, $($args2)*) { +- if i3.len() == i2.len() { +- break; +- } +- res.push(o3); +- input = i3; +- } else { +- break; +- } +- } else { +- break; +- } +- } +- $crate::IResult::Done(input, res) +- } +- }, +- } +- } +- ); +- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- separated_list!($i, $submac!($($args)*), call!($g)); +- ); +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- separated_list!($i, call!($f), $submac!($($args)*)); +- ); +- ($i:expr, $f:expr, $g:expr) => ( +- separated_list!($i, call!($f), call!($g)); +- ); +-); +- +-/// `separated_nonempty_list!(I -> IResult, I -> IResult) => I -> IResult>` +-/// separated_nonempty_list(sep, X) returns Vec +-#[macro_export] +-macro_rules! separated_nonempty_list( +- ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( +- { +- let mut res = ::std::vec::Vec::new(); +- let mut input = $i; +- +- // get the first element +- match $submac!(input, $($args2)*) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i,o) => { +- if i.len() == input.len() { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::SeparatedNonEmptyList,input)) +- } else { +- res.push(o); +- input = i; +- +- loop { +- if let $crate::IResult::Done(i2,_) = $sep!(input, $($args)*) { +- if i2.len() == input.len() { +- break; +- } +- +- if let $crate::IResult::Done(i3,o3) = $submac!(i2, $($args2)*) { +- if i3.len() == i2.len() { +- break; +- } +- res.push(o3); +- input = i3; +- } else { +- break; +- } +- } else { +- break; +- } +- } +- $crate::IResult::Done(input, res) +- } +- }, +- } +- } +- ); +- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( +- separated_nonempty_list!($i, $submac!($($args)*), call!($g)); +- ); +- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( +- separated_nonempty_list!($i, call!($f), $submac!($($args)*)); +- ); +- ($i:expr, $f:expr, $g:expr) => ( +- separated_nonempty_list!($i, call!($f), call!($g)); +- ); +-); +- +-/// `many0!(I -> IResult) => I -> IResult>` +-/// Applies the parser 0 or more times and returns the list of results in a Vec ++/// `cond_with_error!(bool, I -> IResult) => I -> IResult>` ++/// Conditional combinator + /// +-/// the embedded parser may return Incomplete ++/// Wraps another parser and calls it if the ++/// condition is met. This combinator returns ++/// an Option of the return type of the child ++/// parser. ++/// ++/// This is especially useful if a parser depends ++/// on the value returned by a preceding parser in ++/// a `do_parse!`. + /// + /// ``` + /// # #[macro_use] extern crate nom; + /// # use nom::IResult::Done; ++/// # use nom::IResult; + /// # fn main() { +-/// named!(multi<&[u8], Vec<&[u8]> >, many0!( tag!( "abcd" ) ) ); ++/// let b = true; ++/// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b, tag!("abcd") )) ++/// ); + /// +-/// let a = b"abcdabcdefgh"; +-/// let b = b"azerty"; ++/// let a = b"abcdef"; ++/// assert_eq!(f(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); + /// +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); +-/// assert_eq!(multi(&b[..]), Done(&b"azerty"[..], Vec::new())); +-/// # } ++/// let b2 = false; ++/// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b2, tag!("abcd") )) ++/// ); ++/// assert_eq!(f2(&a[..]), Done(&b"abcdef"[..], None)); ++/// # } + /// ``` +-/// 0 or more ++/// + #[macro_export] +-macro_rules! many0( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++macro_rules! cond_with_error( ++ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( + { +- use $crate::InputLength; +- +- let ret; +- let mut res = ::std::vec::Vec::new(); +- let mut input = $i; +- +- loop { +- if input.input_len() == 0 { +- ret = $crate::IResult::Done(input, res); break; +- } +- +- match $submac!(input, $($args)*) { +- $crate::IResult::Error(_) => { +- ret = $crate::IResult::Done(input, res); break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => { +- ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => { +- let size = i + ($i).input_len() - input.input_len(); +- ret = $crate::IResult::Incomplete($crate::Needed::Size(size)); break; +- }, +- $crate::IResult::Done(i, o) => { +- // loop trip must always consume (otherwise infinite loops) +- if i == input { +- ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many0,input)); break; +- } +- +- res.push(o); +- input = i; +- } ++ if $cond { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) + } ++ } else { ++ let res: $crate::IResult<_,_> = $crate::IResult::Done($i, ::std::option::Option::None); ++ res + } +- +- ret + } + ); +- ($i:expr, $f:expr) => ( +- many0!($i, call!($f)); ++ ($i:expr, $cond:expr, $f:expr) => ( ++ cond_with_error!($i, $cond, call!($f)); + ); + ); + +-/// `many1!(I -> IResult) => I -> IResult>` +-/// Applies the parser 1 or more times and returns the list of results in a Vec ++/// `cond!(bool, I -> IResult) => I -> IResult>` ++/// Conditional combinator + /// +-/// the embedded parser may return Incomplete ++/// Wraps another parser and calls it if the ++/// condition is met. This combinator returns ++/// an Option of the return type of the child ++/// parser. ++/// ++/// This is especially useful if a parser depends ++/// on the value returned by a preceding parser in ++/// a `do_parse!`. + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done, Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; ++/// # use nom::IResult::Done; ++/// # use nom::IResult; + /// # fn main() { +-/// named!(multi<&[u8], Vec<&[u8]> >, many1!( tag!( "abcd" ) ) ); ++/// let b = true; ++/// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b, tag!("abcd") )) ++/// ); + /// +-/// let a = b"abcdabcdefgh"; +-/// let b = b"azerty"; ++/// let a = b"abcdef"; ++/// assert_eq!(f(&a[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); + /// +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); +-/// assert_eq!(multi(&b[..]), Error(Position(ErrorKind::Many1,&b[..]))); +-/// # } ++/// let b2 = false; ++/// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], ++/// cond!( b2, tag!("abcd") )) ++/// ); ++/// assert_eq!(f2(&a[..]), Done(&b"abcdef"[..], None)); ++/// # } + /// ``` ++/// + #[macro_export] +-macro_rules! many1( +- ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++macro_rules! cond( ++ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( + { +- use $crate::InputLength; +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many1,$i)), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i1,o1) => { +- if i1.input_len() == 0 { +- $crate::IResult::Done(i1,vec![o1]) +- } else { +- +- let mut res = ::std::vec::Vec::with_capacity(4); +- res.push(o1); +- let mut input = i1; +- let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; +- loop { +- if input.input_len() == 0 { +- break; +- } +- match $submac!(input, $($args)*) { +- $crate::IResult::Error(_) => { +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Unknown); +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); +- break; +- }, +- $crate::IResult::Done(i, o) => { +- if i.input_len() == input.input_len() { +- break; +- } +- res.push(o); +- input = i; +- } +- } +- } +- +- match incomplete { +- ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), +- ::std::option::Option::None => $crate::IResult::Done(input, res) +- } +- } ++ if $cond { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Error(_) => { ++ let res: $crate::IResult<_,_> = $crate::IResult::Done($i, ::std::option::Option::None); ++ res ++ }, + } ++ } else { ++ let res: $crate::IResult<_,_> = $crate::IResult::Done($i, ::std::option::Option::None); ++ res + } + } + ); +- ($i:expr, $f:expr) => ( +- many1!($i, call!($f)); ++ ($i:expr, $cond:expr, $f:expr) => ( ++ cond!($i, $cond, call!($f)); + ); + ); + +-/// `many_m_n!(usize, usize, I -> IResult) => I -> IResult>` +-/// Applies the parser between m and n times (n included) and returns the list of results in a Vec ++/// `cond_reduce!(bool, I -> IResult) => I -> IResult` ++/// Conditional combinator with error + /// +-/// the embedded parser may return Incomplete ++/// Wraps another parser and calls it if the ++/// condition is met. This combinator returns ++/// an error if the condition is false ++/// ++/// This is especially useful if a parser depends ++/// on the value returned by a preceding parser in ++/// a `do_parse!`. + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done, Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; ++/// # use nom::IResult::{Done,Error}; ++/// # use nom::{Err,ErrorKind}; + /// # fn main() { +-/// named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, tag!( "abcd" ) ) ); ++/// let b = true; ++/// let f = closure!(&'static[u8], ++/// cond_reduce!( b, tag!("abcd") ) ++/// ); + /// +-/// let a = b"abcdefgh"; +-/// let b = b"abcdabcdefgh"; +-/// let c = b"abcdabcdabcdabcdabcdefgh"; ++/// let a = b"abcdef"; ++/// assert_eq!(f(&a[..]), Done(&b"ef"[..], &b"abcd"[..])); + /// +-/// assert_eq!(multi(&a[..]),Error(Position(ErrorKind::ManyMN,&a[..]))); +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&b[..]), Done(&b"efgh"[..], res)); +-/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&c[..]), Done(&b"abcdefgh"[..], res2)); +-/// # } ++/// let b2 = false; ++/// let f2 = closure!(&'static[u8], ++/// cond_reduce!( b2, tag!("abcd") ) ++/// ); ++/// assert_eq!(f2(&a[..]), Error(error_position!(ErrorKind::CondReduce, &a[..]))); ++/// # } + /// ``` ++/// + #[macro_export] +-macro_rules! many_m_n( +- ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* )) => ( ++macro_rules! cond_reduce( ++ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( + { +- use $crate::InputLength; +- let mut res = ::std::vec::Vec::with_capacity($m); +- let mut input = $i; +- let mut count: usize = 0; +- let mut err = false; +- let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; +- loop { +- if count == $n { break } +- match $submac!(input, $($args)*) { +- $crate::IResult::Done(i, o) => { +- // do not allow parsers that do not consume input (causes infinite loops) +- if i.input_len() == input.input_len() { +- break; +- } +- res.push(o); +- input = i; +- count += 1; +- } +- $crate::IResult::Error(_) => { +- err = true; +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Unknown); +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); +- break; +- }, +- } +- if input.input_len() == 0 { +- break; +- } +- } +- +- if count < $m { +- if err { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ManyMN,$i)) +- } else { +- match incomplete { +- ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), +- ::std::option::Option::None => $crate::IResult::Incomplete($crate::Needed::Unknown) +- } ++ if $cond { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) + } + } else { +- match incomplete { +- ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), +- ::std::option::Option::None => $crate::IResult::Done(input, res) +- } ++ $crate::IResult::Error(error_position!($crate::ErrorKind::CondReduce, $i)) + } + } + ); +- ($i:expr, $m:expr, $n: expr, $f:expr) => ( +- many_m_n!($i, $m, $n, call!($f)); ++ ($i:expr, $cond:expr, $f:expr) => ( ++ cond_reduce!($i, $cond, call!($f)); + ); + ); + +-/// `count!(I -> IResult, nb) => I -> IResult>` +-/// Applies the child parser a specified number of times ++/// `peek!(I -> IResult) => I -> IResult` ++/// returns a result without consuming the input ++/// ++/// the embedded parser may return Incomplete + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done,Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; ++/// # use nom::IResult::Done; + /// # fn main() { +-/// named!(counter< Vec<&[u8]> >, count!( tag!( "abcd" ), 2 ) ); +-/// +-/// let a = b"abcdabcdabcdef"; +-/// let b = b"abcdefgh"; +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// named!(ptag, peek!( tag!( "abcd" ) ) ); + /// +-/// assert_eq!(counter(&a[..]), Done(&b"abcdef"[..], res)); +-/// assert_eq!(counter(&b[..]), Error(Position(ErrorKind::Count, &b[..]))); ++/// let r = ptag(&b"abcdefgh"[..]); ++/// assert_eq!(r, Done(&b"abcdefgh"[..], &b"abcd"[..])); + /// # } + /// ``` +-/// + #[macro_export] +-macro_rules! count( +- ($i:expr, $submac:ident!( $($args:tt)* ), $count: expr) => ( ++macro_rules! peek( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- let ret; +- let mut input = $i; +- let mut res = ::std::vec::Vec::with_capacity($count); +- +- loop { +- if res.len() == $count { +- ret = $crate::IResult::Done(input, res); break; +- } +- +- match $submac!(input, $($args)*) { +- $crate::IResult::Done(i,o) => { +- res.push(o); +- input = i; +- }, +- $crate::IResult::Error(_) => { +- ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Count,$i)); break; +- }, +- $crate::IResult::Incomplete(_) => { +- ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; +- } +- } ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(_,o) => $crate::IResult::Done($i, o), ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) + } +- +- ret + } + ); +- ($i:expr, $f:expr, $count: expr) => ( +- count!($i, call!($f), $count); ++ ($i:expr, $f:expr) => ( ++ peek!($i, call!($f)); + ); + ); + +-/// `count_fixed!(O, I -> IResult, nb) => I -> IResult` +-/// Applies the child parser a fixed number of times and returns a fixed size array +-/// The type must be specified and it must be `Copy` ++/// `not!(I -> IResult) => I -> IResult` ++/// returns a result only if the embedded parser returns Error or Incomplete ++/// does not consume the input + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done,Error}; ++/// # use nom::IResult::{Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] + /// # use nom::Err::Position; + /// # use nom::ErrorKind; + /// # fn main() { +-/// named!(counter< [&[u8]; 2] >, count_fixed!( &[u8], tag!( "abcd" ), 2 ) ); +-/// // can omit the type specifier if returning slices +-/// // named!(counter< [&[u8]; 2] >, count_fixed!( tag!( "abcd" ), 2 ) ); ++/// named!(not_e, do_parse!( ++/// res: tag!("abc") >> ++/// not!(char!('e')) >> ++/// (res) ++/// )); + /// +-/// let a = b"abcdabcdabcdef"; +-/// let b = b"abcdefgh"; +-/// let res = [&b"abcd"[..], &b"abcd"[..]]; ++/// let r = not_e(&b"abcd"[..]); ++/// assert_eq!(r, Done(&b"d"[..], &b"abc"[..])); + /// +-/// assert_eq!(counter(&a[..]), Done(&b"abcdef"[..], res)); +-/// assert_eq!(counter(&b[..]), Error(Position(ErrorKind::Count, &b[..]))); ++/// let r2 = not_e(&b"abce"[..]); ++/// assert_eq!(r2, Error(error_position!(ErrorKind::Not, &b"e"[..]))); + /// # } + /// ``` +-/// +-#[macro_export] +-macro_rules! count_fixed ( +- ($i:expr, $typ:ty, $submac:ident!( $($args:tt)* ), $count: expr) => ( +- { +- let ret; +- let mut input = $i; +- // `$typ` must be Copy, and thus having no destructor, this is panic safe +- let mut res: [$typ; $count] = unsafe{[::std::mem::uninitialized(); $count as usize]}; +- let mut cnt: usize = 0; +- +- loop { +- if cnt == $count { +- ret = $crate::IResult::Done(input, res); break; +- } +- +- match $submac!(input, $($args)*) { +- $crate::IResult::Done(i,o) => { +- res[cnt] = o; +- cnt += 1; +- input = i; +- }, +- $crate::IResult::Error(_) => { +- ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Count,$i)); break; +- }, +- $crate::IResult::Incomplete(_) => { +- ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; +- } +- } +- } +- +- ret +- } +- ); +- ($i:expr, $typ: ty, $f:ident, $count: expr) => ( +- count_fixed!($i, $typ, call!($f), $count); +- ); +-); +- +-/// `length_value!(I -> IResult, I -> IResult) => I -> IResult>` +-/// gets a number from the first parser, then applies the second parser that many times + #[macro_export] +-macro_rules! length_value( +- ($i:expr, $f:expr, $g:expr) => ( ++macro_rules! not( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- match $f($i) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), +- $crate::IResult::Done(inum, onum) => { +- let ret; +- let length_token = $i.len() - inum.len(); +- let mut input = inum; +- let mut res = ::std::vec::Vec::new(); +- +- loop { +- if res.len() == onum as usize { +- ret = $crate::IResult::Done(input, res); break; +- } +- +- match $g(input) { +- $crate::IResult::Done(iparse, oparse) => { +- res.push(oparse); +- input = iparse; +- }, +- $crate::IResult::Error(_) => { +- ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::LengthValue,$i)); break; +- }, +- $crate::IResult::Incomplete(a) => { +- ret = match a { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(length) => $crate::IResult::Incomplete($crate::Needed::Size(length_token + onum as usize * length)) +- }; +- break; +- } +- } +- } +- +- ret +- } ++ use $crate::Slice; ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(_, _) => $crate::IResult::Error(error_position!($crate::ErrorKind::Not, $i)), ++ $crate::IResult::Error(_) => $crate::IResult::Done($i, ($i).slice(..0)), ++ $crate::IResult::Incomplete(_) => $crate::IResult::Done($i, ($i).slice(..0)) + } + } + ); +- ($i:expr, $f:expr, $g:expr, $length:expr) => ( +- { +- match $f($i) { +- $crate::IResult::Error(a) => $crate::IResult::Error(a), +- $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), +- $crate::IResult::Done(inum, onum) => { +- let ret; +- let length_token = $i.len() - inum.len(); +- let mut input = inum; +- let mut res = ::std::vec::Vec::new(); +- +- loop { +- if res.len() == onum as usize { +- ret = $crate::IResult::Done(input, res); break; +- } +- +- match $g(input) { +- $crate::IResult::Done(iparse, oparse) => { +- res.push(oparse); +- input = iparse; +- }, +- $crate::IResult::Error(_) => { +- ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::LengthValue,$i)); break; +- }, +- $crate::IResult::Incomplete(a) => { +- ret = match a { +- $crate::Needed::Unknown => $crate::IResult::Incomplete($crate::Needed::Unknown), +- $crate::Needed::Size(_) => $crate::IResult::Incomplete($crate::Needed::Size(length_token + onum as usize * $length)) +- }; +- break; +- } +- } +- } +- +- ret +- } +- } +- } ++ ($i:expr, $f:expr) => ( ++ not!($i, call!($f)); + ); + ); + +-/// `fold_many0!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` +-/// Applies the parser 0 or more times and folds the list of return values +-/// +-/// the embedded parser may return Incomplete ++/// `tap!(name: I -> IResult => { block }) => I -> IResult` ++/// allows access to the parser's result without affecting it + /// + /// ``` + /// # #[macro_use] extern crate nom; + /// # use nom::IResult::Done; ++/// # use std::str; + /// # fn main() { +-/// named!(multi<&[u8], Vec<&[u8]> >, fold_many0!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { +-/// acc.push(item); +-/// acc +-/// })); +-/// +-/// let a = b"abcdabcdefgh"; +-/// let b = b"azerty"; ++/// named!(ptag, tap!(res: tag!( "abcd" ) => { println!("recognized {}", str::from_utf8(res).unwrap()) } ) ); + /// +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); +-/// assert_eq!(multi(&b[..]), Done(&b"azerty"[..], Vec::new())); ++/// let r = ptag(&b"abcdefgh"[..]); ++/// assert_eq!(r, Done(&b"efgh"[..], &b"abcd"[..])); + /// # } + /// ``` +-/// 0 or more + #[macro_export] +-macro_rules! fold_many0( +- ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++macro_rules! tap ( ++ ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => ( + { +- use $crate::InputLength; +- let ret; +- let f = $f; +- let mut res = $init; +- let mut input = $i; +- +- loop { +- if input.input_len() == 0 { +- ret = $crate::IResult::Done(input, res); break; +- } +- +- match $submac!(input, $($args)*) { +- $crate::IResult::Error(_) => { +- ret = $crate::IResult::Done(input, res); break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => { +- ret = $crate::IResult::Incomplete($crate::Needed::Unknown); break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => { +- let size = i + ($i).input_len() - input.input_len(); +- ret = $crate::IResult::Incomplete($crate::Needed::Size(size)); break; +- }, +- $crate::IResult::Done(i, o) => { +- // loop trip must always consume (otherwise infinite loops) +- if i == input { +- ret = $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many0,input)); break; +- } +- +- res = f(res, o); +- input = i; +- } +- } ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ let $name = o; ++ $e; ++ $crate::IResult::Done(i, $name) ++ }, ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) + } +- +- ret + } + ); +- ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( +- fold_many0!($i, call!($f), $init, $fold_f); +- ); +-); +- +-/// `fold_many1!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` +-/// Applies the parser 1 or more times and folds the list of return values +-/// +-/// the embedded parser may return Incomplete +-/// +-/// ``` +-/// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done, Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; +-/// # fn main() { +-/// named!(multi<&[u8], Vec<&[u8]> >, fold_many1!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { +-/// acc.push(item); +-/// acc +-/// })); +-/// +-/// let a = b"abcdabcdefgh"; +-/// let b = b"azerty"; ++ ($i:expr, $name: ident: $f:expr => $e:expr) => ( ++ tap!($i, $name: call!($f) => $e); ++ ); ++); ++ ++/// `eof!()` returns its input if it is at the end of input data + /// +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); +-/// assert_eq!(multi(&b[..]), Error(Position(ErrorKind::Many1,&b[..]))); +-/// # } +-/// ``` ++/// please note that for now, eof only means there's no more ++/// data available, it does not work yet with smarter input ++/// types + #[macro_export] +-macro_rules! fold_many1( +- ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++macro_rules! eof ( ++ ($i:expr,) => ( + { + use $crate::InputLength; +- match $submac!($i, $($args)*) { +- $crate::IResult::Error(_) => $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Many1,$i)), +- $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), +- $crate::IResult::Done(i1,o1) => { +- let acc = $init; +- let f = $f; +- if i1.len() == 0 { +- let acc = f(acc, o1); +- $crate::IResult::Done(i1,acc) +- } else { +- let mut acc = f(acc, o1); +- let mut input = i1; +- let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; +- loop { +- if input.input_len() == 0 { +- break; +- } +- match $submac!(input, $($args)*) { +- $crate::IResult::Error(_) => { +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Unknown); +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); +- break; +- }, +- $crate::IResult::Done(i, o) => { +- if i.input_len() == input.input_len() { +- break; +- } +- acc = f(acc, o); +- input = i; +- } +- } +- } +- +- match incomplete { +- ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), +- ::std::option::Option::None => $crate::IResult::Done(input, acc) +- } +- } +- } ++ if ($i).input_len() == 0 { ++ $crate::IResult::Done($i, $i) ++ } else { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Eof, $i)) + } + } + ); +- ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( +- fold_many1!($i, call!($f), $init, $fold_f); +- ); + ); + +-/// `fold_many_m_n!(usize, usize, I -> IResult, R, Fn(R, O) -> R) => I -> IResult` +-/// Applies the parser between m and n times (n included) and folds the list of return value +-/// +-/// the embedded parser may return Incomplete ++/// `recognize!(I -> IResult ) => I -> IResult` ++/// if the child parser was successful, return the consumed input as produced value + /// + /// ``` + /// # #[macro_use] extern crate nom; +-/// # use nom::IResult::{Done, Error}; +-/// # use nom::Err::Position; +-/// # use nom::ErrorKind; ++/// # use nom::IResult::Done; + /// # fn main() { +-/// named!(multi<&[u8], Vec<&[u8]> >, fold_many_m_n!(2, 4, tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { +-/// acc.push(item); +-/// acc +-/// })); +-/// +-/// let a = b"abcdefgh"; +-/// let b = b"abcdabcdefgh"; +-/// let c = b"abcdabcdabcdabcdabcdefgh"; +-/// +-/// assert_eq!(multi(&a[..]),Error(Position(ErrorKind::ManyMN,&a[..]))); +-/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&b[..]), Done(&b"efgh"[..], res)); +-/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; +-/// assert_eq!(multi(&c[..]), Done(&b"abcdefgh"[..], res2)); ++/// named!(x, recognize!(delimited!(tag!("")))); ++/// let r = x(&b" aaa"[..]); ++/// assert_eq!(r, Done(&b" aaa"[..], &b""[..])); + /// # } + /// ``` + #[macro_export] +-macro_rules! fold_many_m_n( +- ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++macro_rules! recognize ( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( + { +- use $crate::InputLength; +- let mut acc = $init; +- let f = $f; +- let mut input = $i; +- let mut count: usize = 0; +- let mut err = false; +- let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; +- loop { +- if count == $n { break } +- match $submac!(input, $($args)*) { +- $crate::IResult::Done(i, o) => { +- // do not allow parsers that do not consume input (causes infinite loops) +- if i.input_len() == input.input_len() { +- break; +- } +- acc = f(acc, o); +- input = i; +- count += 1; +- } +- $crate::IResult::Error(_) => { +- err = true; +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Unknown) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Unknown); +- break; +- }, +- $crate::IResult::Incomplete($crate::Needed::Size(i)) => { +- incomplete = ::std::option::Option::Some($crate::Needed::Size(i + ($i).input_len() - input.input_len())); +- break; +- }, +- } +- if input.input_len() == 0 { +- break; +- } +- } +- +- if count < $m { +- if err { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::ManyMN,$i)) +- } else { +- match incomplete { +- ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), +- ::std::option::Option::None => $crate::IResult::Incomplete($crate::Needed::Unknown) +- } +- } +- } else { +- match incomplete { +- ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), +- ::std::option::Option::None => $crate::IResult::Done(input, acc) +- } ++ use $crate::Offset; ++ use $crate::Slice; ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(i,_) => { ++ let index = (&$i).offset(&i); ++ $crate::IResult::Done(i, ($i).slice(..index)) ++ }, ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i) + } + } + ); +- ($i:expr, $m:expr, $n: expr, $f:expr, $init:expr, $fold_f:expr) => ( +- fold_many_m_n!($i, $m, $n, call!($f), $init, $fold_f); ++ ($i:expr, $f:expr) => ( ++ recognize!($i, call!($f)) + ); + ); + ++ + #[cfg(test)] + mod tests { +- use internal::{Needed,IResult,Err}; ++ use internal::{Needed,IResult}; ++ #[cfg(feature = "verbose-errors")] ++ use verbose_errors::Err; ++ ++ #[cfg(not(feature = "verbose-errors"))] ++ use simple_errors::Err; ++ + use internal::IResult::*; +- use internal::Err::*; + use util::ErrorKind; + + // reproduce the tag and take macros, because of module import order +@@ -2705,7 +1191,7 @@ mod tests { + let b = &$bytes[..m]; + + let res: $crate::IResult<_,_> = if reduced != b { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::Tag, $i)) ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i)) + } else if m < blen { + $crate::IResult::Incomplete($crate::Needed::Size(blen)) + } else { +@@ -2753,333 +1239,6 @@ mod tests { + assert_eq!(b, 6); + } + +- #[derive(PartialEq,Eq,Debug)] +- struct B { +- a: u8, +- b: u8 +- } +- +- #[test] +- fn chain2() { +- fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; +- fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Done(i,2) }; +- +- named!(chain_parser<&[u8],B>, +- chain!( +- tag!("abcd") ~ +- tag!("abcd")? ~ +- aa: ret_int1 ~ +- tag!("efgh") ~ +- bb: ret_int2 ~ +- tag!("efgh") , +- ||{B{a: aa, b: bb}} +- ) +- ); +- +- assert_eq!(chain_parser(&b"abcdabcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); +- assert_eq!(chain_parser(&b"abcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); +- assert_eq!(chain_parser(&b"abcdab"[..]), Incomplete(Needed::Size(8))); +- assert_eq!(chain_parser(&b"abcdefghef"[..]), Incomplete(Needed::Size(12))); +- } +- +- #[test] +- fn nested_chain() { +- fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; +- fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Done(i,2) }; +- +- named!(chain_parser<&[u8],B>, +- chain!( +- chain!( +- tag!("abcd") ~ +- tag!("abcd")? , +- || {} +- ) ~ +- aa: ret_int1 ~ +- tag!("efgh") ~ +- bb: ret_int2 ~ +- tag!("efgh") , +- ||{B{a: aa, b: bb}} +- ) +- ); +- +- assert_eq!(chain_parser(&b"abcdabcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); +- assert_eq!(chain_parser(&b"abcdefghefghX"[..]), Done(&b"X"[..], B{a: 1, b: 2})); +- assert_eq!(chain_parser(&b"abcdab"[..]), Incomplete(Needed::Size(8))); +- assert_eq!(chain_parser(&b"abcdefghef"[..]), Incomplete(Needed::Size(12))); +- } +- +- #[derive(PartialEq,Eq,Debug)] +- struct C { +- a: u8, +- b: Option +- } +- +- #[test] +- fn chain_mut() { +- fn ret_b1_2(i:&[u8]) -> IResult<&[u8], B> { Done(i,B{a:1,b:2}) }; +- named!(f<&[u8],B>, +- chain!( +- tag!("abcd") ~ +- tag!("abcd")? ~ +- tag!("efgh") ~ +- mut bb: ret_b1_2 ~ +- tag!("efgh") , +- ||{ +- bb.b = 3; +- bb +- } +- ) +- ); +- +- let r = f(&b"abcdabcdefghefghX"[..]); +- assert_eq!(r, Done(&b"X"[..], B{a: 1, b: 3})); +- } +- +- #[test] +- fn chain_opt() { +- named!(y, tag!("efgh")); +- fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; +- named!(ret_y<&[u8], u8>, map!(y, |_| 2)); +- +- named!(chain_parser<&[u8],C>, +- chain!( +- tag!("abcd") ~ +- aa: ret_int1 ~ +- bb: ret_y? , +- ||{C{a: aa, b: bb}} +- ) +- ); +- +- assert_eq!(chain_parser(&b"abcdefghX"[..]), Done(&b"X"[..], C{a: 1, b: Some(2)})); +- assert_eq!(chain_parser(&b"abcdWXYZ"[..]), Done(&b"WXYZ"[..], C{a: 1, b: None})); +- assert_eq!(chain_parser(&b"abcdX"[..]), Done(&b"X"[..], C{ a: 1, b: None })); +- assert_eq!(chain_parser(&b"abcdef"[..]), Incomplete(Needed::Size(8))); +- } +- +- use util::{error_to_list, add_error_pattern, print_error}; +- +- fn error_to_string

(e: &Err

) -> &'static str { +- let v:Vec = error_to_list(e); +- // do it this way if you can use slice patterns +- /* +- match &v[..] { +- [ErrorKind::Custom(42), ErrorKind::Tag] => "missing `ijkl` tag", +- [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] => "missing `mnop` tag after `ijkl`", +- _ => "unrecognized error" +- } +- */ +- if &v[..] == [ErrorKind::Custom(42),ErrorKind::Tag] { +- "missing `ijkl` tag" +- } else if &v[..] == [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] { +- "missing `mnop` tag after `ijkl`" +- } else { +- "unrecognized error" +- } +- } +- +- // do it this way if you can use box patterns +- /*use std::str; +- fn error_to_string(e:Err) -> String +- match e { +- NodePosition(ErrorKind::Custom(42), i1, box Position(ErrorKind::Tag, i2)) => { +- format!("missing `ijkl` tag, found '{}' instead", str::from_utf8(i2).unwrap()) +- }, +- NodePosition(ErrorKind::Custom(42), i1, box NodePosition(ErrorKind::Custom(128), i2, box Position(ErrorKind::Tag, i3))) => { +- format!("missing `mnop` tag after `ijkl`, found '{}' instead", str::from_utf8(i3).unwrap()) +- }, +- _ => "unrecognized error".to_string() +- } +- }*/ +- use std::collections; +- #[test] +- fn err() { +- named!(err_test, alt!( +- tag!("abcd") | +- preceded!(tag!("efgh"), error!(ErrorKind::Custom(42), +- chain!( +- tag!("ijkl") ~ +- res: error!(ErrorKind::Custom(128), tag!("mnop")) , +- || { res } +- ) +- ) +- ) +- )); +- let a = &b"efghblah"[..]; +- let b = &b"efghijklblah"[..]; +- let c = &b"efghijklmnop"[..]; +- +- let blah = &b"blah"[..]; +- +- let res_a = err_test(a); +- let res_b = err_test(b); +- let res_c = err_test(c); +- assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), blah, Box::new(Position(ErrorKind::Tag, blah))))); +- assert_eq!(res_b, Error(NodePosition(ErrorKind::Custom(42), &b"ijklblah"[..], Box::new(NodePosition(ErrorKind::Custom(128), blah, Box::new(Position(ErrorKind::Tag, blah))))))); +- assert_eq!(res_c, Done(&b""[..], &b"mnop"[..])); +- +- // Merr-like error matching +- let mut err_map = collections::HashMap::new(); +- assert!(add_error_pattern(&mut err_map, err_test(&b"efghpouet"[..]), "missing `ijkl` tag")); +- assert!(add_error_pattern(&mut err_map, err_test(&b"efghijklpouet"[..]), "missing `mnop` tag after `ijkl`")); +- +- let res_a2 = res_a.clone(); +- match res_a { +- Error(e) => { +- assert_eq!(error_to_list(&e), [ErrorKind::Custom(42), ErrorKind::Tag]); +- assert_eq!(error_to_string(&e), "missing `ijkl` tag"); +- assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `ijkl` tag")); +- }, +- _ => panic!() +- }; +- +- let res_b2 = res_b.clone(); +- match res_b { +- Error(e) => { +- assert_eq!(error_to_list(&e), [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag]); +- assert_eq!(error_to_string(&e), "missing `mnop` tag after `ijkl`"); +- assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `mnop` tag after `ijkl`")); +- }, +- _ => panic!() +- }; +- +- print_error(a, res_a2); +- print_error(b, res_b2); +- } +- +- #[test] +- fn add_err() { +- named!(err_test, +- preceded!(tag!("efgh"), add_error!(ErrorKind::Custom(42), +- chain!( +- tag!("ijkl") ~ +- res: add_error!(ErrorKind::Custom(128), tag!("mnop")) , +- || { res } +- ) +- ) +- )); +- let a = &b"efghblah"[..]; +- let b = &b"efghijklblah"[..]; +- let c = &b"efghijklmnop"[..]; +- +- let blah = &b"blah"[..]; +- +- let res_a = err_test(a); +- let res_b = err_test(b); +- let res_c = err_test(c); +- assert_eq!(res_a, Error(NodePosition(ErrorKind::Custom(42), blah, Box::new(Position(ErrorKind::Tag, blah))))); +- assert_eq!(res_b, Error(NodePosition(ErrorKind::Custom(42), &b"ijklblah"[..], Box::new(NodePosition(ErrorKind::Custom(128), blah, Box::new(Position(ErrorKind::Tag, blah))))))); +- assert_eq!(res_c, Done(&b""[..], &b"mnop"[..])); +- } +- +- #[test] +- fn complete() { +- named!(err_test, +- chain!( +- tag!("ijkl") ~ +- res: complete!(tag!("mnop")) , +- || { res } +- ) +- ); +- let a = &b"ijklmn"[..]; +- +- let res_a = err_test(a); +- assert_eq!(res_a, Error(Position(ErrorKind::Complete, &b"mn"[..]))); +- } +- #[test] +- fn alt() { +- fn work(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { +- Done(&b""[..], input) +- } +- +- #[allow(unused_variables)] +- fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8],&'static str> { +- Error(Code(ErrorKind::Custom("abcd"))) +- } +- +- fn work2(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { +- Done(input, &b""[..]) +- } +- +- fn alt1(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { +- alt!(i, dont_work | dont_work) +- } +- fn alt2(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { +- alt!(i, dont_work | work) +- } +- fn alt3(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { +- alt!(i, dont_work | dont_work | work2 | dont_work) +- } +- //named!(alt1, alt!(dont_work | dont_work)); +- //named!(alt2, alt!(dont_work | work)); +- //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work)); +- +- let a = &b"abcd"[..]; +- assert_eq!(alt1(a), Error(Position(ErrorKind::Alt, a))); +- assert_eq!(alt2(a), Done(&b""[..], a)); +- assert_eq!(alt3(a), Done(a, &b""[..])); +- +- named!(alt4, alt!(tag!("abcd") | tag!("efgh"))); +- let b = &b"efgh"[..]; +- assert_eq!(alt4(a), Done(&b""[..], a)); +- assert_eq!(alt4(b), Done(&b""[..], b)); +- +- // test the alternative syntax +- named!(alt5, alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true })); +- assert_eq!(alt5(a), Done(&b""[..], false)); +- assert_eq!(alt5(b), Done(&b""[..], true)); +- +- } +- +- #[test] +- fn alt_incomplete() { +- named!(alt1, alt!(tag!("a") | tag!("bc") | tag!("def"))); +- +- let a = &b""[..]; +- assert_eq!(alt1(a), Incomplete(Needed::Size(1))); +- let a = &b"b"[..]; +- assert_eq!(alt1(a), Incomplete(Needed::Size(2))); +- let a = &b"bcd"[..]; +- assert_eq!(alt1(a), Done(&b"d"[..], &b"bc"[..])); +- let a = &b"cde"[..]; +- assert_eq!(alt1(a), Error(Position(ErrorKind::Alt, a))); +- let a = &b"de"[..]; +- assert_eq!(alt1(a), Incomplete(Needed::Size(3))); +- let a = &b"defg"[..]; +- assert_eq!(alt1(a), Done(&b"g"[..], &b"def"[..])); +- } +- +- #[test] +- fn alt_complete() { +- named!(ac<&[u8], &[u8]>, +- alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl")) +- ); +- +- let a = &b""[..]; +- assert_eq!(ac(a), Incomplete(Needed::Size(2))); +- let a = &b"ef"[..]; +- assert_eq!(ac(a), Done(&b""[..], &b"ef"[..])); +- let a = &b"cde"[..]; +- assert_eq!(ac(a), Error(Position(ErrorKind::Alt, a))); +- } +- +- #[test] +- fn switch() { +- named!(sw, +- switch!(take!(4), +- b"abcd" => take!(2) | +- b"efgh" => take!(4) +- ) +- ); +- +- let a = &b"abcdefgh"[..]; +- assert_eq!(sw(a), Done(&b"gh"[..], &b"ef"[..])); +- +- let b = &b"efghijkl"[..]; +- assert_eq!(sw(b), Done(&b""[..], &b"ijkl"[..])); +- let c = &b"afghijkl"[..]; +- assert_eq!(sw(c), Error(Position(ErrorKind::Switch, &b"afghijkl"[..]))); +- } +- + #[test] + fn opt() { + named!(opt_abcd<&[u8],Option<&[u8]> >, opt!(tag!("abcd"))); +@@ -3092,22 +1251,39 @@ mod tests { + assert_eq!(opt_abcd(c), Incomplete(Needed::Size(4))); + } + ++ #[cfg(feature = "verbose-errors")] ++ #[test] ++ fn opt_res() { ++ named!(opt_res_abcd<&[u8], Result<&[u8], Err<&[u8]> > >, opt_res!(tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"bcdefg"[..]; ++ let c = &b"ab"[..]; ++ assert_eq!(opt_res_abcd(a), Done(&b"ef"[..], Ok(&b"abcd"[..]))); ++ assert_eq!(opt_res_abcd(b), Done(&b"bcdefg"[..], Err(error_position!(ErrorKind::Tag, b)))); ++ assert_eq!(opt_res_abcd(c), Incomplete(Needed::Size(4))); ++ } ++ ++ #[cfg(not(feature = "verbose-errors"))] + #[test] + fn opt_res() { +- named!(opt_res_abcd<&[u8], Result<&[u8], Err<&[u8]>> >, opt_res!(tag!("abcd"))); ++ named!(opt_res_abcd<&[u8], Result<&[u8], Err> >, opt_res!(tag!("abcd"))); + + let a = &b"abcdef"[..]; + let b = &b"bcdefg"[..]; + let c = &b"ab"[..]; + assert_eq!(opt_res_abcd(a), Done(&b"ef"[..], Ok(&b"abcd"[..]))); +- assert_eq!(opt_res_abcd(b), Done(&b"bcdefg"[..], Err(Position(ErrorKind::Tag, b)))); ++ assert_eq!(opt_res_abcd(b), Done(&b"bcdefg"[..], Err(error_position!(ErrorKind::Tag, b)))); + assert_eq!(opt_res_abcd(c), Incomplete(Needed::Size(4))); + } + + #[test] ++ #[cfg(feature = "std")] + fn cond() { +- let f_true: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( true, tag!("abcd") ) )); +- let f_false: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( false, tag!("abcd") ) )); ++ let f_true: Box IResult<&[u8],Option<&[u8]>, &str>> = ++ Box::new(closure!(&'static [u8], fix_error!(&str, cond!( true, tag!("abcd") ) ))); ++ let f_false: Box IResult<&[u8],Option<&[u8]>, &str>> = ++ Box::new(closure!(&'static [u8], fix_error!(&str, cond!( false, tag!("abcd") ) ))); + //let f_false = closure!(&'static [u8], cond!( false, tag!("abcd") ) ); + + assert_eq!(f_true(&b"abcdef"[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); +@@ -3120,11 +1296,14 @@ mod tests { + } + + #[test] ++ #[cfg(feature = "std")] + fn cond_wrapping() { + // Test that cond!() will wrap a given identifier in the call!() macro. + named!( tag_abcd, tag!("abcd") ); +- let f_true: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( true, tag_abcd ) )); +- let f_false: Box IResult<&[u8],Option<&[u8]>, &str>> = Box::new(closure!(&'static [u8], cond!( false, tag_abcd ) )); ++ let f_true: Box IResult<&[u8],Option<&[u8]>, &str>> = ++ Box::new(closure!(&'static [u8], fix_error!(&str, cond!( true, tag_abcd ) ))); ++ let f_false: Box IResult<&[u8],Option<&[u8]>, &str>> = ++ Box::new(closure!(&'static [u8], fix_error!(&str, cond!( false, tag_abcd ) ))); + //let f_false = closure!(&'static [u8], cond!( b2, tag!("abcd") ) ); + + assert_eq!(f_true(&b"abcdef"[..]), Done(&b"ef"[..], Some(&b"abcd"[..]))); +@@ -3142,420 +1321,22 @@ mod tests { + + assert_eq!(peek_tag(&b"abcdef"[..]), Done(&b"abcdef"[..], &b"abcd"[..])); + assert_eq!(peek_tag(&b"ab"[..]), Incomplete(Needed::Size(4))); +- assert_eq!(peek_tag(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- } +- +- #[test] +- fn pair() { +- named!( tag_abc, tag!("abc") ); +- named!( tag_def, tag!("def") ); +- named!( pair_abc_def<&[u8],(&[u8], &[u8])>, pair!(tag_abc, tag_def) ); +- +- assert_eq!(pair_abc_def(&b"abcdefghijkl"[..]), Done(&b"ghijkl"[..], (&b"abc"[..], &b"def"[..]))); +- assert_eq!(pair_abc_def(&b"ab"[..]), Incomplete(Needed::Size(3))); +- assert_eq!(pair_abc_def(&b"abcd"[..]), Incomplete(Needed::Size(6))); +- assert_eq!(pair_abc_def(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- assert_eq!(pair_abc_def(&b"xxxdef"[..]), Error(Position(ErrorKind::Tag, &b"xxxdef"[..]))); +- assert_eq!(pair_abc_def(&b"abcxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- } +- +- #[test] +- fn separated_pair() { +- named!( tag_abc, tag!("abc") ); +- named!( tag_def, tag!("def") ); +- named!( tag_separator, tag!(",") ); +- named!( sep_pair_abc_def<&[u8],(&[u8], &[u8])>, separated_pair!(tag_abc, tag_separator, tag_def) ); +- +- assert_eq!(sep_pair_abc_def(&b"abc,defghijkl"[..]), Done(&b"ghijkl"[..], (&b"abc"[..], &b"def"[..]))); +- assert_eq!(sep_pair_abc_def(&b"ab"[..]), Incomplete(Needed::Size(3))); +- assert_eq!(sep_pair_abc_def(&b"abc,d"[..]), Incomplete(Needed::Size(7))); +- assert_eq!(sep_pair_abc_def(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- assert_eq!(sep_pair_abc_def(&b"xxx,def"[..]), Error(Position(ErrorKind::Tag, &b"xxx,def"[..]))); +- assert_eq!(sep_pair_abc_def(&b"abc,xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- } +- +- #[test] +- fn preceded() { +- named!( tag_abcd, tag!("abcd") ); +- named!( tag_efgh, tag!("efgh") ); +- named!( preceded_abcd_efgh<&[u8], &[u8]>, preceded!(tag_abcd, tag_efgh) ); +- +- assert_eq!(preceded_abcd_efgh(&b"abcdefghijkl"[..]), Done(&b"ijkl"[..], &b"efgh"[..])); +- assert_eq!(preceded_abcd_efgh(&b"ab"[..]), Incomplete(Needed::Size(4))); +- assert_eq!(preceded_abcd_efgh(&b"abcde"[..]), Incomplete(Needed::Size(8))); +- assert_eq!(preceded_abcd_efgh(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- assert_eq!(preceded_abcd_efgh(&b"xxxxdef"[..]), Error(Position(ErrorKind::Tag, &b"xxxxdef"[..]))); +- assert_eq!(preceded_abcd_efgh(&b"abcdxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- } +- +- #[test] +- fn terminated() { +- named!( tag_abcd, tag!("abcd") ); +- named!( tag_efgh, tag!("efgh") ); +- named!( terminated_abcd_efgh<&[u8], &[u8]>, terminated!(tag_abcd, tag_efgh) ); +- +- assert_eq!(terminated_abcd_efgh(&b"abcdefghijkl"[..]), Done(&b"ijkl"[..], &b"abcd"[..])); +- assert_eq!(terminated_abcd_efgh(&b"ab"[..]), Incomplete(Needed::Size(4))); +- assert_eq!(terminated_abcd_efgh(&b"abcde"[..]), Incomplete(Needed::Size(8))); +- assert_eq!(terminated_abcd_efgh(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- assert_eq!(terminated_abcd_efgh(&b"xxxxdef"[..]), Error(Position(ErrorKind::Tag, &b"xxxxdef"[..]))); +- assert_eq!(terminated_abcd_efgh(&b"abcdxxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxxx"[..]))); +- } +- +- #[test] +- fn delimited() { +- named!( tag_abc, tag!("abc") ); +- named!( tag_def, tag!("def") ); +- named!( tag_ghi, tag!("ghi") ); +- named!( delimited_abc_def_ghi<&[u8], &[u8]>, delimited!(tag_abc, tag_def, tag_ghi) ); +- +- assert_eq!(delimited_abc_def_ghi(&b"abcdefghijkl"[..]), Done(&b"jkl"[..], &b"def"[..])); +- assert_eq!(delimited_abc_def_ghi(&b"ab"[..]), Incomplete(Needed::Size(3))); +- assert_eq!(delimited_abc_def_ghi(&b"abcde"[..]), Incomplete(Needed::Size(6))); +- assert_eq!(delimited_abc_def_ghi(&b"abcdefgh"[..]), Incomplete(Needed::Size(9))); +- assert_eq!(delimited_abc_def_ghi(&b"xxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- assert_eq!(delimited_abc_def_ghi(&b"xxxdefghi"[..]), Error(Position(ErrorKind::Tag, &b"xxxdefghi"[..]))); +- assert_eq!(delimited_abc_def_ghi(&b"abcxxxghi"[..]), Error(Position(ErrorKind::Tag, &b"xxxghi"[..]))); +- assert_eq!(delimited_abc_def_ghi(&b"abcdefxxx"[..]), Error(Position(ErrorKind::Tag, &b"xxx"[..]))); +- } +- +- #[test] +- fn separated_list() { +- named!(multi<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!("abcd"))); +- named!(multi_empty<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!(""))); +- +- let a = &b"abcdef"[..]; +- let b = &b"abcd,abcdef"[..]; +- let c = &b"azerty"[..]; +- let d = &b",,abc"[..]; +- let e = &b"abcd,abcd,ef"[..]; +- +- let res1 = vec![&b"abcd"[..]]; +- assert_eq!(multi(a), Done(&b"ef"[..], res1)); +- let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; +- assert_eq!(multi(b), Done(&b"ef"[..], res2)); +- assert_eq!(multi(c), Done(&b"azerty"[..], Vec::new())); +- assert_eq!(multi_empty(d), Error(Position(ErrorKind::SeparatedList, d))); +- //let res3 = vec![&b""[..], &b""[..], &b""[..]]; +- //assert_eq!(multi_empty(d), Done(&b"abc"[..], res3)); +- let res4 = vec![&b"abcd"[..], &b"abcd"[..]]; +- assert_eq!(multi(e), Done(&b",ef"[..], res4)); +- } +- +- #[test] +- fn separated_nonempty_list() { +- named!(multi<&[u8],Vec<&[u8]> >, separated_nonempty_list!(tag!(","), tag!("abcd"))); +- +- let a = &b"abcdef"[..]; +- let b = &b"abcd,abcdef"[..]; +- let c = &b"azerty"[..]; +- let d = &b"abcd,abcd,ef"[..]; +- +- let res1 = vec![&b"abcd"[..]]; +- assert_eq!(multi(a), Done(&b"ef"[..], res1)); +- let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; +- assert_eq!(multi(b), Done(&b"ef"[..], res2)); +- assert_eq!(multi(c), Error(Position(ErrorKind::Tag,c))); +- let res3 = vec![&b"abcd"[..], &b"abcd"[..]]; +- assert_eq!(multi(d), Done(&b",ef"[..], res3)); +- } +- +- #[test] +- fn many0() { +- named!( tag_abcd, tag!("abcd") ); +- named!( tag_empty, tag!("") ); +- named!( multi<&[u8],Vec<&[u8]> >, many0!(tag_abcd) ); +- named!( multi_empty<&[u8],Vec<&[u8]> >, many0!(tag_empty) ); +- +- assert_eq!(multi(&b"abcdef"[..]), Done(&b"ef"[..], vec![&b"abcd"[..]])); +- assert_eq!(multi(&b"abcdabcdefgh"[..]), Done(&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])); +- assert_eq!(multi(&b"azerty"[..]), Done(&b"azerty"[..], Vec::new())); +- assert_eq!(multi(&b"abcdab"[..]), Incomplete(Needed::Size(8))); +- assert_eq!(multi(&b"abcd"[..]), Done(&b""[..], vec![&b"abcd"[..]])); +- assert_eq!(multi(&b""[..]), Done(&b""[..], Vec::new())); +- assert_eq!(multi_empty(&b"abcdef"[..]), Error(Position(ErrorKind::Many0, &b"abcdef"[..]))); +- } +- +- #[cfg(feature = "nightly")] +- use test::Bencher; +- +- #[cfg(feature = "nightly")] +- #[bench] +- fn many0_bench(b: &mut Bencher) { +- named!(multi<&[u8],Vec<&[u8]> >, many0!(tag!("abcd"))); +- b.iter(|| { +- multi(&b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"[..]) +- }); +- } +- +- #[test] +- fn many1() { +- named!(multi<&[u8],Vec<&[u8]> >, many1!(tag!("abcd"))); +- +- let a = &b"abcdef"[..]; +- let b = &b"abcdabcdefgh"[..]; +- let c = &b"azerty"[..]; +- let d = &b"abcdab"[..]; +- +- let res1 = vec![&b"abcd"[..]]; +- assert_eq!(multi(a), Done(&b"ef"[..], res1)); +- let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; +- assert_eq!(multi(b), Done(&b"efgh"[..], res2)); +- assert_eq!(multi(c), Error(Position(ErrorKind::Many1,c))); +- assert_eq!(multi(d), Incomplete(Needed::Size(8))); +- } +- +- #[test] +- fn infinite_many() { +- fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { +- println!("input: {:?}", input); +- Error(Position(ErrorKind::Custom(0),input)) +- } +- +- // should not go into an infinite loop +- named!(multi0<&[u8],Vec<&[u8]> >, many0!(tst)); +- let a = &b"abcdef"[..]; +- assert_eq!(multi0(a), Done(a, Vec::new())); +- +- named!(multi1<&[u8],Vec<&[u8]> >, many1!(tst)); +- let a = &b"abcdef"[..]; +- assert_eq!(multi1(a), Error(Position(ErrorKind::Many1,a))); +- } +- +- #[test] +- fn many_m_n() { +- named!(multi<&[u8],Vec<&[u8]> >, many_m_n!(2, 4, tag!("Abcd"))); +- +- let a = &b"Abcdef"[..]; +- let b = &b"AbcdAbcdefgh"[..]; +- let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; +- let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; +- let e = &b"AbcdAb"[..]; +- +- assert_eq!(multi(a), Error(Err::Position(ErrorKind::ManyMN,a))); +- let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; +- assert_eq!(multi(b), Done(&b"efgh"[..], res1)); +- let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; +- assert_eq!(multi(c), Done(&b"efgh"[..], res2)); +- let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; +- assert_eq!(multi(d), Done(&b"Abcdefgh"[..], res3)); +- assert_eq!(multi(e), Incomplete(Needed::Size(8))); +- } +- +- #[test] +- fn count() { +- const TIMES: usize = 2; +- named!( tag_abc, tag!("abc") ); +- named!( cnt_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) ); +- +- assert_eq!(cnt_2(&b"abcabcabcdef"[..]), Done(&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]])); +- assert_eq!(cnt_2(&b"ab"[..]), Incomplete(Needed::Unknown)); +- assert_eq!(cnt_2(&b"abcab"[..]), Incomplete(Needed::Unknown)); +- assert_eq!(cnt_2(&b"xxx"[..]), Error(Position(ErrorKind::Count, &b"xxx"[..]))); +- assert_eq!(cnt_2(&b"xxxabcabcdef"[..]), Error(Position(ErrorKind::Count, &b"xxxabcabcdef"[..]))); +- assert_eq!(cnt_2(&b"abcxxxabcdef"[..]), Error(Position(ErrorKind::Count, &b"abcxxxabcdef"[..]))); +- } +- +- #[test] +- fn count_zero() { +- const TIMES: usize = 0; +- named!( tag_abc, tag!("abc") ); +- named!( counter_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) ); +- +- let done = &b"abcabcabcdef"[..]; +- let parsed_done = Vec::new(); +- let rest = done; +- let incomplete_1 = &b"ab"[..]; +- let parsed_incompl_1 = Vec::new(); +- let incomplete_2 = &b"abcab"[..]; +- let parsed_incompl_2 = Vec::new(); +- let error = &b"xxx"[..]; +- let error_remain = &b"xxx"[..]; +- let parsed_err = Vec::new(); +- let error_1 = &b"xxxabcabcdef"[..]; +- let parsed_err_1 = Vec::new(); +- let error_1_remain = &b"xxxabcabcdef"[..]; +- let error_2 = &b"abcxxxabcdef"[..]; +- let parsed_err_2 = Vec::new(); +- let error_2_remain = &b"abcxxxabcdef"[..]; +- +- assert_eq!(counter_2(done), Done(rest, parsed_done)); +- assert_eq!(counter_2(incomplete_1), Done(incomplete_1, parsed_incompl_1)); +- assert_eq!(counter_2(incomplete_2), Done(incomplete_2, parsed_incompl_2)); +- assert_eq!(counter_2(error), Done(error_remain, parsed_err)); +- assert_eq!(counter_2(error_1), Done(error_1_remain, parsed_err_1)); +- assert_eq!(counter_2(error_2), Done(error_2_remain, parsed_err_2)); +- } +- +- #[test] +- fn count_fixed() { +- const TIMES: usize = 2; +- named!( tag_abc, tag!("abc") ); +- named!( cnt_2<&[u8], [&[u8]; TIMES] >, count_fixed!(&[u8], tag_abc, TIMES ) ); +- +- assert_eq!(cnt_2(&b"abcabcabcdef"[..]), Done(&b"abcdef"[..], [&b"abc"[..], &b"abc"[..]])); +- assert_eq!(cnt_2(&b"ab"[..]), Incomplete(Needed::Unknown)); +- assert_eq!(cnt_2(&b"abcab"[..]), Incomplete(Needed::Unknown)); +- assert_eq!(cnt_2(&b"xxx"[..]), Error(Position(ErrorKind::Count, &b"xxx"[..]))); +- assert_eq!(cnt_2(&b"xxxabcabcdef"[..]), Error(Position(ErrorKind::Count, &b"xxxabcabcdef"[..]))); +- assert_eq!(cnt_2(&b"abcxxxabcdef"[..]), Error(Position(ErrorKind::Count, &b"abcxxxabcdef"[..]))); +- } +- +- use nom::{le_u16,eof}; +- #[allow(dead_code)] +- pub fn compile_count_fixed(input: &[u8]) -> IResult<&[u8], ()> { +- chain!(input, +- tag!("abcd") ~ +- count_fixed!( u16, le_u16, 4 ) ~ +- eof , +- || { () } +- ) +- } +- +- #[test] +- fn count_fixed_no_type() { +- const TIMES: usize = 2; +- named!( tag_abc, tag!("abc") ); +- named!( counter_2<&[u8], [&[u8]; TIMES], () >, count_fixed!(&[u8], tag_abc, TIMES ) ); +- +- let done = &b"abcabcabcdef"[..]; +- let parsed_main = [&b"abc"[..], &b"abc"[..]]; +- let rest = &b"abcdef"[..]; +- let incomplete_1 = &b"ab"[..]; +- let incomplete_2 = &b"abcab"[..]; +- let error = &b"xxx"[..]; +- let error_1 = &b"xxxabcabcdef"[..]; +- let error_1_remain = &b"xxxabcabcdef"[..]; +- let error_2 = &b"abcxxxabcdef"[..]; +- let error_2_remain = &b"abcxxxabcdef"[..]; +- +- assert_eq!(counter_2(done), Done(rest, parsed_main)); +- assert_eq!(counter_2(incomplete_1), Incomplete(Needed::Unknown)); +- assert_eq!(counter_2(incomplete_2), Incomplete(Needed::Unknown)); +- assert_eq!(counter_2(error), Error(Position(ErrorKind::Count, error))); +- assert_eq!(counter_2(error_1), Error(Position(ErrorKind::Count, error_1_remain))); +- assert_eq!(counter_2(error_2), Error(Position(ErrorKind::Count, error_2_remain))); +- } +- +- use nom::{be_u8,be_u16}; +- #[test] +- fn length_value_test() { +- named!(length_value_1<&[u8], Vec >, length_value!(be_u8, be_u16)); +- named!(length_value_2<&[u8], Vec >, length_value!(be_u8, be_u16, 2)); +- +- let i1 = vec![0, 5, 6]; +- assert_eq!(length_value_1(&i1), IResult::Done(&i1[1..], vec![])); +- assert_eq!(length_value_2(&i1), IResult::Done(&i1[1..], vec![])); +- +- let i2 = vec![1, 5, 6, 3]; +- assert_eq!(length_value_1(&i2), IResult::Done(&i2[3..], vec![1286])); +- assert_eq!(length_value_2(&i2), IResult::Done(&i2[3..], vec![1286])); +- +- let i3 = vec![2, 5, 6, 3, 4, 5, 7]; +- assert_eq!(length_value_1(&i3), IResult::Done(&i3[5..], vec![1286, 772])); +- assert_eq!(length_value_2(&i3), IResult::Done(&i3[5..], vec![1286, 772])); +- +- let i4 = vec![2, 5, 6, 3]; +- assert_eq!(length_value_1(&i4), IResult::Incomplete(Needed::Size(5))); +- assert_eq!(length_value_2(&i4), IResult::Incomplete(Needed::Size(5))); +- +- let i5 = vec![3, 5, 6, 3, 4, 5]; +- assert_eq!(length_value_1(&i5), IResult::Incomplete(Needed::Size(7))); +- assert_eq!(length_value_2(&i5), IResult::Incomplete(Needed::Size(7))); +- } +- +- #[test] +- fn fold_many0() { +- fn fold_into_vec(mut acc: Vec, item: T) -> Vec { +- acc.push(item); +- acc +- }; +- named!( tag_abcd, tag!("abcd") ); +- named!( tag_empty, tag!("") ); +- named!( multi<&[u8],Vec<&[u8]> >, fold_many0!(tag_abcd, Vec::new(), fold_into_vec) ); +- named!( multi_empty<&[u8],Vec<&[u8]> >, fold_many0!(tag_empty, Vec::new(), fold_into_vec) ); +- +- assert_eq!(multi(&b"abcdef"[..]), Done(&b"ef"[..], vec![&b"abcd"[..]])); +- assert_eq!(multi(&b"abcdabcdefgh"[..]), Done(&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])); +- assert_eq!(multi(&b"azerty"[..]), Done(&b"azerty"[..], Vec::new())); +- assert_eq!(multi(&b"abcdab"[..]), Incomplete(Needed::Size(8))); +- assert_eq!(multi(&b"abcd"[..]), Done(&b""[..], vec![&b"abcd"[..]])); +- assert_eq!(multi(&b""[..]), Done(&b""[..], Vec::new())); +- assert_eq!(multi_empty(&b"abcdef"[..]), Error(Position(ErrorKind::Many0, &b"abcdef"[..]))); +- } +- +- #[test] +- fn fold_many1() { +- fn fold_into_vec(mut acc: Vec, item: T) -> Vec { +- acc.push(item); +- acc +- }; +- named!(multi<&[u8],Vec<&[u8]> >, fold_many1!(tag!("abcd"), Vec::new(), fold_into_vec)); +- +- let a = &b"abcdef"[..]; +- let b = &b"abcdabcdefgh"[..]; +- let c = &b"azerty"[..]; +- let d = &b"abcdab"[..]; +- +- let res1 = vec![&b"abcd"[..]]; +- assert_eq!(multi(a), Done(&b"ef"[..], res1)); +- let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; +- assert_eq!(multi(b), Done(&b"efgh"[..], res2)); +- assert_eq!(multi(c), Error(Position(ErrorKind::Many1,c))); +- assert_eq!(multi(d), Incomplete(Needed::Size(8))); +- } +- +- #[test] +- fn fold_many_m_n() { +- fn fold_into_vec(mut acc: Vec, item: T) -> Vec { +- acc.push(item); +- acc +- }; +- named!(multi<&[u8],Vec<&[u8]> >, fold_many_m_n!(2, 4, tag!("Abcd"), Vec::new(), fold_into_vec)); +- +- let a = &b"Abcdef"[..]; +- let b = &b"AbcdAbcdefgh"[..]; +- let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; +- let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; +- let e = &b"AbcdAb"[..]; +- +- assert_eq!(multi(a), Error(Err::Position(ErrorKind::ManyMN,a))); +- let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; +- assert_eq!(multi(b), Done(&b"efgh"[..], res1)); +- let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; +- assert_eq!(multi(c), Done(&b"efgh"[..], res2)); +- let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; +- assert_eq!(multi(d), Done(&b"Abcdefgh"[..], res3)); +- assert_eq!(multi(e), Incomplete(Needed::Size(8))); +- } +- +- #[test] +- fn chain_incomplete() { +- let res = chain!(&b"abcdefgh"[..], +- a: take!(4) ~ +- b: take!(8), +- ||{(a,b )} +- ); +- +- assert_eq!(res, IResult::Incomplete(Needed::Size(12))); ++ assert_eq!(peek_tag(&b"xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); + } + +- #[test] +- fn tuple_test() { +- named!(tuple_3<&[u8], (u16, &[u8], &[u8]) >, +- tuple!( be_u16 , take!(3), tag!("fg") ) ); +- +- assert_eq!(tuple_3(&b"abcdefgh"[..]), Done(&b"h"[..], (0x6162u16, &b"cde"[..], &b"fg"[..]))); +- assert_eq!(tuple_3(&b"abcd"[..]), Incomplete(Needed::Size(5))); +- assert_eq!(tuple_3(&b"abcde"[..]), Incomplete(Needed::Size(7))); +- assert_eq!(tuple_3(&b"abcdejk"[..]), Error(Position(ErrorKind::Tag, &b"jk"[..]))); +- } +- + #[test] + fn not() { + named!(not_aaa, not!(tag!("aaa"))); +- assert_eq!(not_aaa(&b"aaa"[..]), Error(Position(ErrorKind::Not, &b"aaa"[..]))); ++ assert_eq!(not_aaa(&b"aaa"[..]), Error(error_position!(ErrorKind::Not, &b"aaa"[..]))); + assert_eq!(not_aaa(&b"aa"[..]), Done(&b"aa"[..], &b""[..])); + assert_eq!(not_aaa(&b"abcd"[..]), Done(&b"abcd"[..], &b""[..])); + } ++ ++ #[test] ++ fn verify() { ++ named!(test, verify!(take!(5), |slice: &[u8]| slice[0] == 'a' as u8)); ++ assert_eq!(test(&b"bcd"[..]), Incomplete(Needed::Size(5))); ++ assert_eq!(test(&b"bcdefg"[..]), Error(error_position!(ErrorKind::Verify, &b"bcdefg"[..]))); ++ assert_eq!(test(&b"abcdefg"[..]), Done(&b"fg"[..], &b"abcde"[..])); ++ } + } +diff --git third_party/rust/nom/src/methods.rs third_party/rust/nom/src/methods.rs +index 22868541a96c..7bdabfd063f3 100644 +--- third_party/rust/nom/src/methods.rs ++++ third_party/rust/nom/src/methods.rs +@@ -77,12 +77,12 @@ + //! counterparts: + //! ```ignore + //! method!(pub simple_chain<&mut Parser<'a>, &'a str, &'a str>, self, +-//! chain!( +-//! call_m!(self.tag_abc) ~ +-//! call_m!(self.tag_def) ~ +-//! call_m!(self.tag_ghi) ~ +-//! last: call_m!(self.simple_peek) , +-//! ||{sb.parsed = last; last} ++//! do_parse!( ++//! call_m!(self.tag_abc) >> ++//! call_m!(self.tag_def) >> ++//! call_m!(self.tag_ghi) >> ++//! last: map!(call_m!(self.simple_peek), |parsed| sb.parsed = parsed) >> ++//! (last) + //! ) + //! ); + //! ``` +@@ -107,30 +107,35 @@ + macro_rules! method ( + // Non-public immutable self + ($name:ident<$a:ty>( $i:ty ) -> $o:ty, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( +- fn $name<'a>( $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ #[allow(unused_variables)] ++ fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) +@@ -138,30 +143,35 @@ macro_rules! method ( + ); + // Public immutable self + (pub $name:ident<$a:ty>( $i:ty ) -> $o:ty, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( $self_: $a,i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( +- pub fn $name<'a>( $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ #[allow(unused_variables)] ++ pub fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) +@@ -169,30 +179,35 @@ macro_rules! method ( + ); + // Non-public mutable self + ($name:ident<$a:ty>( $i:ty ) -> $o:ty, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty,$i:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( +- fn $name<'a>( mut $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ #[allow(unused_variables)] ++ fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + ($name:ident<$a:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) +@@ -200,30 +215,35 @@ macro_rules! method ( + ); + // Public mutable self + (pub $name:ident<$a:ty>( $i:ty ) -> $o:ty, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty,$i:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( mut $self_: $a,i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( +- pub fn $name<'a>( mut $self_: $a, i: &'a[u8] ) -> ($a, $crate::IResult<&'a [u8], $o, u32>) { ++ #[allow(unused_variables)] ++ pub fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) + } + ); + (pub $name:ident<$a:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( ++ #[allow(unused_variables)] + pub fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { + let result = $submac!(i, $($args)*); + ($self_, result) +@@ -251,8 +271,8 @@ macro_rules! call_m ( + ); + + +-/// emulate function currying for method calls on structs +-/// `apply!(self.my_function, arg1, arg2, ...)` becomes `self.my_function(input, arg1, arg2, ...)` ++/// emulate function currying for method calls on structs ++/// `apply_m!(self.my_function, arg1, arg2, ...)` becomes `self.my_function(input, arg1, arg2, ...)` + /// + /// Supports up to 6 arguments + #[macro_export] +@@ -274,7 +294,7 @@ mod tests { + } else if ($i).starts_with($tag) { + $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()]) + } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagStr, $i)) ++ $crate::IResult::Error(error_position!($crate::ErrorKind::TagStr, $i)) + }; + res + } +@@ -325,10 +345,10 @@ mod tests { + peek!(call_m!(self.take3)) + ); + method!(pub simple_chain, &'a str, &'a str>, mut self, +- chain!( +- bcd: call_m!(self.tag_bcd) ~ +- last: call_m!(self.simple_peek) , +- ||{self.bcd = bcd; last} ++ do_parse!( ++ map!(call_m!(self.tag_bcd), |bcd| self.bcd = bcd) >> ++ last: call_m!(self.simple_peek) >> ++ (last) + ) + ); + fn tag_stuff(mut self: Parser<'a>, input: &'a str, something: &'a str) -> (Parser<'a>, ::IResult<&'a str, &'a str>) { +diff --git third_party/rust/nom/src/multi.rs third_party/rust/nom/src/multi.rs +new file mode 100644 +index 000000000000..f42164dcf2e3 +--- /dev/null ++++ third_party/rust/nom/src/multi.rs +@@ -0,0 +1,1614 @@ ++//! Parsers for applying parsers multiple times ++ ++/// `separated_list!(I -> IResult, I -> IResult) => I -> IResult>` ++/// separated_list(sep, X) returns Vec will return Incomplete if there may be more elements ++#[macro_export] ++macro_rules! separated_list( ++ ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ ++ //FIXME: use crate vec ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i.clone(); ++ ++ // get the first element ++ let input_ = input.clone(); ++ match $submac!(input_, $($args2)*) { ++ $crate::IResult::Error(_) => $crate::IResult::Done(input, ::std::vec::Vec::new()), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i,o) => { ++ if i.input_len() == input.input_len() { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::SeparatedList,input)) ++ } else { ++ res.push(o); ++ input = i; ++ ++ let ret; ++ ++ loop { ++ // get the separator first ++ let input_ = input.clone(); ++ match $sep!(input_, $($args)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(needed)) => { ++ let (size,overflowed) = needed.overflowing_add(($i).input_len() - input.input_len()); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i2,_) => { ++ let i2_len = i2.input_len(); ++ if i2_len == input.input_len() { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ ++ // get the element next ++ match $submac!(i2, $($args2)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(needed)) => { ++ let (size,overflowed) = needed.overflowing_add(($i).input_len() - i2_len); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i3,o3) => { ++ if i3.input_len() == i2_len { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ res.push(o3); ++ input = i3; ++ } ++ } ++ } ++ } ++ } ++ ++ ret ++ } ++ }, ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_list!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_list!($i, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ separated_list!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `separated_nonempty_list!(I -> IResult, I -> IResult) => I -> IResult>` ++/// separated_nonempty_list(sep, X) returns Vec will return Incomplete if there may be more elements ++#[macro_export] ++macro_rules! separated_nonempty_list( ++ ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i.clone(); ++ ++ // get the first element ++ let input_ = input.clone(); ++ match $submac!(input_, $($args2)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i,o) => { ++ if i.input_len() == input.len() { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::SeparatedNonEmptyList,input)) ++ } else { ++ res.push(o); ++ input = i; ++ ++ let ret; ++ ++ loop { ++ // get the separator first ++ let input_ = input.clone(); ++ match $sep!(input_, $($args)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(needed)) => { ++ let (size,overflowed) = needed.overflowing_add(($i).input_len() - input.input_len()); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i2,_) => { ++ let i2_len = i2.input_len(); ++ if i2_len == input.input_len() { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ ++ // get the element next ++ match $submac!(i2, $($args2)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(needed)) => { ++ let (size,overflowed) = needed.overflowing_add(($i).input_len() - i2_len); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i3,o3) => { ++ if i3.input_len() == i2_len { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ res.push(o3); ++ input = i3; ++ } ++ } ++ } ++ } ++ } ++ ++ ret ++ } ++ }, ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_nonempty_list!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_nonempty_list!($i, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ separated_nonempty_list!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `separated_list_complete!(I -> IResult, I -> IResult) => I -> IResult>` ++/// This is equivalent to the `separated_list!` combinator, except that it will return `Error` ++/// when either the separator or element subparser returns `Incomplete`. ++#[macro_export] ++macro_rules! separated_list_complete { ++ ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ({ ++ separated_list!($i, complete!($sep!($($args)*)), complete!($submac!($($args2)*))) ++ }); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_list_complete!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_list_complete!($i, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ separated_list_complete!($i, call!($f), call!($g)); ++ ); ++} ++ ++/// `separated_nonempty_list_complete!(I -> IResult, I -> IResult) => I -> IResult>` ++/// This is equivalent to the `separated_nonempty_list!` combinator, except that it will return ++/// `Error` when either the separator or element subparser returns `Incomplete`. ++#[macro_export] ++macro_rules! separated_nonempty_list_complete { ++ ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ({ ++ separated_nonempty_list!($i, complete!($sep!($($args)*)), complete!($submac!($($args2)*))) ++ }); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_nonempty_list_complete!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_nonempty_list_complete!($i, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ separated_nonempty_list_complete!($i, call!($f), call!($g)); ++ ); ++} ++ ++/// `many0!(I -> IResult) => I -> IResult>` ++/// Applies the parser 0 or more times and returns the list of results in a Vec ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, many0!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Done(&b"azerty"[..], Vec::new())); ++/// # } ++/// ``` ++/// 0 or more ++#[macro_export] ++macro_rules! many0( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ ++ let ret; ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i.clone(); ++ ++ loop { ++ if input.input_len() == 0 { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ ++ let input_ = input.clone(); ++ match $submac!(input_, $($args)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add(($i).input_len() - input.input_len()); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ // loop trip must always consume (otherwise infinite loops) ++ if i == input { ++ ret = $crate::IResult::Error(error_position!($crate::ErrorKind::Many0,input)); ++ break; ++ } ++ ++ res.push(o); ++ input = i; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ many0!($i, call!($f)); ++ ); ++); ++ ++/// `many1!(I -> IResult) => I -> IResult>` ++/// Applies the parser 1 or more times and returns the list of results in a Vec ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, many1!( tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Error(error_position!(ErrorKind::Many1,&b[..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! many1( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Error(_) => $crate::IResult::Error( ++ error_position!($crate::ErrorKind::Many1,$i) ++ ), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1,o1) => { ++ if i1.input_len() == 0 { ++ let mut res = ::std::vec::Vec::new(); ++ res.push(o1); ++ $crate::IResult::Done(i1,res) ++ } else { ++ ++ let mut res = ::std::vec::Vec::with_capacity(4); ++ res.push(o1); ++ let mut input = i1; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ++ ::std::option::Option::None; ++ loop { ++ if input.input_len() == 0 { ++ break; ++ } ++ let input_ = input.clone(); ++ match $submac!(input_, $($args)*) { ++ $crate::IResult::Error(_) => { ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add(($i).input_len() - input.input_len()); ++ incomplete = ::std::option::Option::Some( ++ match overflowed { ++ true => $crate::Needed::Unknown, ++ false => $crate::Needed::Size(size), ++ } ++ ); ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ res.push(o); ++ input = i; ++ } ++ } ++ } ++ ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, res) ++ } ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $f:expr) => ( ++ many1!($i, call!($f)); ++ ); ++); ++ ++/// `many_till!(I -> IResult, I -> IResult) => I -> IResult, P)>` ++/// Applies the first parser until the second applies. Returns a tuple containing the list ++/// of results from the first in a Vec and the result of the second. ++/// ++/// The first embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( tag!( "abcd" ), tag!( "efgh" ) ) ); ++/// ++/// let a = b"abcdabcdefghabcd"; ++/// let b = b"efghabcd"; ++/// let c = b"azerty"; ++/// ++/// let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]); ++/// let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]); ++/// assert_eq!(multi(&a[..]), Done(&b"abcd"[..], res_a)); ++/// assert_eq!(multi(&b[..]), Done(&b"abcd"[..], res_b)); ++/// assert_eq!(multi(&c[..]), Error(error_node_position!(ErrorKind::ManyTill,&c[..],error_position!(ErrorKind::Tag,&c[..])))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! many_till( ++ ($i:expr, $submac1:ident!( $($args1:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ ++ let ret; ++ let mut res = ::std::vec::Vec::new(); ++ let mut input = $i.clone(); ++ ++ loop { ++ match $submac2!(input, $($args2)*) { ++ $crate::IResult::Done(i, o) => { ++ ret = $crate::IResult::Done(i, (res, o)); ++ break; ++ }, ++ _ => { ++ match $submac1!(input, $($args1)*) { ++ $crate::IResult::Error(err) => { ++ ret = $crate::IResult::Error(error_node_position!($crate::ErrorKind::ManyTill,input, err)); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add(($i).input_len() - input.input_len()); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ // loop trip must always consume (otherwise infinite loops) ++ if i == input { ++ ret = $crate::IResult::Error(error_position!($crate::ErrorKind::ManyTill,input)); ++ break; ++ } ++ ++ res.push(o); ++ input = i; ++ }, ++ } ++ }, ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr, $g: expr) => ( ++ many_till!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `many_m_n!(usize, usize, I -> IResult) => I -> IResult>` ++/// Applies the parser between m and n times (n included) and returns the list of ++/// results in a Vec ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, tag!( "abcd" ) ) ); ++/// ++/// let a = b"abcdefgh"; ++/// let b = b"abcdabcdefgh"; ++/// let c = b"abcdabcdabcdabcdabcdefgh"; ++/// ++/// assert_eq!(multi(&a[..]),Error(error_position!(ErrorKind::ManyMN,&a[..]))); ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&b[..]), Done(&b"efgh"[..], res)); ++/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&c[..]), Done(&b"abcdefgh"[..], res2)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! many_m_n( ++ ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ use $crate::InputLength; ++ let mut res = ::std::vec::Vec::with_capacity($m); ++ let mut input = $i.clone(); ++ let mut count: usize = 0; ++ let mut err = false; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; ++ loop { ++ if count == $n { break } ++ let i_ = input.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Done(i, o) => { ++ // do not allow parsers that do not consume input (causes infinite loops) ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ res.push(o); ++ input = i; ++ count += 1; ++ } ++ $crate::IResult::Error(_) => { ++ err = true; ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add($i.input_len() - input.input_len()); ++ incomplete = ::std::option::Option::Some( ++ match overflowed { ++ true => $crate::Needed::Unknown, ++ false => $crate::Needed::Size(size), ++ } ++ ); ++ break; ++ }, ++ } ++ if input.input_len() == 0 { ++ break; ++ } ++ } ++ ++ if count < $m { ++ if err { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::ManyMN,$i)) ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Incomplete( ++ $crate::Needed::Unknown ++ ) ++ } ++ } ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, res) ++ } ++ } ++ } ++ ); ++ ($i:expr, $m:expr, $n: expr, $f:expr) => ( ++ many_m_n!($i, $m, $n, call!($f)); ++ ); ++); ++ ++/// `count!(I -> IResult, nb) => I -> IResult>` ++/// Applies the child parser a specified number of times ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(counter< Vec<&[u8]> >, count!( tag!( "abcd" ), 2 ) ); ++/// ++/// let a = b"abcdabcdabcdef"; ++/// let b = b"abcdefgh"; ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// ++/// assert_eq!(counter(&a[..]), Done(&b"abcdef"[..], res)); ++/// assert_eq!(counter(&b[..]), Error(error_position!(ErrorKind::Count, &b[..]))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! count( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $count: expr) => ( ++ { ++ let ret: $crate::IResult<_,_>; ++ let mut input = $i.clone(); ++ let mut res = ::std::vec::Vec::new(); ++ ++ loop { ++ if res.len() == $count { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ ++ let input_ = input.clone(); ++ match $submac!(input_, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ res.push(o); ++ input = i; ++ }, ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Error(error_position!($crate::ErrorKind::Count,$i)); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ } ++ $crate::IResult::Incomplete($crate::Needed::Size(sz)) => { ++ let (size,overflowed) = sz.overflowing_add( ++ $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input) ++ ); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr, $count: expr) => ( ++ count!($i, call!($f), $count); ++ ); ++); ++ ++/// `count_fixed!(O, I -> IResult, nb) => I -> IResult` ++/// Applies the child parser a fixed number of times and returns a fixed size array ++/// The type must be specified and it must be `Copy` ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done,Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(counter< [&[u8]; 2] >, count_fixed!( &[u8], tag!( "abcd" ), 2 ) ); ++/// // can omit the type specifier if returning slices ++/// // named!(counter< [&[u8]; 2] >, count_fixed!( tag!( "abcd" ), 2 ) ); ++/// ++/// let a = b"abcdabcdabcdef"; ++/// let b = b"abcdefgh"; ++/// let res = [&b"abcd"[..], &b"abcd"[..]]; ++/// ++/// assert_eq!(counter(&a[..]), Done(&b"abcdef"[..], res)); ++/// assert_eq!(counter(&b[..]), Error(error_position!(ErrorKind::Count, &b[..]))); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! count_fixed ( ++ ($i:expr, $typ:ty, $submac:ident!( $($args:tt)* ), $count: expr) => ( ++ { ++ let ret; ++ let mut input = $i.clone(); ++ // `$typ` must be Copy, and thus having no destructor, this is panic safe ++ let mut res: [$typ; $count] = unsafe{[::std::mem::uninitialized(); $count as usize]}; ++ let mut cnt: usize = 0; ++ ++ loop { ++ if cnt == $count { ++ ret = $crate::IResult::Done(input, res); break; ++ } ++ ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Done(i,o) => { ++ res[cnt] = o; ++ cnt += 1; ++ input = i; ++ }, ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Error(error_position!($crate::ErrorKind::Count,$i)); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ } ++ $crate::IResult::Incomplete($crate::Needed::Size(sz)) => { ++ let (size,overflowed) = sz.overflowing_add( ++ $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&input) ++ ); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ } ++ } ++ } ++ ++ ret ++ } ++); ++ ($i:expr, $typ: ty, $f:ident, $count: expr) => ( ++ count_fixed!($i, $typ, call!($f), $count); ++ ); ++); ++ ++/// `length_count!(I -> IResult, I -> IResult) => I -> IResult>` ++/// gets a number from the first parser, then applies the second parser that many times ++#[macro_export] ++macro_rules! length_count( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ match count!(i, $submac2!($($args2)*), o as usize) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(n)) => { ++ let (size,overflowed) = n.overflowing_add( ++ $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i) ++ ); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ } ++ }, ++ $crate::IResult::Done(i2, o2) => $crate::IResult::Done(i2, o2) ++ } ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ length_count!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ length_count!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ length_count!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `length_data!(I -> IResult) => O` ++/// ++/// `length_data` gets a number from the first parser, than takes a subslice of the input ++/// of that size, and returns that subslice ++#[macro_export] ++macro_rules! length_data( ++ ($i:expr, $submac:ident!( $($args:tt)* )) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ match take!(i, o as usize) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(n)) => { ++ let (size,overflowed) = n.overflowing_add( ++ $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i) ++ ); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ } ++ }, ++ $crate::IResult::Done(i2, o2) => $crate::IResult::Done(i2, o2) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $f:expr) => ( ++ length_data!($i, call!($f)); ++ ); ++); ++ ++/// `length_value!(I -> IResult, I -> IResult) => I -> IResult>` ++/// gets a number from the first parser, takes a subslice of the input of that size, ++/// then applies the second parser on that subslice. If the second parser returns ++/// `Incomplete`, `length_value` will return an error ++#[macro_export] ++macro_rules! length_value( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ match take!(i, o as usize) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(n)) => { ++ let (size,overflowed) = n.overflowing_add( ++ $crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i) ++ ); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ } ++ }, ++ $crate::IResult::Done(i2, o2) => { ++ match complete!(o2, $submac2!($($args2)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(_, o3) => $crate::IResult::Done(i2, o3) ++ } ++ } ++ } ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ length_value!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ length_value!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ length_value!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `fold_many0!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` ++/// Applies the parser 0 or more times and folds the list of return values ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, ++/// fold_many0!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { ++/// acc.push(item); ++/// acc ++/// })); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Done(&b"azerty"[..], Vec::new())); ++/// # } ++/// ``` ++/// 0 or more ++#[macro_export] ++macro_rules! fold_many0( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++ { ++ use $crate::InputLength; ++ let ret; ++ let f = $f; ++ let mut res = $init; ++ let mut input = $i.clone(); ++ ++ loop { ++ if input.input_len() == 0 { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ } ++ ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(_) => { ++ ret = $crate::IResult::Done(input, res); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ ret = $crate::IResult::Incomplete($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add( ($i).input_len() - input.input_len() ); ++ ret = match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(size)), ++ }; ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ // loop trip must always consume (otherwise infinite loops) ++ if i == input { ++ ret = $crate::IResult::Error( ++ error_position!($crate::ErrorKind::Many0,input) ++ ); ++ break; ++ } ++ ++ res = f(res, o); ++ input = i; ++ } ++ } ++ } ++ ++ ret ++ } ++ ); ++ ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( ++ fold_many0!($i, call!($f), $init, $fold_f); ++ ); ++); ++ ++/// `fold_many1!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` ++/// Applies the parser 1 or more times and folds the list of return values ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, ++/// fold_many1!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { ++/// acc.push(item); ++/// acc ++/// })); ++/// ++/// let a = b"abcdabcdefgh"; ++/// let b = b"azerty"; ++/// ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&a[..]), Done(&b"efgh"[..], res)); ++/// assert_eq!(multi(&b[..]), Error(error_position!(ErrorKind::Many1,&b[..]))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fold_many1( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++ { ++ use $crate::InputLength; ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(_) => $crate::IResult::Error( ++ error_position!($crate::ErrorKind::Many1,$i) ++ ), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1,o1) => { ++ let acc = $init; ++ let f = $f; ++ if i1.input_len() == 0 { ++ let acc = f(acc, o1); ++ $crate::IResult::Done(i1,acc) ++ } else { ++ let mut acc = f(acc, o1); ++ let mut input = i1; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ++ ::std::option::Option::None; ++ loop { ++ if input.input_len() == 0 { ++ break; ++ } ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Error(_) => { ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add( ($i).input_len() - input.input_len() ); ++ incomplete = ::std::option::Option::Some( ++ match overflowed { ++ true => $crate::Needed::Unknown, ++ false => $crate::Needed::Size(size), ++ } ++ ); ++ break; ++ }, ++ $crate::IResult::Done(i, o) => { ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ acc = f(acc, o); ++ input = i; ++ } ++ } ++ } ++ ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, acc) ++ } ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( ++ fold_many1!($i, call!($f), $init, $fold_f); ++ ); ++); ++ ++/// `fold_many_m_n!(usize, usize, I -> IResult, R, Fn(R, O) -> R) => I -> IResult` ++/// Applies the parser between m and n times (n included) and folds the list of return value ++/// ++/// the embedded parser may return Incomplete ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// named!(multi<&[u8], Vec<&[u8]> >, ++/// fold_many_m_n!(2, 4, tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| { ++/// acc.push(item); ++/// acc ++/// })); ++/// ++/// let a = b"abcdefgh"; ++/// let b = b"abcdabcdefgh"; ++/// let c = b"abcdabcdabcdabcdabcdefgh"; ++/// ++/// assert_eq!(multi(&a[..]),Error(error_position!(ErrorKind::ManyMN,&a[..]))); ++/// let res = vec![&b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&b[..]), Done(&b"efgh"[..], res)); ++/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; ++/// assert_eq!(multi(&c[..]), Done(&b"abcdefgh"[..], res2)); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fold_many_m_n( ++ ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* ), $init:expr, $f:expr) => ( ++ { ++ use $crate::InputLength; ++ let mut acc = $init; ++ let f = $f; ++ let mut input = $i.clone(); ++ let mut count: usize = 0; ++ let mut err = false; ++ let mut incomplete: ::std::option::Option<$crate::Needed> = ::std::option::Option::None; ++ loop { ++ if count == $n { break } ++ match $submac!(input, $($args)*) { ++ $crate::IResult::Done(i, o) => { ++ // do not allow parsers that do not consume input (causes infinite loops) ++ if i.input_len() == input.input_len() { ++ break; ++ } ++ acc = f(acc, o); ++ input = i; ++ count += 1; ++ } ++ $crate::IResult::Error(_) => { ++ err = true; ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => { ++ incomplete = ::std::option::Option::Some($crate::Needed::Unknown); ++ break; ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (size,overflowed) = i.overflowing_add( ($i).input_len() - input.input_len() ); ++ incomplete = ::std::option::Option::Some( ++ match overflowed { ++ true => $crate::Needed::Unknown, ++ false => $crate::Needed::Size(size), ++ } ++ ); ++ break; ++ }, ++ } ++ if input.input_len() == 0 { ++ break; ++ } ++ } ++ ++ if count < $m { ++ if err { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::ManyMN,$i)) ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Incomplete($crate::Needed::Unknown) ++ } ++ } ++ } else { ++ match incomplete { ++ ::std::option::Option::Some(i) => $crate::IResult::Incomplete(i), ++ ::std::option::Option::None => $crate::IResult::Done(input, acc) ++ } ++ } ++ } ++ ); ++ ($i:expr, $m:expr, $n: expr, $f:expr, $init:expr, $fold_f:expr) => ( ++ fold_many_m_n!($i, $m, $n, call!($f), $init, $fold_f); ++ ); ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::{Needed,IResult}; ++ ++ use internal::IResult::*; ++ use util::ErrorKind; ++ use nom::{alpha,be_u8,be_u16,le_u16,digit}; ++ use std::str::{self,FromStr}; ++ ++ // reproduce the tag and take macros, because of module import order ++ macro_rules! tag ( ++ ($i:expr, $inp: expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ ++ tag_bytes!($i,bytes) ++ } ++ ); ++ ); ++ ++ macro_rules! tag_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ use std::cmp::min; ++ let len = $i.len(); ++ let blen = $bytes.len(); ++ let m = min(len, blen); ++ let reduced = &$i[..m]; ++ let b = &$bytes[..m]; ++ ++ let res: $crate::IResult<_,_> = if reduced != b { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i)) ++ } else if m < blen { ++ $crate::IResult::Incomplete($crate::Needed::Size(blen)) ++ } else { ++ $crate::IResult::Done(&$i[blen..], reduced) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ macro_rules! take( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res:$crate::IResult<&[u8],&[u8]> = if $i.len() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ $crate::IResult::Done(&$i[cnt..],&$i[0..cnt]) ++ }; ++ res ++ } ++ ) ++ ); ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn separated_list() { ++ named!(multi<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!("abcd"))); ++ named!(multi_empty<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!(""))); ++ named!(multi_longsep<&[u8],Vec<&[u8]> >, separated_list!(tag!(".."), tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcd,abcdef"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b",,abc"[..]; ++ let e = &b"abcd,abcd,ef"[..]; ++ let f = &b"abc"[..]; ++ let g = &b"abcd."[..]; ++ let h = &b"abcd,abc"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"ef"[..], res2)); ++ assert_eq!(multi(c), Done(&b"azerty"[..], Vec::new())); ++ assert_eq!(multi_empty(d), Error(error_position!(ErrorKind::SeparatedList, d))); ++ //let res3 = vec![&b""[..], &b""[..], &b""[..]]; ++ //assert_eq!(multi_empty(d), Done(&b"abc"[..], res3)); ++ let res4 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(e), Done(&b",ef"[..], res4)); ++ ++ assert_eq!(multi(f), Incomplete(Needed::Size(4))); ++ assert_eq!(multi_longsep(g), Incomplete(Needed::Size(6))); ++ assert_eq!(multi(h), Incomplete(Needed::Size(9))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn separated_list_complete() { ++ named!(multi<&[u8],Vec<&[u8]> >, separated_list_complete!(tag!(","), alpha)); ++ let a = &b"abcdef"[..]; ++ let b = &b"abcd,abcdef"[..]; ++ let c = &b"abcd,abcd,ef"[..]; ++ let d = &b"abc."[..]; ++ let e = &b"abcd,ef."[..]; ++ let f = &b"123"[..]; ++ ++ assert_eq!(multi(a), Done(&b""[..], vec!(a))); ++ assert_eq!(multi(b), Done(&b""[..], vec!(&b"abcd"[..], &b"abcdef"[..]))); ++ assert_eq!(multi(c), Done(&b""[..], vec!(&b"abcd"[..], &b"abcd"[..], &b"ef"[..]))); ++ assert_eq!(multi(d), Done(&b"."[..], vec!(&b"abc"[..]))); ++ assert_eq!(multi(e), Done(&b"."[..], vec!(&b"abcd"[..], &b"ef"[..]))); ++ assert_eq!(multi(f), Done(&b"123"[..], Vec::new())); ++ } ++ ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn separated_nonempty_list() { ++ named!(multi<&[u8],Vec<&[u8]> >, separated_nonempty_list!(tag!(","), tag!("abcd"))); ++ named!(multi_longsep<&[u8],Vec<&[u8]> >, separated_nonempty_list!(tag!(".."), tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcd,abcdef"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b"abcd,abcd,ef"[..]; ++ ++ let f = &b"abc"[..]; ++ let g = &b"abcd."[..]; ++ let h = &b"abcd,abc"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"ef"[..], res2)); ++ assert_eq!(multi(c), Error(error_position!(ErrorKind::Tag,c))); ++ let res3 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(d), Done(&b",ef"[..], res3)); ++ ++ assert_eq!(multi(f), Incomplete(Needed::Size(4))); ++ assert_eq!(multi_longsep(g), Incomplete(Needed::Size(6))); ++ assert_eq!(multi(h), Incomplete(Needed::Size(9))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn separated_nonempty_list_complete() { ++ named!(multi<&[u8],Vec<&[u8]> >, separated_nonempty_list_complete!(tag!(","), alpha)); ++ let a = &b"abcdef"[..]; ++ let b = &b"abcd,abcdef"[..]; ++ let c = &b"abcd,abcd,ef"[..]; ++ let d = &b"abc."[..]; ++ let e = &b"abcd,ef."[..]; ++ let f = &b"123"[..]; ++ ++ assert_eq!(multi(a), Done(&b""[..], vec!(a))); ++ assert_eq!(multi(b), Done(&b""[..], vec!(&b"abcd"[..], &b"abcdef"[..]))); ++ assert_eq!(multi(c), Done(&b""[..], vec!(&b"abcd"[..], &b"abcd"[..], &b"ef"[..]))); ++ assert_eq!(multi(d), Done(&b"."[..], vec!(&b"abc"[..]))); ++ assert_eq!(multi(e), Done(&b"."[..], vec!(&b"abcd"[..], &b"ef"[..]))); ++ assert_eq!(multi(f), Error(error_position!(ErrorKind::Alpha, &b"123"[..]))); ++ } ++ ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn many0() { ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_empty, tag!("") ); ++ named!( multi<&[u8],Vec<&[u8]> >, many0!(tag_abcd) ); ++ named!( multi_empty<&[u8],Vec<&[u8]> >, many0!(tag_empty) ); ++ ++ assert_eq!(multi(&b"abcdef"[..]), Done(&b"ef"[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b"abcdabcdefgh"[..]), Done(&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])); ++ assert_eq!(multi(&b"azerty"[..]), Done(&b"azerty"[..], Vec::new())); ++ assert_eq!(multi(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(multi(&b"abcd"[..]), Done(&b""[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b""[..]), Done(&b""[..], Vec::new())); ++ assert_eq!(multi_empty(&b"abcdef"[..]), Error(error_position!(ErrorKind::Many0, &b"abcdef"[..]))); ++ } ++ ++ #[cfg(feature = "nightly")] ++ use test::Bencher; ++ ++ #[cfg(feature = "nightly")] ++ #[bench] ++ fn many0_bench(b: &mut Bencher) { ++ named!(multi<&[u8],Vec<&[u8]> >, many0!(tag!("abcd"))); ++ b.iter(|| { ++ multi(&b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"[..]) ++ }); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn many1() { ++ named!(multi<&[u8],Vec<&[u8]> >, many1!(tag!("abcd"))); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcdabcdefgh"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b"abcdab"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res2)); ++ assert_eq!(multi(c), Error(error_position!(ErrorKind::Many1,c))); ++ assert_eq!(multi(d), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn many_till() { ++ named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( tag!( "abcd" ), tag!( "efgh" ) ) ); ++ ++ let a = b"abcdabcdefghabcd"; ++ let b = b"efghabcd"; ++ let c = b"azerty"; ++ ++ let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]); ++ let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]); ++ assert_eq!(multi(&a[..]), Done(&b"abcd"[..], res_a)); ++ assert_eq!(multi(&b[..]), Done(&b"abcd"[..], res_b)); ++ assert_eq!(multi(&c[..]), Error(error_node_position!(ErrorKind::ManyTill,&c[..], error_position!(ErrorKind::Tag,&c[..])))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn infinite_many() { ++ fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { ++ println!("input: {:?}", input); ++ Error(error_position!(ErrorKind::Custom(0),input)) ++ } ++ ++ // should not go into an infinite loop ++ named!(multi0<&[u8],Vec<&[u8]> >, many0!(tst)); ++ let a = &b"abcdef"[..]; ++ assert_eq!(multi0(a), Done(a, Vec::new())); ++ ++ named!(multi1<&[u8],Vec<&[u8]> >, many1!(tst)); ++ let a = &b"abcdef"[..]; ++ assert_eq!(multi1(a), Error(error_position!(ErrorKind::Many1,a))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn many_m_n() { ++ named!(multi<&[u8],Vec<&[u8]> >, many_m_n!(2, 4, tag!("Abcd"))); ++ ++ let a = &b"Abcdef"[..]; ++ let b = &b"AbcdAbcdefgh"[..]; ++ let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; ++ let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; ++ let e = &b"AbcdAb"[..]; ++ ++ assert_eq!(multi(a), Error(error_position!(ErrorKind::ManyMN,a))); ++ let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res1)); ++ let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(c), Done(&b"efgh"[..], res2)); ++ let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(d), Done(&b"Abcdefgh"[..], res3)); ++ assert_eq!(multi(e), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn count() { ++ const TIMES: usize = 2; ++ named!( tag_abc, tag!("abc") ); ++ named!( cnt_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) ); ++ ++ assert_eq!(cnt_2(&b"abcabcabcdef"[..]), Done(&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]])); ++ assert_eq!(cnt_2(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(cnt_2(&b"abcab"[..]), Incomplete(Needed::Size(6))); ++ assert_eq!(cnt_2(&b"xxx"[..]), Error(error_position!(ErrorKind::Count, &b"xxx"[..]))); ++ assert_eq!(cnt_2(&b"xxxabcabcdef"[..]), Error(error_position!(ErrorKind::Count, &b"xxxabcabcdef"[..]))); ++ assert_eq!(cnt_2(&b"abcxxxabcdef"[..]), Error(error_position!(ErrorKind::Count, &b"abcxxxabcdef"[..]))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn count_zero() { ++ const TIMES: usize = 0; ++ named!( tag_abc, tag!("abc") ); ++ named!( counter_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) ); ++ ++ let done = &b"abcabcabcdef"[..]; ++ let parsed_done = Vec::new(); ++ let rest = done; ++ let incomplete_1 = &b"ab"[..]; ++ let parsed_incompl_1 = Vec::new(); ++ let incomplete_2 = &b"abcab"[..]; ++ let parsed_incompl_2 = Vec::new(); ++ let error = &b"xxx"[..]; ++ let error_remain = &b"xxx"[..]; ++ let parsed_err = Vec::new(); ++ let error_1 = &b"xxxabcabcdef"[..]; ++ let parsed_err_1 = Vec::new(); ++ let error_1_remain = &b"xxxabcabcdef"[..]; ++ let error_2 = &b"abcxxxabcdef"[..]; ++ let parsed_err_2 = Vec::new(); ++ let error_2_remain = &b"abcxxxabcdef"[..]; ++ ++ assert_eq!(counter_2(done), Done(rest, parsed_done)); ++ assert_eq!(counter_2(incomplete_1), Done(incomplete_1, parsed_incompl_1)); ++ assert_eq!(counter_2(incomplete_2), Done(incomplete_2, parsed_incompl_2)); ++ assert_eq!(counter_2(error), Done(error_remain, parsed_err)); ++ assert_eq!(counter_2(error_1), Done(error_1_remain, parsed_err_1)); ++ assert_eq!(counter_2(error_2), Done(error_2_remain, parsed_err_2)); ++ } ++ ++ #[test] ++ fn count_fixed() { ++ const TIMES: usize = 2; ++ named!( tag_abc, tag!("abc") ); ++ named!( cnt_2<&[u8], [&[u8]; TIMES] >, count_fixed!(&[u8], tag_abc, TIMES ) ); ++ ++ assert_eq!(cnt_2(&b"abcabcabcdef"[..]), Done(&b"abcdef"[..], [&b"abc"[..], &b"abc"[..]])); ++ assert_eq!(cnt_2(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(cnt_2(&b"abcab"[..]), Incomplete(Needed::Size(6))); ++ assert_eq!(cnt_2(&b"xxx"[..]), Error(error_position!(ErrorKind::Count, &b"xxx"[..]))); ++ assert_eq!(cnt_2(&b"xxxabcabcdef"[..]), Error(error_position!(ErrorKind::Count, &b"xxxabcabcdef"[..]))); ++ assert_eq!(cnt_2(&b"abcxxxabcdef"[..]), Error(error_position!(ErrorKind::Count, &b"abcxxxabcdef"[..]))); ++ } ++ ++ #[allow(dead_code)] ++ pub fn compile_count_fixed(input: &[u8]) -> IResult<&[u8], ()> { ++ do_parse!(input, ++ tag!("abcd") >> ++ count_fixed!( u16, le_u16, 4 ) >> ++ eof!() >> ++ () ++ ) ++ } ++ ++ #[allow(unused_variables)] ++ #[test] ++ fn count_fixed_no_type() { ++ const TIMES: usize = 2; ++ named!( tag_abc, tag!("abc") ); ++ named!( counter_2<&[u8], [&[u8]; TIMES], () >, count_fixed!(&[u8], tag_abc, TIMES ) ); ++ ++ let done = &b"abcabcabcdef"[..]; ++ let parsed_main = [&b"abc"[..], &b"abc"[..]]; ++ let rest = &b"abcdef"[..]; ++ let incomplete_1 = &b"ab"[..]; ++ let incomplete_2 = &b"abcab"[..]; ++ let error = &b"xxx"[..]; ++ let error_1 = &b"xxxabcabcdef"[..]; ++ let error_1_remain = &b"xxxabcabcdef"[..]; ++ let error_2 = &b"abcxxxabcdef"[..]; ++ let error_2_remain = &b"abcxxxabcdef"[..]; ++ ++ assert_eq!(counter_2(done), Done(rest, parsed_main)); ++ assert_eq!(counter_2(incomplete_1), Incomplete(Needed::Size(3))); ++ assert_eq!(counter_2(incomplete_2), Incomplete(Needed::Size(6))); ++ assert_eq!(counter_2(error), Error(error_position!(ErrorKind::Count, error))); ++ assert_eq!(counter_2(error_1), Error(error_position!(ErrorKind::Count, error_1_remain))); ++ assert_eq!(counter_2(error_2), Error(error_position!(ErrorKind::Count, error_2_remain))); ++ } ++ ++ named!(pub number, map_res!( ++ map_res!( ++ digit, ++ str::from_utf8 ++ ), ++ FromStr::from_str ++ )); ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn length_count() { ++ named!(tag_abc, tag!(&b"abc"[..]) ); ++ named!( cnt<&[u8], Vec<&[u8]> >, length_count!(number, tag_abc) ); ++ ++ assert_eq!(cnt(&b"2abcabcabcdef"[..]), Done(&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]])); ++ assert_eq!(cnt(&b"2ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(cnt(&b"3abcab"[..]), Incomplete(Needed::Size(7))); ++ assert_eq!(cnt(&b"xxx"[..]), Error(error_position!(ErrorKind::Digit, &b"xxx"[..]))); ++ assert_eq!(cnt(&b"2abcxxx"[..]), Error(error_position!(ErrorKind::Count, &b"abcxxx"[..]))); ++ } ++ ++ #[test] ++ fn length_data() { ++ named!( take<&[u8], &[u8]>, length_data!(number) ); ++ ++ assert_eq!(take(&b"6abcabcabcdef"[..]), Done(&b"abcdef"[..], &b"abcabc"[..])); ++ assert_eq!(take(&b"3ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(take(&b"xxx"[..]), Error(error_position!(ErrorKind::Digit, &b"xxx"[..]))); ++ assert_eq!(take(&b"2abcxxx"[..]), Done(&b"cxxx"[..], &b"ab"[..])); ++ } ++ ++ #[test] ++ fn length_value_test() { ++ named!(length_value_1<&[u8], u16 >, length_value!(be_u8, be_u16)); ++ named!(length_value_2<&[u8], (u8, u8) >, length_value!(be_u8, tuple!(be_u8, be_u8))); ++ ++ let i1 = [0, 5, 6]; ++ assert_eq!(length_value_1(&i1), IResult::Error(error_position!(ErrorKind::Complete, &b""[..]))); ++ assert_eq!(length_value_2(&i1), IResult::Error(error_position!(ErrorKind::Complete, &b""[..]))); ++ ++ let i2 = [1, 5, 6, 3]; ++ assert_eq!(length_value_1(&i2), IResult::Error(error_position!(ErrorKind::Complete, &i2[1..2]))); ++ assert_eq!(length_value_2(&i2), IResult::Error(error_position!(ErrorKind::Complete, &i2[1..2]))); ++ ++ let i3 = [2, 5, 6, 3, 4, 5, 7]; ++ assert_eq!(length_value_1(&i3), IResult::Done(&i3[3..], 1286)); ++ assert_eq!(length_value_2(&i3), IResult::Done(&i3[3..], (5, 6))); ++ ++ let i4 = [3, 5, 6, 3, 4, 5]; ++ assert_eq!(length_value_1(&i4), IResult::Done(&i4[4..], 1286)); ++ assert_eq!(length_value_2(&i4), IResult::Done(&i4[4..], (5, 6))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn fold_many0() { ++ fn fold_into_vec(mut acc: Vec, item: T) -> Vec { ++ acc.push(item); ++ acc ++ }; ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_empty, tag!("") ); ++ named!( multi<&[u8],Vec<&[u8]> >, fold_many0!(tag_abcd, Vec::new(), fold_into_vec) ); ++ named!( multi_empty<&[u8],Vec<&[u8]> >, fold_many0!(tag_empty, Vec::new(), fold_into_vec) ); ++ ++ assert_eq!(multi(&b"abcdef"[..]), Done(&b"ef"[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b"abcdabcdefgh"[..]), Done(&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])); ++ assert_eq!(multi(&b"azerty"[..]), Done(&b"azerty"[..], Vec::new())); ++ assert_eq!(multi(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(multi(&b"abcd"[..]), Done(&b""[..], vec![&b"abcd"[..]])); ++ assert_eq!(multi(&b""[..]), Done(&b""[..], Vec::new())); ++ assert_eq!(multi_empty(&b"abcdef"[..]), Error(error_position!(ErrorKind::Many0, &b"abcdef"[..]))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn fold_many1() { ++ fn fold_into_vec(mut acc: Vec, item: T) -> Vec { ++ acc.push(item); ++ acc ++ }; ++ named!(multi<&[u8],Vec<&[u8]> >, fold_many1!(tag!("abcd"), Vec::new(), fold_into_vec)); ++ ++ let a = &b"abcdef"[..]; ++ let b = &b"abcdabcdefgh"[..]; ++ let c = &b"azerty"[..]; ++ let d = &b"abcdab"[..]; ++ ++ let res1 = vec![&b"abcd"[..]]; ++ assert_eq!(multi(a), Done(&b"ef"[..], res1)); ++ let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res2)); ++ assert_eq!(multi(c), Error(error_position!(ErrorKind::Many1,c))); ++ assert_eq!(multi(d), Incomplete(Needed::Size(8))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn fold_many_m_n() { ++ fn fold_into_vec(mut acc: Vec, item: T) -> Vec { ++ acc.push(item); ++ acc ++ }; ++ named!(multi<&[u8],Vec<&[u8]> >, fold_many_m_n!(2, 4, tag!("Abcd"), Vec::new(), fold_into_vec)); ++ ++ let a = &b"Abcdef"[..]; ++ let b = &b"AbcdAbcdefgh"[..]; ++ let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; ++ let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; ++ let e = &b"AbcdAb"[..]; ++ ++ assert_eq!(multi(a), Error(error_position!(ErrorKind::ManyMN,a))); ++ let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(b), Done(&b"efgh"[..], res1)); ++ let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(c), Done(&b"efgh"[..], res2)); ++ let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; ++ assert_eq!(multi(d), Done(&b"Abcdefgh"[..], res3)); ++ assert_eq!(multi(e), Incomplete(Needed::Size(8))); ++ } ++ ++} +diff --git third_party/rust/nom/src/nom.rs third_party/rust/nom/src/nom.rs +index 74bac5bfb0c4..7f48afc511bd 100644 +--- third_party/rust/nom/src/nom.rs ++++ third_party/rust/nom/src/nom.rs +@@ -6,16 +6,18 @@ + //! but the macros system makes no promises. + //! + +-#[cfg(feature = "core")] ++#[cfg(not(feature = "std"))] + use std::prelude::v1::*; + use std::boxed::Box; + + use std::fmt::Debug; + use internal::*; + use internal::IResult::*; +-use internal::Err::*; +-use util::{ErrorKind,IterIndices,AsChar,InputLength}; ++use util::ErrorKind; ++use traits::{AsChar,InputLength,InputIter}; + use std::mem::transmute; ++use std::ops::{Range,RangeFrom,RangeTo}; ++use traits::{Compare,CompareResult,Slice}; + + #[inline] + pub fn tag_cl<'a,'b>(rec:&'a[u8]) -> Box IResult<&'b[u8], &'b[u8]> + 'a> { +@@ -23,12 +25,12 @@ pub fn tag_cl<'a,'b>(rec:&'a[u8]) -> Box IResult<&'b[u8], &'b[u8 + if i.len() >= rec.len() && &i[0..rec.len()] == rec { + Done(&i[rec.len()..], &i[0..rec.len()]) + } else { +- Error(Position(ErrorKind::TagClosure, i)) ++ Error(error_position!(ErrorKind::TagClosure, i)) + } + }) + } + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] + #[inline] + pub fn print(input: T) -> IResult { + println!("{:?}", input); +@@ -40,38 +42,89 @@ pub fn begin(input: &[u8]) -> IResult<(), &[u8]> { + Done((), input) + } + ++pub fn crlf(input:T) -> IResult where ++ T:Slice>+Slice>+Slice>, ++ T: InputIter, ++ T: Compare<&'static str> { ++ match input.compare("\r\n") { ++ //FIXME: is this the right index? ++ CompareResult::Ok => { ++ IResult::Done(input.slice(2..), input.slice(0..2)) ++ }, ++ CompareResult::Incomplete => IResult::Incomplete(Needed::Size(2)), ++ CompareResult::Error => IResult::Error(error_position!(ErrorKind::CrLf, input)) ++ } ++} ++ + // FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export + // public methods +-//pub is_not!(line_ending b"\r\n") +-pub fn not_line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> { +- for (idx, item) in input.iter().enumerate() { +- for &i in b"\r\n".iter() { +- if *item == i { +- return Done(&input[idx..], &input[0..idx]) ++pub fn not_line_ending(input:T) -> IResult where ++ T:Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ T: Compare<&'static str>, ++ ::Item: AsChar { ++ match input.iter_elements().position(|item| { ++ let c = item.as_char(); ++ c == '\r' || c == '\n' ++ }) { ++ None => Done(input.slice(input.input_len()..), input), ++ Some(index) => { ++ let mut it = input.iter_elements(); ++ let nth = it.nth(index).unwrap().as_char(); ++ if nth == '\r' { ++ let sliced = input.slice(index..); ++ let comp = sliced.compare("\r\n"); ++ match comp { ++ //FIXME: calculate the right index ++ CompareResult::Incomplete => Incomplete(Needed::Unknown), ++ CompareResult::Error => Error(error_position!(ErrorKind::Tag, input)), ++ CompareResult::Ok => Done(input.slice(index..), input.slice(..index)) ++ } ++ } else { ++ Done(input.slice(index..), input.slice(..index)) ++ } ++ } + } ++} ++ ++/// Recognizes an end of line (both '\n' and '\r\n') ++pub fn line_ending(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ T: Compare<&'static str> { ++ ++ match input.compare("\n") { ++ CompareResult::Ok => Done(input.slice(1..), input.slice(0..1)), ++ CompareResult::Incomplete => Incomplete(Needed::Size(1)), ++ CompareResult::Error => match input.compare("\r\n") { ++ //FIXME: is this the right index? ++ CompareResult::Ok => Done(input.slice(2..), input.slice(0..2)), ++ CompareResult::Incomplete => Incomplete(Needed::Size(2)), ++ CompareResult::Error => Error(error_position!(ErrorKind::CrLf, input)) + } + } +- Done(&input[input.len()..], input) + } + +-named!(tag_ln, tag!("\n")); +- +-/// Recognizes a line feed +-#[inline] +-pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> { +- tag_ln(input) ++pub fn eol(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ T: Compare<&'static str> { ++ line_ending(input) + } + ++/// Tests if byte is ASCII alphabetic: A-Z, a-z + #[inline] + pub fn is_alphabetic(chr:u8) -> bool { + (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A) + } + ++/// Tests if byte is ASCII digit: 0-9 + #[inline] + pub fn is_digit(chr: u8) -> bool { + chr >= 0x30 && chr <= 0x39 + } + ++/// Tests if byte is ASCII hex digit: 0-9, A-F, a-f + #[inline] + pub fn is_hex_digit(chr: u8) -> bool { + (chr >= 0x30 && chr <= 0x39) || +@@ -79,16 +132,19 @@ pub fn is_hex_digit(chr: u8) -> bool { + (chr >= 0x61 && chr <= 0x66) + } + ++/// Tests if byte is ASCII octal digit: 0-7 + #[inline] + pub fn is_oct_digit(chr: u8) -> bool { + chr >= 0x30 && chr <= 0x37 + } + ++/// Tests if byte is ASCII alphanumeric: A-Z, a-z, 0-9 + #[inline] + pub fn is_alphanumeric(chr: u8) -> bool { + is_alphabetic(chr) || is_digit(chr) + } + ++/// Tests if byte is ASCII space or tab + #[inline] + pub fn is_space(chr:u8) -> bool { + chr == ' ' as u8 || chr == '\t' as u8 +@@ -101,154 +157,160 @@ pub fn is_space(chr:u8) -> bool { + //pub filter!(oct_digit is_oct_digit) + //pub filter!(alphanumeric is_alphanumeric) + +-use std::ops::{Index,Range,RangeFrom}; +-/// Recognizes lowercase and uppercase alphabetic characters: a-zA-Z +-pub fn alpha<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more lowercase and uppercase alphabetic characters: a-zA-Z ++pub fn alpha(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::Alpha, input)) ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { + if ! item.is_alpha() { + if idx == 0 { +- return Error(Position(ErrorKind::Alpha, input)) ++ return Error(error_position!(ErrorKind::Alpha, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + +-/// Recognizes numerical characters: 0-9 +-pub fn digit<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more numerical characters: 0-9 ++pub fn digit(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::Digit, input)) ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { +- if ! item.is_0_to_9() { ++ if ! item.is_dec_digit() { + if idx == 0 { +- return Error(Position(ErrorKind::Digit, input)) ++ return Error(error_position!(ErrorKind::Digit, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + +-/// Recognizes hexadecimal numerical characters: 0-9, A-F, a-f +-pub fn hex_digit<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more hexadecimal numerical characters: 0-9, A-F, a-f ++pub fn hex_digit(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::HexDigit, input)) ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { + if ! item.is_hex_digit() { + if idx == 0 { +- return Error(Position(ErrorKind::HexDigit, input)) ++ return Error(error_position!(ErrorKind::HexDigit, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + +-/// Recognizes octal characters: 0-7 +-pub fn oct_digit<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more octal characters: 0-7 ++pub fn oct_digit(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::OctDigit, input)) ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { + if ! item.is_oct_digit() { + if idx == 0 { +- return Error(Position(ErrorKind::OctDigit, input)) ++ return Error(error_position!(ErrorKind::OctDigit, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + +-/// Recognizes numerical and alphabetic characters: 0-9a-zA-Z +-pub fn alphanumeric<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more numerical and alphabetic characters: 0-9a-zA-Z ++pub fn alphanumeric(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::AlphaNumeric, input)); ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { + if ! item.is_alphanum() { + if idx == 0 { +- return Error(Position(ErrorKind::AlphaNumeric, input)) ++ return Error(error_position!(ErrorKind::AlphaNumeric, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + +-/// Recognizes spaces and tabs +-pub fn space<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more spaces and tabs ++pub fn space(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::Space, input)); ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { + let chr = item.as_char(); + if ! (chr == ' ' || chr == '\t') { + if idx == 0 { +- return Error(Position(ErrorKind::Space, input)) ++ return Error(error_position!(ErrorKind::Space, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + +-/// Recognizes spaces, tabs, carriage returns and line feeds +-pub fn multispace<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, &'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: IterIndices+InputLength { ++/// Recognizes one or more spaces, tabs, carriage returns and line feeds ++pub fn multispace(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputIter+InputLength, ++ ::Item: AsChar { + let input_length = input.input_len(); + if input_length == 0 { +- return Error(Position(ErrorKind::MultiSpace, input)); ++ return Incomplete(Needed::Unknown); + } + + for (idx, item) in input.iter_indices() { + let chr = item.as_char(); + if ! (chr == ' ' || chr == '\t' || chr == '\r' || chr == '\n') { + if idx == 0 { +- return Error(Position(ErrorKind::MultiSpace, input)) ++ return Error(error_position!(ErrorKind::MultiSpace, input)) + } else { +- return Done(&input[idx..], &input[0..idx]) ++ return Done(input.slice(idx..), input.slice(0..idx)) + } + } + } +- Done(&input[input_length..], input) ++ Done(input.slice(input_length..), input) + } + + pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> { +@@ -265,20 +327,6 @@ pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> { + } + } + +-pub fn length_value(input:&[u8]) -> IResult<&[u8], &[u8]> { +- let input_len = input.len(); +- if input_len == 0 { +- return Error(Position(ErrorKind::LengthValueFn, input)) +- } +- +- let len = input[0] as usize; +- if input_len - 1 >= len { +- IResult::Done(&input[len+1..], &input[1..len+1]) +- } else { +- IResult::Incomplete(Needed::Size(1+len)) +- } +-} +- + /// Recognizes an unsigned 1 byte integer (equivalent to take!(1) + #[inline] + pub fn be_u8(i: &[u8]) -> IResult<&[u8], u8> { +@@ -300,6 +348,17 @@ pub fn be_u16(i: &[u8]) -> IResult<&[u8], u16> { + } + } + ++/// Recognizes big endian unsigned 3 byte integer ++#[inline] ++pub fn be_u24(i: &[u8]) -> IResult<&[u8], u32> { ++ if i.len() < 3 { ++ Incomplete(Needed::Size(3)) ++ } else { ++ let res = ((i[0] as u32) << 16) + ((i[1] as u32) << 8) + (i[2] as u32); ++ Done(&i[3..], res) ++ } ++} ++ + /// Recognizes big endian unsigned 4 bytes integer + #[inline] + pub fn be_u32(i: &[u8]) -> IResult<&[u8], u32> { +@@ -335,6 +394,13 @@ pub fn be_i16(i:&[u8]) -> IResult<&[u8], i16> { + map!(i, be_u16, | x | { x as i16 }) + } + ++/// Recognizes big endian signed 3 bytes integer ++#[inline] ++pub fn be_i24(i: &[u8]) -> IResult<&[u8], i32> { ++ // Same as the unsigned version but we need to sign-extend manually here ++ map!(i, be_u24, | x | if x & 0x80_00_00 != 0 { (x | 0xff_00_00_00) as i32 } else { x as i32 }) ++} ++ + /// Recognizes big endian signed 4 bytes integer + #[inline] + pub fn be_i32(i:&[u8]) -> IResult<&[u8], i32> { +@@ -368,6 +434,17 @@ pub fn le_u16(i: &[u8]) -> IResult<&[u8], u16> { + } + } + ++/// Recognizes little endian unsigned 3 byte integer ++#[inline] ++pub fn le_u24(i: &[u8]) -> IResult<&[u8], u32> { ++ if i.len() < 3 { ++ Incomplete(Needed::Size(3)) ++ } else { ++ let res = (i[0] as u32) + ((i[1] as u32) << 8) + ((i[2] as u32) << 16); ++ Done(&i[3..], res) ++ } ++} ++ + /// Recognizes little endian unsigned 4 bytes integer + #[inline] + pub fn le_u32(i: &[u8]) -> IResult<&[u8], u32> { +@@ -403,6 +480,13 @@ pub fn le_i16(i:&[u8]) -> IResult<&[u8], i16> { + map!(i, le_u16, | x | { x as i16 }) + } + ++/// Recognizes little endian signed 3 bytes integer ++#[inline] ++pub fn le_i24(i: &[u8]) -> IResult<&[u8], i32> { ++ // Same as the unsigned version but we need to sign-extend manually here ++ map!(i, le_u24, | x | if x & 0x80_00_00 != 0 { (x | 0xff_00_00_00) as i32 } else { x as i32 }) ++} ++ + /// Recognizes little endian signed 4 bytes integer + #[inline] + pub fn le_i32(i:&[u8]) -> IResult<&[u8], i32> { +@@ -415,31 +499,38 @@ pub fn le_i64(i:&[u8]) -> IResult<&[u8], i64> { + map!(i, le_u64, | x | { x as i64 }) + } + +-/// if parameter is true, parse a big endian u16 integer, ++/// Configurable endianness ++#[derive(Debug,PartialEq,Eq,Clone,Copy)] ++pub enum Endianness { ++ Big, ++ Little, ++} ++ ++/// if the parameter is nom::Endianness::Big, parse a big endian u16 integer, + /// otherwise a little endian u16 integer + #[macro_export] +-macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_u16($i) } else { $crate::le_u16($i) } } );); +-/// if parameter is true, parse a big endian u32 integer, ++macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u16($i) } else { $crate::le_u16($i) } } );); ++/// if the parameter is nom::Endianness::Big, parse a big endian u32 integer, + /// otherwise a little endian u32 integer + #[macro_export] +-macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_u32($i) } else { $crate::le_u32($i) } } );); +-/// if parameter is true, parse a big endian u64 integer, ++macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u32($i) } else { $crate::le_u32($i) } } );); ++/// if the parameter is nom::Endianness::Big, parse a big endian u64 integer, + /// otherwise a little endian u64 integer + #[macro_export] +-macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_u64($i) } else { $crate::le_u64($i) } } );); ++macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u64($i) } else { $crate::le_u64($i) } } );); + +-/// if parameter is true, parse a big endian i16 integer, ++/// if the parameter is nom::Endianness::Big, parse a big endian i16 integer, + /// otherwise a little endian i16 integer + #[macro_export] +-macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_i16($i) } else { $crate::le_i16($i) } } );); +-/// if parameter is true, parse a big endian i32 integer, ++macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i16($i) } else { $crate::le_i16($i) } } );); ++/// if the parameter is nom::Endianness::Big, parse a big endian i32 integer, + /// otherwise a little endian i32 integer + #[macro_export] +-macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_i32($i) } else { $crate::le_i32($i) } } );); +-/// if parameter is true, parse a big endian i64 integer, ++macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i32($i) } else { $crate::le_i32($i) } } );); ++/// if the parameter is nom::Endianness::Big, parse a big endian i64 integer, + /// otherwise a little endian i64 integer + #[macro_export] +-macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $e { $crate::be_i64($i) } else { $crate::le_i64($i) } } );); ++macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i64($i) } else { $crate::le_i64($i) } } );); + + /// Recognizes big endian 4 bytes floating point number + #[inline] +@@ -500,7 +591,7 @@ pub fn le_f64(input: &[u8]) -> IResult<&[u8], f64> { + /// Recognizes a hex-encoded integer + #[inline] + pub fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { +- match is_a!(input, &b"0123456789abcdef"[..]) { ++ match is_a!(input, &b"0123456789abcdefABCDEF"[..]) { + Error(e) => Error(e), + Incomplete(e) => Incomplete(e), + Done(i,o) => { +@@ -524,30 +615,15 @@ pub fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { + } + } + +-/// Recognizes empty input buffers +-/// +-/// useful to verify that the previous parsers used all of the input +-#[inline] +-//pub fn eof(input:&[u8]) -> IResult<&[u8], &[u8]> { +-pub fn eof<'a, T:?Sized>(input: &'a T) -> IResult<&'a T,&'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: InputLength { +- if input.input_len() == 0 { +- Done(input, input) +- } else { +- Error(Position(ErrorKind::Eof, input)) +- } +-} +- + /// Recognizes non empty buffers + #[inline] +-pub fn non_empty<'a, T:?Sized>(input: &'a T) -> IResult<&'a T,&'a T> where +- T:Index, Output=T>+Index, Output=T>, +- &'a T: InputLength { ++pub fn non_empty(input:T) -> IResult where ++ T: Slice>+Slice>+Slice>, ++ T: InputLength { + if input.input_len() == 0 { +- Error(Position(ErrorKind::NonEmpty, input)) ++ Error(error_position!(ErrorKind::NonEmpty, input)) + } else { +- Done(&input[input.input_len()..], input) ++ Done(input.slice(input.input_len()..), input) + } + } + +@@ -563,12 +639,102 @@ pub fn rest_s(input: &str) -> IResult<&str, &str> { + IResult::Done(&input[input.len()..], input) + } + ++/// Recognizes floating point number in a byte string and returns a f32 ++#[cfg(feature = "std")] ++pub fn float(input: &[u8]) -> IResult<&[u8],f32> { ++ flat_map!(input, ++ recognize!( ++ tuple!( ++ opt!(alt!(tag!("+") | tag!("-"))), ++ alt!( ++ delimited!(digit, tag!("."), opt!(digit)) ++ | delimited!(opt!(digit), tag!("."), digit) ++ ), ++ opt!(complete!(tuple!( ++ alt!(tag!("e") | tag!("E")), ++ opt!(alt!(tag!("+") | tag!("-"))), ++ digit ++ ) ++ )) ++ ) ++ ), ++ parse_to!(f32) ++ ) ++} ++ ++/// Recognizes floating point number in a string and returns a f32 ++#[cfg(feature = "std")] ++pub fn float_s(input: &str) -> IResult<&str,f32> { ++ flat_map!(input, ++ recognize!( ++ tuple!( ++ opt!(alt!(tag!("+") | tag!("-"))), ++ alt!( ++ delimited!(digit, tag!("."), opt!(digit)) ++ | delimited!(opt!(digit), tag!("."), digit) ++ ), ++ opt!(complete!(tuple!( ++ alt!(tag!("e") | tag!("E")), ++ opt!(alt!(tag!("+") | tag!("-"))), ++ digit ++ ) ++ )) ++ ) ++ ), ++ parse_to!(f32) ++ ) ++} ++ ++/// Recognizes floating point number in a byte string and returns a f64 ++#[cfg(feature = "std")] ++pub fn double(input: &[u8]) -> IResult<&[u8],f64> { ++ flat_map!(input, ++ recognize!( ++ tuple!( ++ opt!(alt!(tag!("+") | tag!("-"))), ++ alt!( ++ delimited!(digit, tag!("."), opt!(digit)) ++ | delimited!(opt!(digit), tag!("."), digit) ++ ), ++ opt!(complete!(tuple!( ++ alt!(tag!("e") | tag!("E")), ++ opt!(alt!(tag!("+") | tag!("-"))), ++ digit ++ ) ++ )) ++ ) ++ ), ++ parse_to!(f64) ++ ) ++} ++ ++/// Recognizes floating point number in a string and returns a f64 ++#[cfg(feature = "std")] ++pub fn double_s(input: &str) -> IResult<&str,f64> { ++ flat_map!(input, ++ recognize!( ++ tuple!( ++ opt!(alt!(tag!("+") | tag!("-"))), ++ alt!( ++ delimited!(digit, tag!("."), opt!(digit)) ++ | delimited!(opt!(digit), tag!("."), digit) ++ ), ++ opt!(complete!(tuple!( ++ alt!(tag!("e") | tag!("E")), ++ opt!(alt!(tag!("+") | tag!("-"))), ++ digit ++ ) ++ )) ++ ) ++ ), ++ parse_to!(f64) ++ ) ++} ++ + #[cfg(test)] + mod tests { + use super::*; + use internal::{Needed,IResult}; +- use internal::IResult::*; +- use internal::Err::*; + use util::ErrorKind; + + #[test] +@@ -578,7 +744,7 @@ mod tests { + assert_eq!(r, Done(&b"abcdefgh"[..], &b"abcd"[..])); + + let r2 = x(&b"abcefgh"[..]); +- assert_eq!(r2, Error(Position(ErrorKind::TagClosure, &b"abcefgh"[..]))); ++ assert_eq!(r2, Error(error_position!(ErrorKind::TagClosure, &b"abcefgh"[..]))); + } + + #[test] +@@ -590,22 +756,22 @@ mod tests { + let d: &[u8] = "azé12".as_bytes(); + let e: &[u8] = b" "; + assert_eq!(alpha(a), Done(empty, a)); +- assert_eq!(alpha(b), Error(Position(ErrorKind::Alpha,b))); ++ assert_eq!(alpha(b), Error(error_position!(ErrorKind::Alpha,b))); + assert_eq!(alpha(c), Done(&c[1..], &b"a"[..])); + assert_eq!(alpha(d), Done("é12".as_bytes(), &b"az"[..])); +- assert_eq!(digit(a), Error(Position(ErrorKind::Digit,a))); ++ assert_eq!(digit(a), Error(error_position!(ErrorKind::Digit,a))); + assert_eq!(digit(b), Done(empty, b)); +- assert_eq!(digit(c), Error(Position(ErrorKind::Digit,c))); +- assert_eq!(digit(d), Error(Position(ErrorKind::Digit,d))); ++ assert_eq!(digit(c), Error(error_position!(ErrorKind::Digit,c))); ++ assert_eq!(digit(d), Error(error_position!(ErrorKind::Digit,d))); + assert_eq!(hex_digit(a), Done(empty, a)); + assert_eq!(hex_digit(b), Done(empty, b)); + assert_eq!(hex_digit(c), Done(empty, c)); + assert_eq!(hex_digit(d), Done("zé12".as_bytes(), &b"a"[..])); +- assert_eq!(hex_digit(e), Error(Position(ErrorKind::HexDigit,e))); +- assert_eq!(oct_digit(a), Error(Position(ErrorKind::OctDigit,a))); ++ assert_eq!(hex_digit(e), Error(error_position!(ErrorKind::HexDigit,e))); ++ assert_eq!(oct_digit(a), Error(error_position!(ErrorKind::OctDigit,a))); + assert_eq!(oct_digit(b), Done(empty, b)); +- assert_eq!(oct_digit(c), Error(Position(ErrorKind::OctDigit,c))); +- assert_eq!(oct_digit(d), Error(Position(ErrorKind::OctDigit,d))); ++ assert_eq!(oct_digit(c), Error(error_position!(ErrorKind::OctDigit,c))); ++ assert_eq!(oct_digit(d), Error(error_position!(ErrorKind::OctDigit,d))); + assert_eq!(alphanumeric(a), Done(empty, a)); + assert_eq!(fix_error!(b,(), alphanumeric), Done(empty, b)); + assert_eq!(alphanumeric(c), Done(empty, c)); +@@ -622,22 +788,22 @@ mod tests { + let d = "azé12"; + let e = " "; + assert_eq!(alpha(a), Done(empty, a)); +- assert_eq!(alpha(b), Error(Position(ErrorKind::Alpha,b))); ++ assert_eq!(alpha(b), Error(error_position!(ErrorKind::Alpha,b))); + assert_eq!(alpha(c), Done(&c[1..], &"a"[..])); + assert_eq!(alpha(d), Done("12", &"azé"[..])); +- assert_eq!(digit(a), Error(Position(ErrorKind::Digit,a))); ++ assert_eq!(digit(a), Error(error_position!(ErrorKind::Digit,a))); + assert_eq!(digit(b), Done(empty, b)); +- assert_eq!(digit(c), Error(Position(ErrorKind::Digit,c))); +- assert_eq!(digit(d), Error(Position(ErrorKind::Digit,d))); ++ assert_eq!(digit(c), Error(error_position!(ErrorKind::Digit,c))); ++ assert_eq!(digit(d), Error(error_position!(ErrorKind::Digit,d))); + assert_eq!(hex_digit(a), Done(empty, a)); + assert_eq!(hex_digit(b), Done(empty, b)); + assert_eq!(hex_digit(c), Done(empty, c)); + assert_eq!(hex_digit(d), Done("zé12", &"a"[..])); +- assert_eq!(hex_digit(e), Error(Position(ErrorKind::HexDigit,e))); +- assert_eq!(oct_digit(a), Error(Position(ErrorKind::OctDigit,a))); ++ assert_eq!(hex_digit(e), Error(error_position!(ErrorKind::HexDigit,e))); ++ assert_eq!(oct_digit(a), Error(error_position!(ErrorKind::OctDigit,a))); + assert_eq!(oct_digit(b), Done(empty, b)); +- assert_eq!(oct_digit(c), Error(Position(ErrorKind::OctDigit,c))); +- assert_eq!(oct_digit(d), Error(Position(ErrorKind::OctDigit,d))); ++ assert_eq!(oct_digit(c), Error(error_position!(ErrorKind::OctDigit,c))); ++ assert_eq!(oct_digit(d), Error(error_position!(ErrorKind::OctDigit,d))); + assert_eq!(alphanumeric(a), Done(empty, a)); + assert_eq!(fix_error!(b,(), alphanumeric), Done(empty, b)); + assert_eq!(alphanumeric(c), Done(empty, c)); +@@ -645,7 +811,7 @@ mod tests { + assert_eq!(space(e), Done(&""[..], &" "[..])); + } + +- use util::HexDisplay; ++ use util::Offset; + #[test] + fn offset() { + let a = &b"abcd"[..]; +@@ -686,18 +852,48 @@ mod tests { + } + + #[test] +- fn is_not() { ++ fn is_not_line_ending_bytes() { + let a: &[u8] = b"ab12cd\nefgh"; + assert_eq!(not_line_ending(a), Done(&b"\nefgh"[..], &b"ab12cd"[..])); + + let b: &[u8] = b"ab12cd\nefgh\nijkl"; + assert_eq!(not_line_ending(b), Done(&b"\nefgh\nijkl"[..], &b"ab12cd"[..])); + +- let c: &[u8] = b"ab12cd"; +- assert_eq!(not_line_ending(c), Done(&b""[..], c)); ++ let c: &[u8] = b"ab12cd\r\nefgh\nijkl"; ++ assert_eq!(not_line_ending(c), Done(&b"\r\nefgh\nijkl"[..], &b"ab12cd"[..])); ++ ++ let d: &[u8] = b"ab12cd"; ++ assert_eq!(not_line_ending(d), Done(&b""[..], d)); + } + + #[test] ++ fn is_not_line_ending_str() { ++ /* ++ let a: &str = "ab12cd\nefgh"; ++ assert_eq!(not_line_ending(a), Done(&"\nefgh"[..], &"ab12cd"[..])); ++ ++ let b: &str = "ab12cd\nefgh\nijkl"; ++ assert_eq!(not_line_ending(b), Done(&"\nefgh\nijkl"[..], &"ab12cd"[..])); ++ ++ let c: &str = "ab12cd\r\nefgh\nijkl"; ++ assert_eq!(not_line_ending(c), Done(&"\r\nefgh\nijkl"[..], &"ab12cd"[..])); ++ ++ let d = "βèƒôřè\nÂßÇáƒƭèř"; ++ assert_eq!(not_line_ending(d), Done(&"\nÂßÇáƒƭèř"[..], &"βèƒôřè"[..])); ++ ++ let e = "βèƒôřè\r\nÂßÇáƒƭèř"; ++ assert_eq!(not_line_ending(e), Done(&"\r\nÂßÇáƒƭèř"[..], &"βèƒôřè"[..])); ++ */ ++ ++ let f = "βèƒôřè\rÂßÇáƒƭèř"; ++ assert_eq!(not_line_ending(f), Error(error_position!(ErrorKind::Tag,f))); ++ ++ let g: &str = "ab12cd"; ++ assert_eq!(not_line_ending(g), Done("", g)); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] + fn buffer_with_size() { + let i:Vec = vec![7,8]; + let o:Vec = vec![4,5,6]; +@@ -716,26 +912,6 @@ mod tests { + assert_eq!(res, Done(&v2[..], ())); + }*/ + +- #[test] +- fn length_value_test() { +- let i1 = vec![7,8]; +- let o1 = vec![4, 5, 6]; +- let arr1:[u8; 6usize] = [3, 4, 5, 6, 7, 8]; +- let res1 = length_value(&arr1); +- assert_eq!(Done(&i1[..], &o1[..]), res1); +- +- let i2:Vec = vec![4,5,6,7,8]; +- let o2: &[u8] = b""; +- let arr2:[u8; 6usize] = [0, 4, 5, 6, 7, 8]; +- let res2 = length_value(&arr2); +- assert_eq!(Done(&i2[..], o2), res2); +- +- let arr3:[u8; 7usize] = [8, 4, 5, 6, 7, 8, 9]; +- let res3 = length_value(&arr3); +- //FIXME: should be incomplete +- assert_eq!(Incomplete(Needed::Size(9)), res3); +- } +- + #[test] + fn i8_tests() { + assert_eq!(be_i8(&[0x00]), Done(&b""[..], 0)); +@@ -752,6 +928,20 @@ mod tests { + assert_eq!(be_i16(&[0x80, 0x00]), Done(&b""[..], -32768_i16)); + } + ++ #[test] ++ fn u24_tests() { ++ assert_eq!(be_u24(&[0x00, 0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(be_u24(&[0x00, 0xFF, 0xFF]), Done(&b""[..], 65535_u32)); ++ assert_eq!(be_u24(&[0x12, 0x34, 0x56]), Done(&b""[..], 1193046_u32)); ++ } ++ ++ #[test] ++ fn i24_tests() { ++ assert_eq!(be_i24(&[0xFF, 0xFF, 0xFF]), Done(&b""[..], -1_i32)); ++ assert_eq!(be_i24(&[0xFF, 0x00, 0x00]), Done(&b""[..], -65536_i32)); ++ assert_eq!(be_i24(&[0xED, 0xCB, 0xAA]), Done(&b""[..], -1193046_i32)); ++ } ++ + #[test] + fn i32_tests() { + assert_eq!(be_i32(&[0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0)); +@@ -784,6 +974,20 @@ mod tests { + assert_eq!(le_i16(&[0x00, 0x80]), Done(&b""[..], -32768_i16)); + } + ++ #[test] ++ fn le_u24_tests() { ++ assert_eq!(le_u24(&[0x00, 0x00, 0x00]), Done(&b""[..], 0)); ++ assert_eq!(le_u24(&[0xFF, 0xFF, 0x00]), Done(&b""[..], 65535_u32)); ++ assert_eq!(le_u24(&[0x56, 0x34, 0x12]), Done(&b""[..], 1193046_u32)); ++ } ++ ++ #[test] ++ fn le_i24_tests() { ++ assert_eq!(le_i24(&[0xFF, 0xFF, 0xFF]), Done(&b""[..], -1_i32)); ++ assert_eq!(le_i24(&[0x00, 0x00, 0xFF]), Done(&b""[..], -65536_i32)); ++ assert_eq!(le_i24(&[0xAA, 0xCB, 0xED]), Done(&b""[..], -1193046_i32)); ++ } ++ + #[test] + fn le_i32_tests() { + assert_eq!(le_i32(&[0x00, 0x00, 0x00, 0x00]), Done(&b""[..], 0)); +@@ -830,6 +1034,7 @@ mod tests { + assert_eq!(hex_u32(&b"ff"[..]), Done(&b""[..], 255)); + assert_eq!(hex_u32(&b"1be2"[..]), Done(&b""[..], 7138)); + assert_eq!(hex_u32(&b"c5a31be2"[..]), Done(&b""[..], 3315801058)); ++ assert_eq!(hex_u32(&b"C5A31be2"[..]), Done(&b""[..], 3315801058)); + assert_eq!(hex_u32(&b"00c5a31be2"[..]), Done(&b"e2"[..], 12952347)); + assert_eq!(hex_u32(&b"c5a31be201"[..]), Done(&b"01"[..], 3315801058)); + assert_eq!(hex_u32(&b"ffffffff"[..]), Done(&b""[..], 4294967295)); +@@ -840,49 +1045,51 @@ mod tests { + fn end_of_input() { + let not_over = &b"Hello, world!"[..]; + let is_over = &b""[..]; ++ named!(eof_test, eof!()); + +- let res_not_over = eof(not_over); +- assert_eq!(res_not_over, Error(Position(ErrorKind::Eof, not_over))); ++ let res_not_over = eof_test(not_over); ++ assert_eq!(res_not_over, Error(error_position!(ErrorKind::Eof, not_over))); + +- let res_over = eof(is_over); ++ let res_over = eof_test(is_over); + assert_eq!(res_over, Done(is_over, is_over)); + } + + #[test] + fn configurable_endianness() { +- named!(be_tst16, u16!(true)); +- named!(le_tst16, u16!(false)); ++ named!(be_tst16, u16!(Endianness::Big)); ++ named!(le_tst16, u16!(Endianness::Little)); + assert_eq!(be_tst16(&[0x80, 0x00]), Done(&b""[..], 32768_u16)); + assert_eq!(le_tst16(&[0x80, 0x00]), Done(&b""[..], 128_u16)); + +- named!(be_tst32, u32!(true)); +- named!(le_tst32, u32!(false)); ++ named!(be_tst32, u32!(Endianness::Big)); ++ named!(le_tst32, u32!(Endianness::Little)); + assert_eq!(be_tst32(&[0x12, 0x00, 0x60, 0x00]), Done(&b""[..], 302014464_u32)); + assert_eq!(le_tst32(&[0x12, 0x00, 0x60, 0x00]), Done(&b""[..], 6291474_u32)); + +- named!(be_tst64, u64!(true)); +- named!(le_tst64, u64!(false)); ++ named!(be_tst64, u64!(Endianness::Big)); ++ named!(le_tst64, u64!(Endianness::Little)); + assert_eq!(be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 1297142246100992000_u64)); + assert_eq!(le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 36028874334666770_u64)); + +- named!(be_tsti16, i16!(true)); +- named!(le_tsti16, i16!(false)); ++ named!(be_tsti16, i16!(Endianness::Big)); ++ named!(le_tsti16, i16!(Endianness::Little)); + assert_eq!(be_tsti16(&[0x00, 0x80]), Done(&b""[..], 128_i16)); + assert_eq!(le_tsti16(&[0x00, 0x80]), Done(&b""[..], -32768_i16)); + +- named!(be_tsti32, i32!(true)); +- named!(le_tsti32, i32!(false)); ++ named!(be_tsti32, i32!(Endianness::Big)); ++ named!(le_tsti32, i32!(Endianness::Little)); + assert_eq!(be_tsti32(&[0x00, 0x12, 0x60, 0x00]), Done(&b""[..], 1204224_i32)); + assert_eq!(le_tsti32(&[0x00, 0x12, 0x60, 0x00]), Done(&b""[..], 6296064_i32)); + +- named!(be_tsti64, i64!(true)); +- named!(le_tsti64, i64!(false)); ++ named!(be_tsti64, i64!(Endianness::Big)); ++ named!(le_tsti64, i64!(Endianness::Little)); + assert_eq!(be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 71881672479506432_i64)); + assert_eq!(le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]), Done(&b""[..], 36028874334732032_i64)); + + } + + #[test] ++ #[cfg(feature = "std")] + fn manual_configurable_endianness_test() { + let x = 1; + let int_parse: Box IResult<&[u8], u16> > = if x == 2 { +@@ -907,10 +1114,10 @@ mod tests { + assert_eq!(hex_digit(i), Done(empty, i)); + + let i = &b"g"[..]; +- assert_eq!(hex_digit(i), Error(Position(ErrorKind::HexDigit,i))); ++ assert_eq!(hex_digit(i), Error(error_position!(ErrorKind::HexDigit,i))); + + let i = &b"G"[..]; +- assert_eq!(hex_digit(i), Error(Position(ErrorKind::HexDigit,i))); ++ assert_eq!(hex_digit(i), Error(error_position!(ErrorKind::HexDigit,i))); + + assert!(is_hex_digit(b'0')); + assert!(is_hex_digit(b'9')); +@@ -934,7 +1141,7 @@ mod tests { + assert_eq!(oct_digit(i), Done(empty, i)); + + let i = &b"8"[..]; +- assert_eq!(oct_digit(i), Error(Position(ErrorKind::OctDigit,i))); ++ assert_eq!(oct_digit(i), Error(error_position!(ErrorKind::OctDigit,i))); + + assert!(is_oct_digit(b'0')); + assert!(is_oct_digit(b'7')); +@@ -947,4 +1154,72 @@ mod tests { + assert!(!is_oct_digit(b'@')); + assert!(!is_oct_digit(b'\x60')); + } ++ ++ #[test] ++ fn full_line_windows() { ++ named!(take_full_line<(&[u8], &[u8])>, tuple!(not_line_ending, line_ending)); ++ let input = b"abc\r\n"; ++ let output = take_full_line(input); ++ assert_eq!(output, Done(&b""[..], (&b"abc"[..], &b"\r\n"[..]))); ++ } ++ ++ #[test] ++ fn full_line_unix() { ++ named!(take_full_line<(&[u8], &[u8])>, tuple!(not_line_ending, line_ending)); ++ let input = b"abc\n"; ++ let output = take_full_line(input); ++ assert_eq!(output, Done(&b""[..], (&b"abc"[..], &b"\n"[..]))); ++ } ++ ++ #[test] ++ fn check_windows_lineending() { ++ let input = b"\r\n"; ++ let output = line_ending(&input[..]); ++ assert_eq!(output, Done(&b""[..], &b"\r\n"[..])); ++ } ++ ++ #[test] ++ fn check_unix_lineending() { ++ let input = b"\n"; ++ let output = line_ending(&input[..]); ++ assert_eq!(output, Done(&b""[..], &b"\n"[..])); ++ } ++ ++ #[test] ++ fn cr_lf() { ++ assert_eq!(crlf(&b"\r\na"[..]), Done(&b"a"[..], &b"\r\n"[..])); ++ assert_eq!(crlf(&b"\r"[..]), Incomplete(Needed::Size(2))); ++ assert_eq!(crlf(&b"\ra"[..]), Error(error_position!(ErrorKind::CrLf, &b"\ra"[..]))); ++ ++ assert_eq!(crlf("\r\na"), Done("a", "\r\n")); ++ assert_eq!(crlf("\r"), Incomplete(Needed::Size(2))); ++ assert_eq!(crlf("\ra"), Error(error_position!(ErrorKind::CrLf, "\ra"))); ++ } ++ ++ #[test] ++ fn end_of_line() { ++ assert_eq!(eol(&b"\na"[..]), Done(&b"a"[..], &b"\n"[..])); ++ assert_eq!(eol(&b"\r\na"[..]), Done(&b"a"[..], &b"\r\n"[..])); ++ assert_eq!(eol(&b"\r"[..]), Incomplete(Needed::Size(2))); ++ assert_eq!(eol(&b"\ra"[..]), Error(error_position!(ErrorKind::CrLf, &b"\ra"[..]))); ++ ++ assert_eq!(eol("\na"), Done("a", "\n")); ++ assert_eq!(eol("\r\na"), Done("a", "\r\n")); ++ assert_eq!(eol("\r"), Incomplete(Needed::Size(2))); ++ assert_eq!(eol("\ra"), Error(error_position!(ErrorKind::CrLf, "\ra"))); ++ } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn float_test() { ++ assert_eq!(float(&b"+3.14"[..]), Done(&b""[..], 3.14)); ++ assert_eq!(float_s(&"3.14"[..]), Done(&""[..], 3.14)); ++ assert_eq!(double(&b"3.14"[..]), Done(&b""[..], 3.14)); ++ assert_eq!(double_s(&"3.14"[..]), Done(&""[..], 3.14)); ++ ++ assert_eq!(float(&b"-1.234E-12"[..]), Done(&b""[..], -1.234E-12)); ++ assert_eq!(float_s(&"-1.234E-12"[..]), Done(&""[..], -1.234E-12)); ++ assert_eq!(double(&b"-1.234E-12"[..]), Done(&b""[..], -1.234E-12)); ++ assert_eq!(double_s(&"-1.234E-12"[..]), Done(&""[..], -1.234E-12)); ++ } + } +diff --git third_party/rust/nom/src/regexp.rs third_party/rust/nom/src/regexp.rs +index 17f8ede1a3f7..b4a90f448cb2 100644 +--- third_party/rust/nom/src/regexp.rs ++++ third_party/rust/nom/src/regexp.rs +@@ -28,11 +28,13 @@ macro_rules! re_match ( + ($i:expr, $re:expr) => ( + { + use $crate::InputLength; ++ use $crate::Slice; + let re = ::regex::Regex::new($re).unwrap(); + if re.is_match($i) { +- $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ $crate::IResult::Done($i.slice($i.input_len()..), $i) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatch)); ++ res + } + } + ) +@@ -48,11 +50,13 @@ macro_rules! re_match_static ( + ($i:expr, $re:expr) => ( + { + use $crate::InputLength; ++ use $crate::Slice; + regex!(RE, $re); + if RE.is_match($i) { +- $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ $crate::IResult::Done($i.slice($i.input_len()..), $i) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatch)); ++ res + } + } + ) +@@ -67,11 +71,13 @@ macro_rules! re_bytes_match ( + ($i:expr, $re:expr) => ( + { + use $crate::InputLength; ++ use $crate::Slice; + let re = ::regex::bytes::Regex::new($re).unwrap(); + if re.is_match($i) { +- $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ $crate::IResult::Done($i.slice($i.input_len()..), $i) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatch)); ++ res + } + } + ) +@@ -87,11 +93,13 @@ macro_rules! re_bytes_match_static ( + ($i:expr, $re:expr) => ( + { + use $crate::InputLength; ++ use $crate::Slice; + regex_bytes!(RE, $re); + if RE.is_match($i) { +- $crate::IResult::Done(&$i[$i.input_len()..], $i) ++ $crate::IResult::Done($i.slice($i.input_len()..), $i) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatch)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatch)); ++ res + } + } + ) +@@ -105,11 +113,13 @@ macro_rules! re_bytes_match_static ( + macro_rules! re_find ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::Regex::new($re).unwrap(); +- if let Some((begin, end)) = re.find($i) { +- $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ if let Some(m) = re.find($i) { ++ $crate::IResult::Done($i.slice(m.end()..), $i.slice(m.start()..m.end())) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpFind)); ++ res + } + } + ) +@@ -124,11 +134,13 @@ macro_rules! re_find ( + macro_rules! re_find_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex!(RE, $re); +- if let Some((begin, end)) = RE.find($i) { +- $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ if let Some(m) = RE.find($i) { ++ $crate::IResult::Done($i.slice(m.end()..), $i.slice(m.start()..m.end())) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpFind)); ++ res + } + } + +@@ -143,11 +155,13 @@ macro_rules! re_find_static ( + macro_rules! re_bytes_find ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::bytes::Regex::new($re).unwrap(); +- if let Some((begin, end)) = re.find($i) { +- $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ if let Some(m) = re.find($i) { ++ $crate::IResult::Done($i.slice(m.end()..), $i.slice(m.start()..m.end())) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpFind)); ++ res + } + } + ) +@@ -162,11 +176,13 @@ macro_rules! re_bytes_find ( + macro_rules! re_bytes_find_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex_bytes!(RE, $re); +- if let Some((begin, end)) = RE.find($i) { +- $crate::IResult::Done(&$i[end..], &$i[begin..end]) ++ if let Some(m) = RE.find($i) { ++ $crate::IResult::Done($i.slice(m.end()..), $i.slice(m.start()..m.end())) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpFind)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpFind)); ++ res + } + } + +@@ -181,16 +197,18 @@ macro_rules! re_bytes_find_static ( + macro_rules! re_matches ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::Regex::new($re).unwrap(); +- let v: Vec<&str> = re.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v: Vec<&str> = re.find_iter($i).map(|m| $i.slice(m.start()..m.end())).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatches)); ++ res + } + } + ) +@@ -205,16 +223,18 @@ macro_rules! re_matches ( + macro_rules! re_matches_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex!(RE, $re); +- let v: Vec<&str> = RE.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v: Vec<&str> = RE.find_iter($i).map(|m| $i.slice(m.start()..m.end())).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatches)); ++ res + } + } + ) +@@ -228,16 +248,18 @@ macro_rules! re_matches_static ( + macro_rules! re_bytes_matches ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::bytes::Regex::new($re).unwrap(); +- let v: Vec<&[u8]> = re.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v: Vec<&[u8]> = re.find_iter($i).map(|m| $i.slice(m.start()..m.end())).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatches)); ++ res + } + } + ) +@@ -252,16 +274,18 @@ macro_rules! re_bytes_matches ( + macro_rules! re_bytes_matches_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex_bytes!(RE, $re); +- let v: Vec<&[u8]> = RE.find_iter($i).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v: Vec<&[u8]> = RE.find_iter($i).map(|m| $i.slice(m.start()..m.end())).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpMatches)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpMatches)); ++ res + } + } + ) +@@ -275,16 +299,18 @@ macro_rules! re_bytes_matches_static ( + macro_rules! re_capture ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::Regex::new($re).unwrap(); + if let Some(c) = re.captures($i) { +- let v:Vec<&str> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v:Vec<&str> = c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect(); + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -299,16 +325,18 @@ macro_rules! re_capture ( + macro_rules! re_capture_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex!(RE, $re); + if let Some(c) = RE.captures($i) { +- let v:Vec<&str> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v:Vec<&str> = c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect(); + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -322,16 +350,18 @@ macro_rules! re_capture_static ( + macro_rules! re_bytes_capture ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::bytes::Regex::new($re).unwrap(); + if let Some(c) = re.captures($i) { +- let v:Vec<&[u8]> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v:Vec<&[u8]> = c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect(); + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -346,16 +376,18 @@ macro_rules! re_bytes_capture ( + macro_rules! re_bytes_capture_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex_bytes!(RE, $re); + if let Some(c) = RE.captures($i) { +- let v:Vec<&[u8]> = c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect(); ++ let v:Vec<&[u8]> = c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect(); + let offset = { + let end = v.last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -369,16 +401,18 @@ macro_rules! re_bytes_capture_static ( + macro_rules! re_captures ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::Regex::new($re).unwrap(); +- let v:Vec> = re.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ let v:Vec> = re.captures_iter($i).map(|c| c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect()).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap().last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -393,16 +427,18 @@ macro_rules! re_captures ( + macro_rules! re_captures_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex!(RE, $re); +- let v:Vec> = RE.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ let v:Vec> = RE.captures_iter($i).map(|c| c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect()).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap().last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -416,16 +452,18 @@ macro_rules! re_captures_static ( + macro_rules! re_bytes_captures ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + let re = ::regex::bytes::Regex::new($re).unwrap(); +- let v:Vec> = re.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ let v:Vec> = re.captures_iter($i).map(|c| c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect()).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap().last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -440,16 +478,18 @@ macro_rules! re_bytes_captures ( + macro_rules! re_bytes_captures_static ( + ($i:expr, $re:expr) => ( + { ++ use $crate::Slice; + regex_bytes!(RE, $re); +- let v:Vec> = RE.captures_iter($i).map(|c| c.iter_pos().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|(begin,end)| &$i[begin..end]).collect()).collect(); ++ let v:Vec> = RE.captures_iter($i).map(|c| c.iter().filter(|el| el.is_some()).map(|el| el.unwrap()).map(|m| $i.slice(m.start()..m.end())).collect()).collect(); + if v.len() != 0 { + let offset = { + let end = v.last().unwrap().last().unwrap(); + end.as_ptr() as usize + end.len() - $i.as_ptr() as usize + }; +- $crate::IResult::Done(&$i[offset..], v) ++ $crate::IResult::Done($i.slice(offset..), v) + } else { +- $crate::IResult::Error($crate::Err::Code($crate::ErrorKind::RegexpCapture)) ++ let res: $crate::IResult<_,_> = $crate::IResult::Error(error_code!($crate::ErrorKind::RegexpCapture)); ++ res + } + } + ) +@@ -457,14 +497,13 @@ macro_rules! re_bytes_captures_static ( + #[cfg(test)] + mod tests { + use internal::IResult::*; +- use internal::Err::*; + use util::ErrorKind; + + #[test] + fn re_match() { + named!(rm<&str,&str>, re_match!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpMatch))); + assert_eq!(rm("2015-09-07blah"), Done("", "2015-09-07blah")); + } + +@@ -473,7 +512,7 @@ mod tests { + fn re_match_static() { + named!(rm<&str,&str>, re_match_static!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpMatch))); + assert_eq!(rm("2015-09-07blah"), Done("", "2015-09-07blah")); + } + +@@ -481,7 +520,7 @@ mod tests { + fn re_find() { + named!(rm<&str,&str>, re_find!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpFind))); + assert_eq!(rm("2015-09-07blah"), Done("blah", "2015-09-07")); + } + +@@ -490,7 +529,7 @@ mod tests { + fn re_find_static() { + named!(rm<&str,&str>, re_find_static!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm("2015-09-07"), Done("", "2015-09-07")); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpFind))); + assert_eq!(rm("2015-09-07blah"), Done("blah", "2015-09-07")); + } + +@@ -498,7 +537,7 @@ mod tests { + fn re_matches() { + named!(rm< &str,Vec<&str> >, re_matches!(r"\d{4}-\d{2}-\d{2}")); + assert_eq!(rm("2015-09-07"), Done("", vec!["2015-09-07"])); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpMatches))); + assert_eq!(rm("aaa2015-09-07blah2015-09-09pouet"), Done("pouet", vec!["2015-09-07", "2015-09-09"])); + } + +@@ -507,32 +546,32 @@ mod tests { + fn re_matches_static() { + named!(rm< &str,Vec<&str> >, re_matches_static!(r"\d{4}-\d{2}-\d{2}")); + assert_eq!(rm("2015-09-07"), Done("", vec!["2015-09-07"])); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpMatches))); + assert_eq!(rm("aaa2015-09-07blah2015-09-09pouet"), Done("pouet", vec!["2015-09-07", "2015-09-09"])); + } + + #[test] + fn re_capture() { +- named!(rm< &str,Vec<&str> >, re_capture!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< &str,Vec<&str> >, re_capture!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41"), Done(" world regex 0.1.41", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); + } + + #[cfg(feature = "regexp_macros")] + #[test] + fn re_capture_static() { +- named!(rm< &str,Vec<&str> >, re_capture_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< &str,Vec<&str> >, re_capture_static!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41"), Done(" world regex 0.1.41", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"])); + } + + #[test] + fn re_captures() { +- named!(rm< &str,Vec> >, re_captures!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< &str,Vec> >, re_captures!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec![vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]])); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41 aaa"), Done(" aaa", vec![ + vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"], + vec!["regex 0.1.41", "regex", "0.1.41", "0", "1", "41"], +@@ -542,9 +581,9 @@ mod tests { + #[cfg(feature = "regexp_macros")] + #[test] + fn re_captures_static() { +- named!(rm< &str,Vec> >, re_captures_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< &str,Vec> >, re_captures_static!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm("blah nom 0.3.11pouet"), Done("pouet", vec![vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]])); +- assert_eq!(rm("blah"), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm("blah"), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm("hello nom 0.3.11 world regex 0.1.41 aaa"), Done(" aaa", vec![ + vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"], + vec!["regex 0.1.41", "regex", "0.1.41", "0", "1", "41"], +@@ -555,7 +594,7 @@ mod tests { + fn re_bytes_match() { + named!(rm, re_bytes_match!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpMatch))); + assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b""[..], &b"2015-09-07blah"[..])); + } + +@@ -564,7 +603,7 @@ mod tests { + fn re_bytes_match_static() { + named!(rm, re_bytes_match_static!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatch))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpMatch))); + assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b""[..], &b"2015-09-07blah"[..])); + } + +@@ -572,7 +611,7 @@ mod tests { + fn re_bytes_find() { + named!(rm, re_bytes_find!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpFind))); + assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b"blah"[..], &b"2015-09-07"[..])); + } + +@@ -581,7 +620,7 @@ mod tests { + fn re_bytes_find_static() { + named!(rm, re_bytes_find_static!(r"^\d{4}-\d{2}-\d{2}")); + assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], &b"2015-09-07"[..])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpFind))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpFind))); + assert_eq!(rm(&b"2015-09-07blah"[..]), Done(&b"blah"[..], &b"2015-09-07"[..])); + } + +@@ -589,7 +628,7 @@ mod tests { + fn re_bytes_matches() { + named!(rm >, re_bytes_matches!(r"\d{4}-\d{2}-\d{2}")); + assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], vec![&b"2015-09-07"[..]])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpMatches))); + assert_eq!(rm(&b"aaa2015-09-07blah2015-09-09pouet"[..]), Done(&b"pouet"[..], vec![&b"2015-09-07"[..], &b"2015-09-09"[..]])); + } + +@@ -598,32 +637,32 @@ mod tests { + fn re_bytes_matches_static() { + named!(rm >, re_bytes_matches_static!(r"\d{4}-\d{2}-\d{2}")); + assert_eq!(rm(&b"2015-09-07"[..]), Done(&b""[..], vec![&b"2015-09-07"[..]])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpMatches))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpMatches))); + assert_eq!(rm(&b"aaa2015-09-07blah2015-09-09pouet"[..]), Done(&b"pouet"[..], vec![&b"2015-09-07"[..], &b"2015-09-09"[..]])); + } + + #[test] + fn re_bytes_capture() { +- named!(rm >, re_bytes_capture!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm >, re_bytes_capture!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41"[..]), Done(&b" world regex 0.1.41"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); + } + + #[cfg(feature = "regexp_macros")] + #[test] + fn re_bytes_capture_static() { +- named!(rm< Vec<&[u8]> >, re_bytes_capture_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< Vec<&[u8]> >, re_bytes_capture_static!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41"[..]), Done(&b" world regex 0.1.41"[..], vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]])); + } + + #[test] + fn re_bytes_captures() { +- named!(rm< Vec> >, re_bytes_captures!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< Vec> >, re_bytes_captures!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]]])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41 aaa"[..]), Done(&b" aaa"[..], vec![ + vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]], + vec![&b"regex 0.1.41"[..], &b"regex"[..], &b"0.1.41"[..], &b"0"[..], &b"1"[..], &b"41"[..]], +@@ -633,9 +672,9 @@ mod tests { + #[cfg(feature = "regexp_macros")] + #[test] + fn re_bytes_captures_static() { +- named!(rm< Vec> >, re_bytes_captures_static!(r"([:alpha:]+)\s+((\d+).(\d+).(\d+))")); ++ named!(rm< Vec> >, re_bytes_captures_static!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")); + assert_eq!(rm(&b"blah nom 0.3.11pouet"[..]), Done(&b"pouet"[..], vec![vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]]])); +- assert_eq!(rm(&b"blah"[..]), Error(Code(ErrorKind::RegexpCapture))); ++ assert_eq!(rm(&b"blah"[..]), Error(error_code!(ErrorKind::RegexpCapture))); + assert_eq!(rm(&b"hello nom 0.3.11 world regex 0.1.41 aaa"[..]), Done(&b" aaa"[..], vec![ + vec![&b"nom 0.3.11"[..], &b"nom"[..], &b"0.3.11"[..], &b"0"[..], &b"3"[..], &b"11"[..]], + vec![&b"regex 0.1.41"[..], &b"regex"[..], &b"0.1.41"[..], &b"0"[..], &b"1"[..], &b"41"[..]], +diff --git third_party/rust/nom/src/sequence.rs third_party/rust/nom/src/sequence.rs +new file mode 100644 +index 000000000000..0bbefe009aa2 +--- /dev/null ++++ third_party/rust/nom/src/sequence.rs +@@ -0,0 +1,889 @@ ++/// `tuple!(I->IResult, I->IResult, ... I->IResult) => I -> IResult` ++/// chains parsers and assemble the sub results in a tuple. ++/// ++/// The input type `I` must implement `nom::InputLength`. ++/// ++/// This combinator will count how much data is consumed by every child parser ++/// and take it into account if there is not enough data ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Error}; ++/// # #[cfg(feature = "verbose-errors")] ++/// # use nom::Err::Position; ++/// # use nom::ErrorKind; ++/// # use nom::be_u16; ++/// // the return type depends of the children parsers ++/// named!(parser<&[u8], (u16, &[u8], &[u8]) >, ++/// tuple!( ++/// be_u16 , ++/// take!(3), ++/// tag!("fg") ++/// ) ++/// ); ++/// ++/// # fn main() { ++/// assert_eq!( ++/// parser(&b"abcdefgh"[..]), ++/// Done( ++/// &b"h"[..], ++/// (0x6162u16, &b"cde"[..], &b"fg"[..]) ++/// ) ++/// ); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! tuple ( ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ tuple_parser!($i, 0usize, (), $($rest)*) ++ } ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! tuple_parser ( ++ ($i:expr, $consumed:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => ( ++ tuple_parser!($i, $consumed, ($($parsed),*), call!($e), $($rest)*); ++ ); ++ ($i:expr, $consumed:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Error(e) => ++ $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,o) => { ++ let i_ = i.clone(); ++ tuple_parser!(i_, ++ $consumed + ($crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&i)), (o), $($rest)*) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Error(e) => ++ $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,o) => { ++ let i_ = i.clone(); ++ tuple_parser!(i_, ++ $consumed + ($crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&i)), ($($parsed)* , o), $($rest)*) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:tt),*), $e:ident) => ( ++ tuple_parser!($i, $consumed, ($($parsed),*), call!($e)); ++ ); ++ ($i:expr, $consumed:expr, (), $submac:ident!( $($args:tt)* )) => ( ++ { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Error(e) => ++ $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,o) => { ++ $crate::IResult::Done(i, (o)) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => ++ $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,o) => { ++ $crate::IResult::Done(i, ($($parsed),* , o)) ++ } ++ } ++ } ++ ); ++ ($i:expr, $consumed:expr, ($($parsed:expr),*)) => ( ++ { ++ $crate::IResult::Done($i, ($($parsed),*)) ++ } ++ ); ++); ++ ++/// `pair!(I -> IResult, I -> IResult) => I -> IResult` ++/// pair(X,Y), returns (x,y) ++/// ++#[macro_export] ++macro_rules! pair( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ pair!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ pair!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ pair!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `separated_pair!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` ++/// separated_pair(X,sep,Y) returns (x,y) ++#[macro_export] ++macro_rules! separated_pair( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( ++ { ++ match tuple_parser!($i, 0usize, (), $submac!($($args)*), $($rest)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1, (o1, _, o2)) => { ++ $crate::IResult::Done(i1, (o1, o2)) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $f:expr, $($rest:tt)+) => ( ++ separated_pair!($i, call!($f), $($rest)*); ++ ); ++); ++ ++/// `preceded!(I -> IResult, I -> IResult) => I -> IResult` ++/// preceded(opening, X) returns X ++#[macro_export] ++macro_rules! preceded( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (_,o)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ preceded!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ preceded!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ preceded!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `terminated!(I -> IResult, I -> IResult) => I -> IResult` ++/// terminated(X, closing) returns X ++#[macro_export] ++macro_rules! terminated( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (o,_)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ terminated!($i, $submac!($($args)*), call!($g)); ++ ); ++ ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ terminated!($i, call!($f), $submac!($($args)*)); ++ ); ++ ++ ($i:expr, $f:expr, $g:expr) => ( ++ terminated!($i, call!($f), call!($g)); ++ ); ++); ++ ++/// `delimited!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` ++/// delimited(opening, X, closing) returns X ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done}; ++/// named!(bracketed, ++/// delimited!( ++/// tag!("("), ++/// take_until!(")"), ++/// tag!(")") ++/// ) ++/// ); ++/// ++/// # fn main() { ++/// let input = &b"(test)"[..]; ++/// assert_eq!(bracketed(input), Done(&b""[..], &b"test"[..])); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! delimited( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( ++ { ++ match tuple_parser!($i, 0usize, (), $submac!($($args)*), $($rest)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1, (_, o, _)) => { ++ $crate::IResult::Done(i1, o) ++ } ++ } ++ } ++ ); ++ ++ ($i:expr, $f:expr, $($rest:tt)+) => ( ++ delimited!($i, call!($f), $($rest)*); ++ ); ++); ++ ++/// `do_parse!(I->IResult >> I->IResult >> ... I->IResult , ( O ) ) => I -> IResult` ++/// do_parse applies sub parsers in a sequence. ++/// it can store intermediary results and make them available ++/// for later parsers ++/// ++/// The input type `I` must implement `nom::InputLength`. ++/// ++/// This combinator will count how much data is consumed by every child parser ++/// and take it into account if there is not enough data ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Incomplete}; ++/// # use nom::Needed; ++/// use nom::be_u8; ++/// ++/// // this parser implements a common pattern in binary formats, ++/// // the TAG-LENGTH-VALUE, where you first recognize a specific ++/// // byte slice, then the next bytes indicate the length of ++/// // the data, then you take that slice and return it ++/// // ++/// // here, we match the tag 42, take the length in the next byte ++/// // and store it in `length`, then use `take!` with `length` ++/// // to obtain the subslice that we store in `bytes`, then return ++/// // `bytes` ++/// named!(tag_length_value, ++/// do_parse!( ++/// tag!( &[ 42u8 ][..] ) >> ++/// length: be_u8 >> ++/// bytes: take!(length) >> ++/// (bytes) ++/// ) ++/// ); ++/// ++/// # fn main() { ++/// let a: Vec = vec!(42, 2, 3, 4, 5); ++/// let result_a: Vec = vec!(3, 4); ++/// let rest_a: Vec = vec!(5); ++/// assert_eq!(tag_length_value(&a[..]), Done(&rest_a[..], &result_a[..])); ++/// ++/// // here, the length is 5, but there are only 3 bytes afterwards (3, 4 and 5), ++/// // so the parser will tell you that you need 7 bytes: one for the tag, ++/// // one for the length, then 5 bytes ++/// let b: Vec = vec!(42, 5, 3, 4, 5); ++/// assert_eq!(tag_length_value(&b[..]), Incomplete(Needed::Size(7))); ++/// # } ++/// ``` ++/// ++/// the result is a tuple, so you can return multiple sub results, like ++/// this: ++/// `do_parse!(I->IResult >> I->IResult >> ... I->IResult , ( O, P ) ) => I -> IResult` ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self, Done, Incomplete}; ++/// # use nom::Needed; ++/// use nom::be_u8; ++/// named!(tag_length_value<(u8, &[u8])>, ++/// do_parse!( ++/// tag!( &[ 42u8 ][..] ) >> ++/// length: be_u8 >> ++/// bytes: take!(length) >> ++/// (length, bytes) ++/// ) ++/// ); ++/// ++/// # fn main() { ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! do_parse ( ++ (__impl $i:expr, $consumed:expr, ( $($rest:expr),* )) => ( ++ $crate::IResult::Done($i, ( $($rest),* )) ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ) => ( ++ do_parse!(__impl $i, $consumed, $submac!( $($args)* )) ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ) => ( ++ compiler_error!("do_parse is missing the return value. A do_parse call must end ++ with a return value between parenthesis, as follows: ++ ++ do_parse!( ++ a: tag!(\"abcd\") >> ++ b: tag!(\"efgh\") >> ++ ++ ( Value { a: a, b: b } ) ++ "); ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) ~ $($rest:tt)* ) => ( ++ compiler_error!("do_parse uses >> as separator, not ~"); ++ ); ++ (__impl $i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) ~ $($rest:tt)* ) => ( ++ compiler_error!("do_parse uses >> as separator, not ~"); ++ ); ++ (__impl $i:expr, $consumed:expr, $field:ident : $e:ident ~ $($rest:tt)*) => ( ++ do_parse!(__impl $i, $consumed, $field: call!($e) ~ $($rest)*); ++ ); ++ (__impl $i:expr, $consumed:expr, $e:ident ~ $($rest:tt)*) => ( ++ do_parse!(__impl $i, $consumed, call!($e) ~ $($rest)*); ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $e:ident >> $($rest:tt)*) => ( ++ do_parse!(__impl $i, $consumed, call!($e) >> $($rest)*); ++ ); ++ (__impl $i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,_) => { ++ let i_ = i.clone(); ++ do_parse!(__impl i_, ++ $consumed + ($crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&i)), $($rest)*) ++ }, ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $field:ident : $e:ident >> $($rest:tt)*) => ( ++ do_parse!(__impl $i, $consumed, $field: call!($e) >> $($rest)*); ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( ++ { ++ let i_ = $i.clone(); ++ match $submac!(i_, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,o) => { ++ let $field = o; ++ let i_ = i.clone(); ++ do_parse!(__impl i_, ++ $consumed + ($crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&i)), $($rest)*) ++ }, ++ } ++ } ++ ); ++ ++ // ending the chain ++ (__impl $i:expr, $consumed:expr, $e:ident >> ( $($rest:tt)* )) => ( ++ do_parse!(__impl $i, $consumed, call!($e) >> ( $($rest)* )); ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,_) => { ++ $crate::IResult::Done(i, ( $($rest)* )) ++ }, ++ } ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $field:ident : $e:ident >> ( $($rest:tt)* )) => ( ++ do_parse!(__impl $i, $consumed, $field: call!($e) >> ( $($rest)* ) ); ++ ); ++ ++ (__impl $i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ( ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => { ++ let (needed,overflowed) = $consumed.overflowing_add(i); ++ match overflowed { ++ true => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ false => $crate::IResult::Incomplete($crate::Needed::Size(needed)), ++ } ++ }, ++ $crate::IResult::Done(i,o) => { ++ let $field = o; ++ $crate::IResult::Done(i, ( $($rest)* )) ++ }, ++ } ++ ); ++ ++ ($i:expr, $($rest:tt)*) => ( ++ { ++ do_parse!(__impl $i, 0usize, $($rest)*) ++ } ++ ); ++ ($submac:ident!( $($args:tt)* ) >> $($rest:tt)* ) => ( ++ compiler_error!("if you are using do_parse outside of a named! macro, you must ++ pass the input data as first argument, like this: ++ ++ let res = do_parse!(input, ++ a: tag!(\"abcd\") >> ++ b: tag!(\"efgh\") >> ++ ( Value { a: a, b: b } ) ++ );"); ++ ); ++ ($e:ident! >> $($rest:tt)* ) => ( ++ do_parse!( call!($e) >> $($rest)*); ++ ); ++); ++ ++#[cfg(test)] ++mod tests { ++ use internal::{Needed,IResult}; ++ use internal::IResult::*; ++ use util::ErrorKind; ++ use nom::be_u16; ++ ++ #[cfg(feature = "verbose-errors")] ++ use verbose_errors::Err; ++ ++ // reproduce the tag and take macros, because of module import order ++ macro_rules! tag ( ++ ($i:expr, $inp: expr) => ( ++ { ++ #[inline(always)] ++ fn as_bytes(b: &T) -> &[u8] { ++ b.as_bytes() ++ } ++ ++ let expected = $inp; ++ let bytes = as_bytes(&expected); ++ ++ tag_bytes!($i,bytes) ++ } ++ ); ++ ); ++ ++ macro_rules! tag_bytes ( ++ ($i:expr, $bytes: expr) => ( ++ { ++ use std::cmp::min; ++ let len = $i.len(); ++ let blen = $bytes.len(); ++ let m = min(len, blen); ++ let reduced = &$i[..m]; ++ let b = &$bytes[..m]; ++ ++ let res: $crate::IResult<_,_> = if reduced != b { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Tag, $i)) ++ } else if m < blen { ++ $crate::IResult::Incomplete($crate::Needed::Size(blen)) ++ } else { ++ $crate::IResult::Done(&$i[blen..], reduced) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ macro_rules! take ( ++ ($i:expr, $count:expr) => ( ++ { ++ let cnt = $count as usize; ++ let res:$crate::IResult<&[u8],&[u8]> = if $i.len() < cnt { ++ $crate::IResult::Incomplete($crate::Needed::Size(cnt)) ++ } else { ++ $crate::IResult::Done(&$i[cnt..],&$i[0..cnt]) ++ }; ++ res ++ } ++ ); ++ ); ++ ++ #[derive(PartialEq,Eq,Debug)] ++ struct B { ++ a: u8, ++ b: u8 ++ } ++ ++ #[derive(PartialEq,Eq,Debug)] ++ struct C { ++ a: u8, ++ b: Option ++ } ++ ++ #[cfg(feature = "verbose-errors")] ++ use util::{error_to_list, add_error_pattern, print_error}; ++ ++ #[cfg(feature = "verbose-errors")] ++ fn error_to_string

(e: &Err

) -> &'static str { ++ let v:Vec = error_to_list(e); ++ // do it this way if you can use slice patterns ++ /* ++ match &v[..] { ++ [ErrorKind::Custom(42), ErrorKind::Tag] => "missing `ijkl` tag", ++ [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] => "missing `mnop` tag after `ijkl`", ++ _ => "unrecognized error" ++ } ++ */ ++ if &v[..] == [ErrorKind::Custom(42),ErrorKind::Tag] { ++ "missing `ijkl` tag" ++ } else if &v[..] == [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] { ++ "missing `mnop` tag after `ijkl`" ++ } else { ++ "unrecognized error" ++ } ++ } ++ ++ // do it this way if you can use box patterns ++ /*use std::str; ++ fn error_to_string(e:Err) -> String ++ match e { ++ NodePosition(ErrorKind::Custom(42), i1, box Position(ErrorKind::Tag, i2)) => { ++ format!("missing `ijkl` tag, found '{}' instead", str::from_utf8(i2).unwrap()) ++ }, ++ NodePosition(ErrorKind::Custom(42), i1, box NodePosition(ErrorKind::Custom(128), i2, box Position(ErrorKind::Tag, i3))) => { ++ format!("missing `mnop` tag after `ijkl`, found '{}' instead", str::from_utf8(i3).unwrap()) ++ }, ++ _ => "unrecognized error".to_string() ++ } ++ }*/ ++ ++ #[cfg(feature = "verbose-errors")] ++ use std::collections; ++ ++ #[cfg(feature = "verbose-errors")] ++ #[test] ++ fn err() { ++ named!(err_test, alt!( ++ tag!("abcd") | ++ preceded!(tag!("efgh"), return_error!(ErrorKind::Custom(42), ++ do_parse!( ++ tag!("ijkl") >> ++ res: return_error!(ErrorKind::Custom(128), tag!("mnop")) >> ++ (res) ++ ) ++ ) ++ ) ++ )); ++ let a = &b"efghblah"[..]; ++ let b = &b"efghijklblah"[..]; ++ let c = &b"efghijklmnop"[..]; ++ ++ let blah = &b"blah"[..]; ++ ++ let res_a = err_test(a); ++ let res_b = err_test(b); ++ let res_c = err_test(c); ++ assert_eq!(res_a, Error(error_node_position!(ErrorKind::Custom(42), blah, error_position!(ErrorKind::Tag, blah)))); ++ assert_eq!(res_b, Error(error_node_position!(ErrorKind::Custom(42), &b"ijklblah"[..], error_node_position!(ErrorKind::Custom(128), blah, error_position!(ErrorKind::Tag, blah))))); ++ assert_eq!(res_c, Done(&b""[..], &b"mnop"[..])); ++ ++ // Merr-like error matching ++ let mut err_map = collections::HashMap::new(); ++ assert!(add_error_pattern(&mut err_map, err_test(&b"efghpouet"[..]), "missing `ijkl` tag")); ++ assert!(add_error_pattern(&mut err_map, err_test(&b"efghijklpouet"[..]), "missing `mnop` tag after `ijkl`")); ++ ++ let res_a2 = res_a.clone(); ++ match res_a { ++ Error(e) => { ++ assert_eq!(error_to_list(&e), [ErrorKind::Custom(42), ErrorKind::Tag]); ++ assert_eq!(error_to_string(&e), "missing `ijkl` tag"); ++ assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `ijkl` tag")); ++ }, ++ _ => panic!() ++ }; ++ ++ let res_b2 = res_b.clone(); ++ match res_b { ++ Error(e) => { ++ assert_eq!(error_to_list(&e), [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag]); ++ assert_eq!(error_to_string(&e), "missing `mnop` tag after `ijkl`"); ++ assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `mnop` tag after `ijkl`")); ++ }, ++ _ => panic!() ++ }; ++ ++ print_error(a, res_a2); ++ print_error(b, res_b2); ++ } ++ ++ #[allow(unused_variables)] ++ #[test] ++ fn add_err() { ++ named!(err_test, ++ preceded!(tag!("efgh"), add_return_error!(ErrorKind::Custom(42), ++ do_parse!( ++ tag!("ijkl") >> ++ res: add_return_error!(ErrorKind::Custom(128), tag!("mnop")) >> ++ (res) ++ ) ++ ) ++ )); ++ let a = &b"efghblah"[..]; ++ let b = &b"efghijklblah"[..]; ++ let c = &b"efghijklmnop"[..]; ++ ++ let blah = &b"blah"[..]; ++ ++ let res_a = err_test(a); ++ let res_b = err_test(b); ++ let res_c = err_test(c); ++ assert_eq!(res_a, Error(error_node_position!(ErrorKind::Custom(42), blah, error_position!(ErrorKind::Tag, blah)))); ++ assert_eq!(res_b, Error(error_node_position!(ErrorKind::Custom(42), &b"ijklblah"[..], error_node_position!(ErrorKind::Custom(128), blah, error_position!(ErrorKind::Tag, blah))))); ++ assert_eq!(res_c, Done(&b""[..], &b"mnop"[..])); ++ } ++ ++ #[test] ++ fn complete() { ++ named!(err_test, ++ do_parse!( ++ tag!("ijkl") >> ++ res: complete!(tag!("mnop")) >> ++ (res) ++ ) ++ ); ++ let a = &b"ijklmn"[..]; ++ ++ let res_a = err_test(a); ++ assert_eq!(res_a, Error(error_position!(ErrorKind::Complete, &b"mn"[..]))); ++ } ++ ++ #[test] ++ fn pair() { ++ named!( tag_abc, tag!("abc") ); ++ named!( tag_def, tag!("def") ); ++ named!( pair_abc_def<&[u8],(&[u8], &[u8])>, pair!(tag_abc, tag_def) ); ++ ++ assert_eq!(pair_abc_def(&b"abcdefghijkl"[..]), Done(&b"ghijkl"[..], (&b"abc"[..], &b"def"[..]))); ++ assert_eq!(pair_abc_def(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(pair_abc_def(&b"abcd"[..]), Incomplete(Needed::Size(6))); ++ assert_eq!(pair_abc_def(&b"xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(pair_abc_def(&b"xxxdef"[..]), Error(error_position!(ErrorKind::Tag, &b"xxxdef"[..]))); ++ assert_eq!(pair_abc_def(&b"abcxxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn separated_pair() { ++ named!( tag_abc, tag!("abc") ); ++ named!( tag_def, tag!("def") ); ++ named!( tag_separator, tag!(",") ); ++ named!( sep_pair_abc_def<&[u8],(&[u8], &[u8])>, separated_pair!(tag_abc, tag_separator, tag_def) ); ++ ++ assert_eq!(sep_pair_abc_def(&b"abc,defghijkl"[..]), Done(&b"ghijkl"[..], (&b"abc"[..], &b"def"[..]))); ++ assert_eq!(sep_pair_abc_def(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(sep_pair_abc_def(&b"abc,d"[..]), Incomplete(Needed::Size(7))); ++ assert_eq!(sep_pair_abc_def(&b"xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(sep_pair_abc_def(&b"xxx,def"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx,def"[..]))); ++ assert_eq!(sep_pair_abc_def(&b"abc,xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn preceded() { ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_efgh, tag!("efgh") ); ++ named!( preceded_abcd_efgh<&[u8], &[u8]>, preceded!(tag_abcd, tag_efgh) ); ++ ++ assert_eq!(preceded_abcd_efgh(&b"abcdefghijkl"[..]), Done(&b"ijkl"[..], &b"efgh"[..])); ++ assert_eq!(preceded_abcd_efgh(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(preceded_abcd_efgh(&b"abcde"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(preceded_abcd_efgh(&b"xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(preceded_abcd_efgh(&b"xxxxdef"[..]), Error(error_position!(ErrorKind::Tag, &b"xxxxdef"[..]))); ++ assert_eq!(preceded_abcd_efgh(&b"abcdxxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn terminated() { ++ named!( tag_abcd, tag!("abcd") ); ++ named!( tag_efgh, tag!("efgh") ); ++ named!( terminated_abcd_efgh<&[u8], &[u8]>, terminated!(tag_abcd, tag_efgh) ); ++ ++ assert_eq!(terminated_abcd_efgh(&b"abcdefghijkl"[..]), Done(&b"ijkl"[..], &b"abcd"[..])); ++ assert_eq!(terminated_abcd_efgh(&b"ab"[..]), Incomplete(Needed::Size(4))); ++ assert_eq!(terminated_abcd_efgh(&b"abcde"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(terminated_abcd_efgh(&b"xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(terminated_abcd_efgh(&b"xxxxdef"[..]), Error(error_position!(ErrorKind::Tag, &b"xxxxdef"[..]))); ++ assert_eq!(terminated_abcd_efgh(&b"abcdxxxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxxx"[..]))); ++ } ++ ++ #[test] ++ fn delimited() { ++ named!( tag_abc, tag!("abc") ); ++ named!( tag_def, tag!("def") ); ++ named!( tag_ghi, tag!("ghi") ); ++ named!( delimited_abc_def_ghi<&[u8], &[u8]>, delimited!(tag_abc, tag_def, tag_ghi) ); ++ ++ assert_eq!(delimited_abc_def_ghi(&b"abcdefghijkl"[..]), Done(&b"jkl"[..], &b"def"[..])); ++ assert_eq!(delimited_abc_def_ghi(&b"ab"[..]), Incomplete(Needed::Size(3))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcde"[..]), Incomplete(Needed::Size(6))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcdefgh"[..]), Incomplete(Needed::Size(9))); ++ assert_eq!(delimited_abc_def_ghi(&b"xxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ assert_eq!(delimited_abc_def_ghi(&b"xxxdefghi"[..]), Error(error_position!(ErrorKind::Tag, &b"xxxdefghi"[..]))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcxxxghi"[..]), Error(error_position!(ErrorKind::Tag, &b"xxxghi"[..]))); ++ assert_eq!(delimited_abc_def_ghi(&b"abcdefxxx"[..]), Error(error_position!(ErrorKind::Tag, &b"xxx"[..]))); ++ } ++ ++ #[test] ++ fn tuple_test() { ++ named!(tuple_3<&[u8], (u16, &[u8], &[u8]) >, ++ tuple!( be_u16 , take!(3), tag!("fg") ) ); ++ ++ assert_eq!(tuple_3(&b"abcdefgh"[..]), Done(&b"h"[..], (0x6162u16, &b"cde"[..], &b"fg"[..]))); ++ assert_eq!(tuple_3(&b"abcd"[..]), Incomplete(Needed::Size(5))); ++ assert_eq!(tuple_3(&b"abcde"[..]), Incomplete(Needed::Size(7))); ++ assert_eq!(tuple_3(&b"abcdejk"[..]), Error(error_position!(ErrorKind::Tag, &b"jk"[..]))); ++ } ++ ++ #[test] ++ fn do_parse() { ++ fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; ++ fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Done(i,2) }; ++ ++ //trace_macros!(true); ++ named!(do_parser<&[u8], (u8, u8)>, ++ do_parse!( ++ tag!("abcd") >> ++ opt!(tag!("abcd")) >> ++ aa: ret_int1 >> ++ tag!("efgh") >> ++ bb: ret_int2 >> ++ tag!("efgh") >> ++ (aa, bb) ++ ) ++ ); ++ //named!(do_parser<&[u8], (u8, u8)>, ++ // do_parse!( ++ // tag!("abcd") >> aa: ret_int1 >> tag!("efgh") >> bb: ret_int2 >> tag!("efgh") >> (aa, bb) ++ // ) ++ //); ++ ++ //trace_macros!(false); ++ ++ assert_eq!(do_parser(&b"abcdabcdefghefghX"[..]), Done(&b"X"[..], (1, 2))); ++ assert_eq!(do_parser(&b"abcdefghefghX"[..]), Done(&b"X"[..], (1, 2))); ++ assert_eq!(do_parser(&b"abcdab"[..]), Incomplete(Needed::Size(8))); ++ assert_eq!(do_parser(&b"abcdefghef"[..]), Incomplete(Needed::Size(12))); ++ } ++ ++ #[test] ++ fn do_parse_dependency() { ++ use nom::be_u8; ++ ++ named!(length_value, ++ do_parse!( ++ length: be_u8 >> ++ bytes: take!(length) >> ++ (bytes) ++ ) ++ ); ++ ++ let a = [2u8, 3, 4, 5]; ++ let res_a = [3u8, 4]; ++ assert_eq!(length_value(&a[..]), Done(&a[3..], &res_a[..])); ++ let b = [5u8, 3, 4, 5]; ++ assert_eq!(length_value(&b[..]), Incomplete(Needed::Size(6))); ++ } ++ ++ /* ++ named!(does_not_compile, ++ do_parse!( ++ length: be_u8 >> ++ bytes: take!(length) ++ ) ++ ); ++ named!(does_not_compile_either, ++ do_parse!( ++ length: be_u8 ~ ++ bytes: take!(length) ~ ++ ( () ) ++ ) ++ ); ++ fn still_does_not_compile() { ++ let data = b"abcd"; ++ ++ let res = do_parse!( ++ tag!("abcd") >> ++ tag!("efgh") >> ++ ( () ) ++ ); ++ } ++ */ ++} +diff --git third_party/rust/nom/src/simple_errors.rs third_party/rust/nom/src/simple_errors.rs +new file mode 100644 +index 000000000000..04bddd4309bf +--- /dev/null ++++ third_party/rust/nom/src/simple_errors.rs +@@ -0,0 +1,153 @@ ++//! Error management ++//! ++//! there are two ways to handle errors in nom. The first one, ++//! activated by default, uses the `nom::ErrorKind` enum ++//! in the error branch of `IResult`. This enum can hold either ++//! a parser specific error code, or a custom error type you ++//! specify. ++//! ++//! If you need more advanced error management, you can activate ++//! the "verbose-errors" compilation feature, which will give you ++//! the error system available in nom 1.0. The verbose errors ++//! accumulate error codes and positions as you backtrack through ++//! the parser tree. From there, you can precisely identify which ++//! parts of the input triggered the error case. ++//! ++//! Please note that the verbose error management is a bit slower ++//! than the simple one. ++use util::ErrorKind; ++use internal::{IResult, IError}; ++use internal::IResult::*; ++ ++pub type Err = ErrorKind; ++ ++impl IResult { ++ /// Maps a `IResult` to `IResult` by appling a function ++ /// to a contained `Error` value, leaving `Done` and `Incomplete` value ++ /// untouched. ++ #[inline] ++ pub fn map_err(self, f: F) -> IResult ++ where F: FnOnce(Err) -> Err { ++ match self { ++ Error(e) => Error(f(e)), ++ Incomplete(n) => Incomplete(n), ++ Done(i, o) => Done(i, o), ++ } ++ } ++ ++ /// Unwrap the contained `Error(E)` value, or panic if the `IResult` is not ++ /// `Error`. ++ pub fn unwrap_err(self) -> Err { ++ match self { ++ Error(e) => e, ++ Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"), ++ Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"), ++ } ++ } ++ ++ /// Convert the IResult to a std::result::Result ++ pub fn to_full_result(self) -> Result> { ++ match self { ++ Done(_, o) => Ok(o), ++ Incomplete(n) => Err(IError::Incomplete(n)), ++ Error(e) => Err(IError::Error(e)) ++ } ++ } ++ ++ /// Convert the IResult to a std::result::Result, or panic if the `IResult` is `Incomplete` ++ pub fn to_result(self) -> Result> { ++ match self { ++ Done(_, o) => Ok(o), ++ Error(e) => Err(e), ++ Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete") ++ } ++ } ++} ++ ++#[cfg(feature = "std")] ++use std::any::Any; ++#[cfg(feature = "std")] ++use std::{error,fmt}; ++#[cfg(feature = "std")] ++impl error::Error for Err { ++ fn description(&self) -> &str { ++ self.description() ++ } ++} ++ ++#[cfg(feature = "std")] ++impl fmt::Display for Err { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ write!(f, "{}", self.description()) ++ } ++} ++ ++/// translate parser result from IResult to IResult with a custom type ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use std::collections; ++/// # use nom::IResult::Error; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// // will add a Custom(42) error to the error chain ++/// named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd"))); ++/// // Convert to IREsult<&[u8], &[u8], &str> ++/// named!(parser<&[u8], &[u8], &str>, add_return_error!(ErrorKind::Custom("custom error message"), fix_error!(&str, err_test))); ++/// ++/// let a = &b"efghblah"[..]; ++/// let res_a = parser(a); ++/// assert_eq!(res_a, Error(error_node_position!( ErrorKind::Custom("custom error message"), a, Position(ErrorKind::Fix, a)))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fix_error ( ++ ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(_) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::IResult::Error(e) ++ } ++ } ++ } ++ ); ++ ($i:expr, $t:ty, $f:expr) => ( ++ fix_error!($i, $t, call!($f)); ++ ); ++); ++ ++/// `flat_map!(R -> IResult, S -> IResult) => R -> IResult` ++/// ++/// combines a parser R -> IResult and ++/// a parser S -> IResult to return another ++/// parser R -> IResult ++#[macro_export] ++macro_rules! flat_map( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), ++ $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(ref i2)) => $crate::IResult::Incomplete($crate::Needed::Size(*i2)), ++ $crate::IResult::Done(_, o2) => $crate::IResult::Done(i, o2) ++ } ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ flat_map!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ flat_map!($i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ flat_map!($i, call!($f), $submac!($($args)*)); ++ ); ++); +diff --git third_party/rust/nom/src/str.rs third_party/rust/nom/src/str.rs +index 768786edaba1..4f8643bd3e68 100644 +--- third_party/rust/nom/src/str.rs ++++ third_party/rust/nom/src/str.rs +@@ -21,15 +21,32 @@ + macro_rules! tag_s ( + ($i:expr, $tag: expr) => ( + { +- let res: $crate::IResult<_,_> = if $tag.len() > $i.len() { +- $crate::IResult::Incomplete($crate::Needed::Size($tag.len())) +- //} else if &$i[0..$tag.len()] == $tag { +- } else if ($i).starts_with($tag) { +- $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()]) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagStr, $i)) +- }; +- res ++ tag!($i, $tag) ++ } ++ ); ++); ++ ++/// `tag_no_case_s!(&str) => &str -> IResult<&str, &str>` ++/// declares a case-insensitive string as a suite to recognize ++/// ++/// consumes the recognized characters ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::{self,Done}; ++/// # fn main() { ++/// fn test(input: &str) -> IResult<&str, &str> { ++/// tag_no_case_s!(input, "ABcd") ++/// } ++/// let r = test("aBCdefgh"); ++/// assert_eq!(r, Done("efgh", "aBCd")); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! tag_no_case_s ( ++ ($i:expr, $tag: expr) => ( ++ { ++ tag_no_case!($i, $tag) + } + ); + ); +@@ -47,28 +64,19 @@ macro_rules! tag_s ( + /// let a = "abcdefgh"; + /// + /// assert_eq!(take5(a), Done("fgh", "abcde")); ++/// ++/// let b = "12345"; ++/// ++/// assert_eq!(take5(b), Done("", "12345")); + /// # } + /// ``` + #[macro_export] + macro_rules! take_s ( + ($i:expr, $count:expr) => ( + { ++ let input = $i; + let cnt = $count as usize; +- let res: $crate::IResult<_,_> = if $i.chars().count() < cnt { +- $crate::IResult::Incomplete($crate::Needed::Size(cnt)) +- } else { +- let mut offset = $i.len(); +- let mut count = 0; +- for (o, _) in $i.char_indices() { +- if count == cnt { +- offset = o; +- break; +- } +- count += 1; +- } +- $crate::IResult::Done(&$i[offset..], &$i[..offset]) +- }; +- res ++ take!(input, cnt) + } + ); + ); +@@ -91,22 +99,7 @@ macro_rules! take_s ( + macro_rules! is_not_s ( + ($input:expr, $arr:expr) => ( + { +- use std::collections::HashSet; +- let set: HashSet = $arr.chars().collect(); +- let mut offset = $input.len(); +- for (o, c) in $input.char_indices() { +- if set.contains(&c) { +- offset = o; +- break; +- } +- } +- if offset == 0 { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsAStr,$input)) +- } else if offset < $input.len() { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Done("", $input) +- } ++ is_not!($input, $arr) + } + ); + ); +@@ -131,22 +124,7 @@ macro_rules! is_not_s ( + macro_rules! is_a_s ( + ($input:expr, $arr:expr) => ( + { +- use std::collections::HashSet; +- let set: HashSet = $arr.chars().collect(); +- let mut offset = $input.len(); +- for (o, c) in $input.char_indices() { +- if !set.contains(&c) { +- offset = o; +- break; +- } +- } +- if offset == 0 { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::IsAStr,$input)) +- } else if offset < $input.len() { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Done("", $input) +- } ++ is_a!($input, $arr) + } + ); + ); +@@ -173,18 +151,7 @@ macro_rules! is_a_s ( + macro_rules! take_while_s ( + ($input:expr, $submac:ident!( $($args:tt)* )) => ( + { +- let mut offset = $input.len(); +- for (o, c) in $input.char_indices() { +- if !$submac!(c, $($args)*) { +- offset = o; +- break; +- } +- } +- if offset < $input.len() { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Done("", $input) +- } ++ take_while!($input, $submac!($($args)*)) + } + ); + ($input:expr, $f:expr) => ( +@@ -211,22 +178,7 @@ macro_rules! take_while_s ( + #[macro_export] + macro_rules! take_while1_s ( + ($input:expr, $submac:ident!( $($args:tt)* )) => ( +- { +- let mut offset = $input.len(); +- for (o, c) in $input.char_indices() { +- if !$submac!(c, $($args)*) { +- offset = o; +- break; +- } +- } +- if offset == 0 { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeWhile1Str,$input)) +- } else if offset < $input.len() { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Done("", $input) +- } +- } ++ take_while1!($input, $submac!($($args)*)) + ); + ($input:expr, $f:expr) => ( + take_while1_s!($input, call!($f)); +@@ -234,27 +186,15 @@ macro_rules! take_while1_s ( + ); + + +-/// `take_till_s!(&str -> bool) => &str -> IResult<&str, &str>` ++/// `take_till_s!(char -> bool) => &str -> IResult<&str, &str>` + /// returns the longest list of characters until the provided function succeeds + /// + /// The argument is either a function `char -> bool` or a macro returning a `bool + #[macro_export] + macro_rules! take_till_s ( + ($input:expr, $submac:ident!( $($args:tt)* )) => ( +- + { +- let mut offset = $input.len(); +- for (o, c) in $input.char_indices() { +- if $submac!(c, $($args)*) { +- offset = o; +- break; +- } +- } +- if offset < $input.len() { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Done("", $input) +- } ++ take_till!($input, $submac!($($args)*)) + } + ); + ($input:expr, $f:expr) => ( +@@ -262,48 +202,29 @@ macro_rules! take_till_s ( + ); + ); + ++/// `take_till1_s!(char -> bool) => &str -> IResult<&str, &str>` ++/// returns the longest non empty list of characters until the provided function succeeds ++/// ++/// The argument is either a function `char -> bool` or a macro returning a `bool ++#[macro_export] ++macro_rules! take_till1_s ( ++ ($input:expr, $submac:ident!( $($args:tt)* )) => ( ++ { ++ take_till1!($input, $submac!($($args)*)) ++ } ++ ); ++ ($input:expr, $f:expr) => ( ++ take_till1_s!($input, call!($f)); ++ ); ++); ++ + /// `take_until_and_consume_s!(&str) => &str -> IResult<&str, &str>` + /// generates a parser consuming all chars until the specified string is found and consumes it + #[macro_export] + macro_rules! take_until_and_consume_s ( + ($input:expr, $substr:expr) => ( + { +- #[inline(always)] +- fn shift_window_and_cmp(window: & mut ::std::vec::Vec, c: char, substr_vec: & ::std::vec::Vec) -> bool { +- window.push(c); +- if window.len() > substr_vec.len() { +- window.remove(0); +- } +- window == substr_vec +- } +- let res: $crate::IResult<_, _> = if $substr.len() > $input.len() { +- $crate::IResult::Incomplete($crate::Needed::Size($substr.len())) +- } else { +- let substr_vec: ::std::vec::Vec = $substr.chars().collect(); +- let mut window: ::std::vec::Vec = vec![]; +- let mut offset = $input.len(); +- let mut parsed = false; +- for (o, c) in $input.char_indices() { +- if parsed { +- // The easiest way to get the byte offset of the char after the found string +- offset = o; +- break; +- } +- if shift_window_and_cmp(& mut window, c, &substr_vec) { +- parsed = true; +- } +- } +- if parsed { +- if offset < $input.len() { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Done("", $input) +- } +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilAndConsumeStr,$input)) +- } +- }; +- res ++ take_until_and_consume!($input, $substr) + } + ); + ); +@@ -314,39 +235,7 @@ macro_rules! take_until_and_consume_s ( + macro_rules! take_until_s ( + ($input:expr, $substr:expr) => ( + { +- #[inline(always)] +- fn shift_window_and_cmp(window: & mut Vec, c: char, substr_vec: &Vec) -> bool { +- window.push(c); +- if window.len() > substr_vec.len() { +- window.remove(0); +- } +- window == substr_vec +- } +- let res: $crate::IResult<&str, &str> = if $substr.len() > $input.len() { +- $crate::IResult::Incomplete($crate::Needed::Size($substr.len())) +- } else { +- let substr_vec: Vec = $substr.chars().collect(); +- let mut window: Vec = vec![]; +- let mut offset = $input.len(); +- let mut parsed = false; +- for (o, c) in $input.char_indices() { +- if shift_window_and_cmp(& mut window, c, &substr_vec) { +- parsed = true; +- window.pop(); +- let window_len: usize = window.iter() +- .map(|x| x.len_utf8()) +- .fold(0, |x, y| x + y); +- offset = o - window_len; +- break; +- } +- } +- if parsed { +- $crate::IResult::Done(&$input[offset..], &$input[..offset]) +- } else { +- $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TakeUntilStr,$input)) +- } +- }; +- res ++ take_until!($input, $substr) + } + ); + ); +@@ -451,8 +340,8 @@ mod test { + } + } + +- use internal::IResult::{Done, Error}; +- use internal::Err::Position; ++ use internal::IResult::{Done, Error, Incomplete}; ++ use internal::Needed; + use util::ErrorKind; + + pub fn is_alphabetic(c:char) -> bool { +@@ -480,10 +369,10 @@ mod test { + let c = "abcd123"; + let d = "123"; + +- assert_eq!(f(&a[..]), Error(Position(ErrorKind::TakeWhile1Str, &""[..]))); ++ assert_eq!(f(&a[..]), Incomplete(Needed::Size(1))); + assert_eq!(f(&b[..]), Done(&a[..], &b[..])); + assert_eq!(f(&c[..]), Done(&"123"[..], &b[..])); +- assert_eq!(f(&d[..]), Error(Position(ErrorKind::TakeWhile1Str, &d[..]))); ++ assert_eq!(f(&d[..]), Error(error_position!(ErrorKind::TakeWhile1, &d[..]))); + } + + #[test] +@@ -557,16 +446,16 @@ mod test { + fn take_until_and_consume_s_succeed() { + const INPUT: &'static str = "βèƒôřèÂßÇáƒƭèř"; + const FIND: &'static str = "ÂßÇ"; +- const CONSUMED: &'static str = "βèƒôřèÂßÇ"; ++ const OUTPUT: &'static str = "βèƒôřè"; + const LEFTOVER: &'static str = "áƒƭèř"; + + match take_until_and_consume_s!(INPUT, FIND) { + IResult::Done(extra, output) => { + assert!(extra == LEFTOVER, "Parser `take_until_and_consume_s`\ + consumed leftover input. Leftover `{}`.", extra); +- assert!(output == CONSUMED, "Parser `take_until_and_consume_s`\ +- doens't return the string it consumed on success. Expected `{}`, got `{}`.", +- CONSUMED, output); ++ assert!(output == OUTPUT, "Parser `take_until_and_consume_s`\ ++ doens't return the string it selected on success. Expected `{}`, got `{}`.", ++ OUTPUT, output); + } + other => panic!("Parser `take_until_and_consume_s` didn't succeed when it should have. \ + Got `{:?}`.", other), +@@ -731,4 +620,39 @@ mod test { + Got `{:?}`.", other), + }; + } ++ ++ #[test] ++ #[cfg(feature = "std")] ++ fn recognize_is_a_s() { ++ let a = "aabbab"; ++ let b = "ababcd"; ++ ++ named!(f <&str,&str>, recognize!(many1!(alt!( tag_s!("a") | tag_s!("b") )))); ++ ++ assert_eq!(f(&a[..]), Done(&a[6..], &a[..])); ++ assert_eq!(f(&b[..]), Done(&b[4..], &b[..4])); ++ ++ } ++ ++ #[test] ++ fn utf8_indexing() { ++ named!(dot(&str) -> &str, ++ tag_s!(".") ++ ); ++ ++ dot("點"); ++ } ++ ++ #[test] ++ fn case_insensitive() { ++ named!(test<&str,&str>, tag_no_case!("ABcd")); ++ assert_eq!(test("aBCdefgh"), Done("efgh", "aBCd")); ++ assert_eq!(test("abcdefgh"), Done("efgh", "abcd")); ++ assert_eq!(test("ABCDefgh"), Done("efgh", "ABCD")); ++ ++ named!(test2<&str,&str>, tag_no_case!("ABcd")); ++ assert_eq!(test2("aBCdefgh"), Done("efgh", "aBCd")); ++ assert_eq!(test2("abcdefgh"), Done("efgh", "abcd")); ++ assert_eq!(test2("ABCDefgh"), Done("efgh", "ABCD")); ++ } + } +diff --git third_party/rust/nom/src/stream.rs third_party/rust/nom/src/stream.rs +index 38d5c870c938..4d92bed75c8e 100644 +--- third_party/rust/nom/src/stream.rs ++++ third_party/rust/nom/src/stream.rs +@@ -212,9 +212,11 @@ impl<'x,'b> Producer<'b,&'x[u8],Move> for MemProducer<'x> { + } + } + { +- use std::cmp; +- let end = cmp::min(self.index + self.chunk_size, self.length); +- consumer.handle(Input::Element(&self.buffer[self.index..end])) ++ if self.index + self.chunk_size > self.length { ++ consumer.handle(Input::Eof(Some(&self.buffer[self.index..self.length]))) ++ } else { ++ consumer.handle(Input::Element(&self.buffer[self.index..self.index + self.chunk_size])) ++ } + } else { + consumer.state() + } +@@ -259,7 +261,15 @@ impl FileProducer { + shift(&mut self.v, self.start, self.end); + self.end = self.end - self.start; + self.start = 0; +- match self.file.read(&mut self.v[self.end..]) { ++ ++ let remaining = &mut self.v[self.end..]; ++ ++ // already full, prevents erroneous Eof below ++ if remaining.is_empty() { ++ return Some(0); ++ } ++ ++ match self.file.read(remaining) { + Err(_) => { + self.state = FileProducerState::Error; + None +@@ -494,7 +504,7 @@ macro_rules! consumer_from_parser ( + + impl $crate::Consumer<$input, $output, (), $crate::Move> for $name { + fn handle(&mut self, input: $crate::Input<$input>) -> & $crate::ConsumerState<$output, (), $crate::Move> { +- use $crate::HexDisplay; ++ use $crate::Offset; + match input { + $crate::Input::Empty | $crate::Input::Eof(None) => &self.state, + $crate::Input::Element(sl) | $crate::Input::Eof(Some(sl)) => { +@@ -537,7 +547,7 @@ macro_rules! consumer_from_parser ( + + impl<'a> $crate::Consumer<&'a[u8], $output, (), $crate::Move> for $name { + fn handle(&mut self, input: $crate::Input<&'a[u8]>) -> & $crate::ConsumerState<$output, (), $crate::Move> { +- use $crate::HexDisplay; ++ use $crate::Offset; + match input { + $crate::Input::Empty | $crate::Input::Eof(None) => &self.state, + $crate::Input::Element(sl) | $crate::Input::Eof(Some(sl)) => { +@@ -577,7 +587,7 @@ macro_rules! consumer_from_parser ( + mod tests { + use super::*; + use internal::IResult; +- use util::HexDisplay; ++ use util::Offset; + use std::str::from_utf8; + use std::io::SeekFrom; + +@@ -897,8 +907,8 @@ mod tests { + } + }*/ + +- fn lf(i:& u8) -> bool { +- *i == '\n' as u8 ++ fn lf(i:u8) -> bool { ++ i == '\n' as u8 + } + fn to_utf8_string(input:&[u8]) -> String { + String::from(from_utf8(input).unwrap()) +@@ -938,6 +948,27 @@ mod tests { + //assert!(false); + } + ++ #[test] ++ fn small_buffer() { ++ let mut f = FileProducer::new("LICENSE", 10 /* smaller than a line */).unwrap(); ++ let mut a = LineConsumer::new(); ++ ++ for i in 0..2 { ++ match f.apply(&mut a) { ++ &ConsumerState::Continue(Move::Await(_)) => {} ++ _ => assert!(false, "LineConsumer should be awaiting more input: {}", i), ++ } ++ assert_eq!(FileProducerState::Normal, f.state()); ++ } ++ ++ f.resize(200 /* large enough for a line */); ++ match f.apply(&mut a) { ++ &ConsumerState::Done(..) => {} ++ _ => assert!(false, "LineConsumer should have succeeded"), ++ } ++ assert_eq!(FileProducerState::Normal, f.state()); ++ } ++ + #[derive(Debug,Clone,Copy,PartialEq,Eq)] + enum SeekState { + Begin, +diff --git third_party/rust/nom/src/traits.rs third_party/rust/nom/src/traits.rs +new file mode 100644 +index 000000000000..e8103336b147 +--- /dev/null ++++ third_party/rust/nom/src/traits.rs +@@ -0,0 +1,623 @@ ++//! Traits input types have to implement to work with nom combinators ++//! ++use std::ops::{Range,RangeTo,RangeFrom,RangeFull}; ++use std::iter::Enumerate; ++use std::slice::Iter; ++ ++use std::str::Chars; ++use std::str::CharIndices; ++use std::str::FromStr; ++use std::str::from_utf8; ++ ++use memchr; ++ ++ ++/// abstract method to calculate the input length ++pub trait InputLength { ++ /// calculates the input length, as indicated by its name, ++ /// and the name of the trait itself ++ #[inline] ++ fn input_len(&self) -> usize; ++} ++ ++impl<'a, T> InputLength for &'a[T] { ++ #[inline] ++ fn input_len(&self) -> usize { ++ self.len() ++ } ++} ++ ++impl<'a> InputLength for &'a str { ++ #[inline] ++ fn input_len(&self) -> usize { ++ self.len() ++ } ++} ++ ++impl<'a> InputLength for (&'a [u8], usize) { ++ #[inline] ++ fn input_len(&self) -> usize { ++ //println!("bit input length for ({:?}, {}):", self.0, self.1); ++ let res = self.0.len() * 8 - self.1; ++ //println!("-> {}", res); ++ res ++ } ++} ++ ++/// transforms common types to a char for basic token parsing ++pub trait AsChar { ++ /// makes a char from self ++ #[inline] ++ fn as_char(self) -> char; ++ ++ /// tests that self is an alphabetic character ++ /// ++ /// warning: for `&str` it recognizes alphabetic ++ /// characters outside of the 52 ASCII letters ++ #[inline] ++ fn is_alpha(self) -> bool; ++ ++ /// tests that self is an alphabetic character ++ /// or a decimal digit ++ #[inline] ++ fn is_alphanum(self) -> bool; ++ /// tests that self is a decimal digit ++ #[inline] ++ fn is_dec_digit(self) -> bool; ++ /// tests that self is an hex digit ++ #[inline] ++ fn is_hex_digit(self) -> bool; ++ /// tests that self is an octal digit ++ #[inline] ++ fn is_oct_digit(self) -> bool; ++ /// gets the len in bytes for self ++ #[inline] ++ fn len(self) -> usize; ++} ++ ++impl AsChar for u8 { ++ #[inline] ++ fn as_char(self) -> char { self as char } ++ #[inline] ++ fn is_alpha(self) -> bool { ++ (self >= 0x41 && self <= 0x5A) || (self >= 0x61 && self <= 0x7A) ++ } ++ #[inline] ++ fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } ++ #[inline] ++ fn is_dec_digit(self) -> bool { ++ self >= 0x30 && self <= 0x39 ++ } ++ #[inline] ++ fn is_hex_digit(self) -> bool { ++ (self >= 0x30 && self <= 0x39) || ++ (self >= 0x41 && self <= 0x46) || ++ (self >= 0x61 && self <= 0x66) ++ } ++ #[inline] ++ fn is_oct_digit(self) -> bool { ++ self >= 0x30 && self <= 0x37 ++ } ++ #[inline] ++ fn len(self) -> usize { ++ 1 ++ } ++} ++impl<'a> AsChar for &'a u8 { ++ #[inline] ++ fn as_char(self) -> char { *self as char } ++ #[inline] ++ fn is_alpha(self) -> bool { ++ (*self >= 0x41 && *self <= 0x5A) || (*self >= 0x61 && *self <= 0x7A) ++ } ++ #[inline] ++ fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } ++ #[inline] ++ fn is_dec_digit(self) -> bool { ++ *self >= 0x30 && *self <= 0x39 ++ } ++ #[inline] ++ fn is_hex_digit(self) -> bool { ++ (*self >= 0x30 && *self <= 0x39) || ++ (*self >= 0x41 && *self <= 0x46) || ++ (*self >= 0x61 && *self <= 0x66) ++ } ++ #[inline] ++ fn is_oct_digit(self) -> bool { ++ *self >= 0x30 && *self <= 0x37 ++ } ++ #[inline] ++ fn len(self) -> usize { ++ 1 ++ } ++} ++ ++impl AsChar for char { ++ #[inline] ++ fn as_char(self) -> char { self } ++ #[inline] ++ fn is_alpha(self) -> bool { self.is_alphabetic() } ++ #[inline] ++ fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } ++ #[inline] ++ fn is_dec_digit(self) -> bool { self.is_digit(10) } ++ #[inline] ++ fn is_hex_digit(self) -> bool { self.is_digit(16) } ++ #[inline] ++ fn is_oct_digit(self) -> bool { self.is_digit(8) } ++ #[inline] ++ fn len(self) -> usize { self.len_utf8() } ++} ++ ++impl<'a> AsChar for &'a char { ++ #[inline] ++ fn as_char(self) -> char { self.clone() } ++ #[inline] ++ fn is_alpha(self) -> bool { self.is_alphabetic() } ++ #[inline] ++ fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } ++ #[inline] ++ fn is_dec_digit(self) -> bool { self.is_digit(10) } ++ #[inline] ++ fn is_hex_digit(self) -> bool { self.is_digit(16) } ++ #[inline] ++ fn is_oct_digit(self) -> bool { self.is_digit(8) } ++ #[inline] ++ fn len(self) -> usize { self.len_utf8() } ++} ++ ++/// abstracts common iteration operations on the input type ++/// ++/// it needs a distinction between `Item` and `RawItem` because ++/// `&[T]` iterates on references ++pub trait InputIter { ++ type Item; ++ type RawItem; ++ type Iter : Iterator; ++ type IterElem : Iterator; ++ ++ /// returns an iterator over the elements and their byte offsets ++ fn iter_indices(&self) -> Self::Iter; ++ /// returns an iterator over the elements ++ fn iter_elements(&self) -> Self::IterElem; ++ /// finds the byte position of the element ++ fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool; ++ /// get the byte offset from the element's position in the stream ++ fn slice_index(&self, count:usize) -> Option; ++} ++ ++/// abstracts slicing operations ++pub trait InputTake { ++ /// returns a slice of `count` bytes ++ fn take

(&self, count: usize) -> Option<&Self>; ++ /// split the stream at the `count` byte offset ++ fn take_split

(&self, count: usize) -> Option<(&Self,&Self)>; ++} ++ ++impl<'a> InputIter for &'a [u8] { ++ type Item = &'a u8; ++ type RawItem = u8; ++ type Iter = Enumerate>; ++ type IterElem = Iter<'a, Self::RawItem>; ++ ++ #[inline] ++ fn iter_indices(&self) -> Self::Iter { ++ self.iter().enumerate() ++ } ++ #[inline] ++ fn iter_elements(&self) -> Self::IterElem { ++ self.iter() ++ } ++ #[inline] ++ fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool { ++ self.iter().position(|b| predicate(*b)) ++ } ++ #[inline] ++ fn slice_index(&self, count:usize) -> Option { ++ if self.len() >= count { ++ Some(count) ++ } else { ++ None ++ } ++ } ++} ++ ++impl InputTake for [u8] { ++ #[inline] ++ fn take

(&self, count: usize) -> Option<&Self> { ++ if self.len() >= count { ++ Some(&self[0..count]) ++ } else { ++ None ++ } ++ } ++ #[inline] ++ fn take_split

(&self, count: usize) -> Option<(&Self,&Self)> { ++ if self.len() >= count { ++ Some((&self[count..],&self[..count])) ++ } else { ++ None ++ } ++ } ++} ++ ++impl<'a> InputIter for &'a str { ++ type Item = char; ++ type RawItem = char; ++ type Iter = CharIndices<'a>; ++ type IterElem = Chars<'a>; ++ #[inline] ++ fn iter_indices(&self) -> Self::Iter { ++ self.char_indices() ++ } ++ #[inline] ++ fn iter_elements(&self) -> Self::IterElem { ++ self.chars() ++ } ++ fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool { ++ for (o,c) in self.char_indices() { ++ if predicate(c) { ++ return Some(o) ++ } ++ } ++ None ++ } ++ #[inline] ++ fn slice_index(&self, count:usize) -> Option { ++ let mut cnt = 0; ++ for (index, _) in self.char_indices() { ++ if cnt == count { ++ return Some(index) ++ } ++ cnt += 1; ++ } ++ if cnt == count { ++ return Some(self.len()) ++ } ++ None ++ } ++} ++ ++impl InputTake for str { ++ #[inline] ++ fn take

(&self, count: usize) -> Option<&Self> { ++ let mut cnt = 0; ++ for (index, _) in self.char_indices() { ++ if cnt == count { ++ return Some(&self[..index]) ++ } ++ cnt += 1; ++ } ++ None ++ } ++ ++ // return byte index ++ #[inline] ++ fn take_split

(&self, count: usize) -> Option<(&Self,&Self)> { ++ let mut cnt = 0; ++ for (index, _) in self.char_indices() { ++ if cnt == count { ++ return Some((&self[index..],&self[..index])) ++ } ++ cnt += 1; ++ } ++ None ++ } ++} ++ ++/// indicates wether a comparison was successful, an error, or ++/// if more data was needed ++#[derive(Debug,PartialEq)] ++pub enum CompareResult { ++ Ok, ++ Incomplete, ++ Error ++} ++ ++/// abstracts comparison operations ++pub trait Compare { ++ /// compares self to another value for equality ++ fn compare(&self, t:T) -> CompareResult; ++ /// compares self to another value for equality ++ /// independently of the case. ++ /// ++ /// warning: for `&str`, the comparison is done ++ /// by lowercasing both strings and comparing ++ /// the result. This is a temporary solution until ++ /// a better one appears ++ fn compare_no_case(&self, t:T) -> CompareResult; ++} ++ ++impl<'a,'b> Compare<&'b[u8]> for &'a [u8] { ++ #[inline(always)] ++ fn compare(&self, t: &'b[u8]) -> CompareResult { ++ let len = self.len(); ++ let blen = t.len(); ++ let m = if len < blen { len } else { blen }; ++ let reduced = &self[..m]; ++ let b = &t[..m]; ++ ++ if reduced != b { ++ CompareResult::Error ++ } else if m < blen { ++ CompareResult::Incomplete ++ } else { ++ CompareResult::Ok ++ } ++ } ++ ++ #[inline(always)] ++ fn compare_no_case(&self, t: &'b[u8]) -> CompareResult { ++ let len = self.len(); ++ let blen = t.len(); ++ let m = if len < blen { len } else { blen }; ++ let reduced = &self[..m]; ++ let other = &t[..m]; ++ ++ if !reduced.iter().zip(other).all(|(a, b)| { ++ match (*a,*b) { ++ (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == b, ++ (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122 ) |(97...122, 65...90) => { ++ *a | 0b00100000 == *b | 0b00100000 ++ } ++ _ => false ++ } ++ }) { ++ CompareResult::Error ++ } else if m < blen { ++ CompareResult::Incomplete ++ } else { ++ CompareResult::Ok ++ } ++ } ++} ++ ++impl<'a,'b> Compare<&'b str> for &'a [u8] { ++ #[inline(always)] ++ fn compare(&self, t: &'b str) -> CompareResult { ++ self.compare(str::as_bytes(t)) ++ } ++ #[inline(always)] ++ fn compare_no_case(&self, t: &'b str) -> CompareResult { ++ self.compare_no_case(str::as_bytes(t)) ++ } ++} ++ ++impl<'a,'b> Compare<&'b str> for &'a str { ++ #[inline(always)] ++ fn compare(&self, t: &'b str) -> CompareResult { ++ let pos = self.chars().zip(t.chars()).position(|(a,b)| a != b); ++ ++ match pos { ++ Some(_) => CompareResult::Error, ++ None => if self.len() >= t.len() { ++ CompareResult::Ok ++ } else { ++ CompareResult::Incomplete ++ } ++ } ++ } ++ ++ //FIXME: this version is too simple and does not use the current locale ++ #[inline(always)] ++ fn compare_no_case(&self, t: &'b str) -> CompareResult { ++ let pos = self.to_lowercase().chars().zip(t.to_lowercase().chars()).position(|(a,b)| a != b); ++ ++ match pos { ++ Some(_) => CompareResult::Error, ++ None => if self.len() >= t.len() { ++ CompareResult::Ok ++ } else { ++ CompareResult::Incomplete ++ } ++ } ++ } ++} ++ ++/// look for self in the given input stream ++pub trait FindToken { ++ fn find_token(&self, input: T) -> bool; ++} ++ ++impl<'a> FindToken<&'a[u8]> for u8 { ++ fn find_token(&self, input: &[u8]) -> bool { ++ memchr::memchr(*self, input).is_some() ++ } ++} ++ ++impl<'a> FindToken<&'a str> for u8 { ++ fn find_token(&self, input: &str) -> bool { ++ self.find_token(str::as_bytes(input)) ++ } ++} ++ ++impl<'a,'b> FindToken<&'a[u8]> for &'b u8 { ++ fn find_token(&self, input: &[u8]) -> bool { ++ memchr::memchr(**self, input).is_some() ++ } ++} ++ ++impl<'a,'b> FindToken<&'a str> for &'b u8 { ++ fn find_token(&self, input: &str) -> bool { ++ self.find_token(str::as_bytes(input)) ++ } ++} ++ ++impl<'a> FindToken<&'a str> for char { ++ fn find_token(&self, input: &str) -> bool { ++ for i in input.chars() { ++ if *self == i { return true } ++ } ++ false ++ } ++} ++ ++/// look for a substring in self ++pub trait FindSubstring { ++ fn find_substring(&self, substr: T) -> Option; ++} ++ ++impl<'a,'b> FindSubstring<&'b [u8]> for &'a[u8] { ++ fn find_substring(&self, substr: &'b[u8]) -> Option { ++ let substr_len = substr.len(); ++ ++ if substr_len == 0 { ++ None ++ } else if substr_len == 1 { ++ memchr::memchr(substr[0], self) ++ } else { ++ let max = self.len() - substr_len; ++ let mut offset = 0; ++ let mut haystack = &self[..]; ++ ++ while let Some(position) = memchr::memchr(substr[0], haystack) { ++ offset += position; ++ ++ if offset > max { ++ return None ++ } ++ ++ if &haystack[position..position + substr_len] == substr { ++ return Some(offset) ++ } ++ ++ haystack = &haystack[position + 1..]; ++ offset += 1; ++ } ++ ++ None ++ } ++ } ++} ++ ++impl<'a,'b> FindSubstring<&'b str> for &'a[u8] { ++ fn find_substring(&self, substr: &'b str) -> Option { ++ self.find_substring(str::as_bytes(substr)) ++ } ++} ++ ++impl<'a,'b> FindSubstring<&'b str> for &'a str { ++ //returns byte index ++ fn find_substring(&self, substr: &'b str) -> Option { ++ self.find(substr) ++ } ++} ++ ++/// used to integrate str's parse() method ++pub trait ParseTo { ++ fn parse_to(&self) -> Option; ++} ++ ++impl<'a,R: FromStr> ParseTo for &'a[u8] { ++ fn parse_to(&self) -> Option { ++ from_utf8(self).ok().and_then(|s| s.parse().ok()) ++ } ++} ++ ++impl<'a,R:FromStr> ParseTo for &'a str { ++ fn parse_to(&self) -> Option { ++ self.parse().ok() ++ } ++} ++ ++/// slicing operations using ranges ++/// ++/// this trait is loosely based on ++/// `Index`, but can actually return ++/// something else than a `&[T]` or `&str` ++pub trait Slice { ++ #[inline(always)] ++ fn slice(&self, range: R) -> Self; ++} ++ ++macro_rules! impl_fn_slice { ++ ( $ty:ty ) => { ++ fn slice(&self, range:$ty) -> Self { ++ &self[range] ++ } ++ } ++} ++ ++macro_rules! slice_range_impl { ++ ( [ $for_type:ident ], $ty:ty ) => { ++ impl<'a, $for_type> Slice<$ty> for &'a [$for_type] { ++ impl_fn_slice!( $ty ); ++ } ++ }; ++ ( $for_type:ty, $ty:ty ) => { ++ impl<'a> Slice<$ty> for &'a $for_type { ++ impl_fn_slice!( $ty ); ++ } ++ } ++} ++ ++macro_rules! slice_ranges_impl { ++ ( [ $for_type:ident ] ) => { ++ slice_range_impl! {[$for_type], Range} ++ slice_range_impl! {[$for_type], RangeTo} ++ slice_range_impl! {[$for_type], RangeFrom} ++ slice_range_impl! {[$for_type], RangeFull} ++ }; ++ ( $for_type:ty ) => { ++ slice_range_impl! {$for_type, Range} ++ slice_range_impl! {$for_type, RangeTo} ++ slice_range_impl! {$for_type, RangeFrom} ++ slice_range_impl! {$for_type, RangeFull} ++ } ++} ++ ++slice_ranges_impl! {str} ++slice_ranges_impl! {[T]} ++ ++ ++macro_rules! array_impls { ++ ($($N:expr)+) => { ++ $( ++ impl InputLength for [u8; $N] { ++ #[inline] ++ fn input_len(&self) -> usize { ++ self.len() ++ } ++ } ++ ++ impl<'a> InputLength for &'a [u8; $N] { ++ #[inline] ++ fn input_len(&self) -> usize { ++ self.len() ++ } ++ } ++ ++ impl<'a> Compare<[u8; $N]> for &'a [u8] { ++ #[inline(always)] ++ fn compare(&self, t: [u8; $N]) -> CompareResult { ++ self.compare(&t[..]) ++ } ++ ++ #[inline(always)] ++ fn compare_no_case(&self, t: [u8;$N]) -> CompareResult { ++ self.compare_no_case(&t[..]) ++ } ++ } ++ ++ impl<'a,'b> Compare<&'b [u8; $N]> for &'a [u8] { ++ #[inline(always)] ++ fn compare(&self, t: &'b [u8; $N]) -> CompareResult { ++ self.compare(&t[..]) ++ } ++ ++ #[inline(always)] ++ fn compare_no_case(&self, t: &'b [u8;$N]) -> CompareResult { ++ self.compare_no_case(&t[..]) ++ } ++ } ++ )+ ++ }; ++} ++ ++ ++array_impls! { ++ 0 1 2 3 4 5 6 7 8 9 ++ 10 11 12 13 14 15 16 17 18 19 ++ 20 21 22 23 24 25 26 27 28 29 ++ 30 31 32 ++} +diff --git third_party/rust/nom/src/util.rs third_party/rust/nom/src/util.rs +index e2428ead0a4d..75663b958284 100644 +--- third_party/rust/nom/src/util.rs ++++ third_party/rust/nom/src/util.rs +@@ -1,19 +1,27 @@ +-use internal::{IResult,Err}; + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "verbose-errors")] ++use internal::IResult; ++ ++#[cfg(feature = "verbose-errors")] ++use verbose_errors::Err; ++ ++#[cfg(feature = "std")] + use std::collections::HashMap; + +-#[cfg(feature = "core")] ++#[cfg(not(feature = "std"))] + use std::prelude::v1::*; ++ + use std::vec::Vec; + use std::string::ToString; + + /// useful functions to calculate the offset between slices and show a hexdump of a slice +-#[cfg(not(feature = "core"))] +-pub trait HexDisplay { ++pub trait Offset { + /// offset between the first byte of self and the first byte of the argument +- fn offset(&self, second:&[u8]) -> usize;// OFFSET SHOULD GO TO ITS OWN TRAIT ++ fn offset(&self, second:&Self) -> usize; ++} + ++#[cfg(feature = "std")] ++pub trait HexDisplay { + /// Converts the value of `self` to a hex dump, returning the owned + /// string. + fn to_hex(&self, chunk_size: usize) -> String; +@@ -23,130 +31,28 @@ pub trait HexDisplay { + fn to_hex_from(&self, chunk_size: usize, from: usize) -> String; + } + +-pub trait InputLength { +- #[inline] +- fn input_len(&self) -> usize; +-} +- +-impl<'a, T> InputLength for &'a[T] { +- #[inline] +- fn input_len(&self) -> usize { +- self.len() +- } +-} ++static CHARS: &'static[u8] = b"0123456789abcdef"; + +-impl<'a> InputLength for &'a str { +- #[inline] +- fn input_len(&self) -> usize { +- self.len() +- } +-} ++impl Offset for [u8] { ++ fn offset(&self, second:&[u8]) -> usize { ++ let fst = self.as_ptr(); ++ let snd = second.as_ptr(); + +-impl<'a> InputLength for (&'a [u8], usize) { +- #[inline] +- fn input_len(&self) -> usize { +- //println!("bit input length for ({:?}, {}):", self.0, self.1); +- let res = self.0.len() * 8 - self.1; +- //println!("-> {}", res); +- res ++ snd as usize - fst as usize + } + } + +-use std::iter::Enumerate; +-#[cfg(not(feature = "core"))] +-use std::str::CharIndices; +- +-pub trait AsChar { +- #[inline] +- fn as_char(self) -> char; +- #[inline] +- fn is_alpha(self) -> bool; +- #[inline] +- fn is_alphanum(self) -> bool; +- #[inline] +- fn is_0_to_9(self) -> bool; +- #[inline] +- fn is_hex_digit(self) -> bool; +- #[inline] +- fn is_oct_digit(self) -> bool; +-} ++impl Offset for str { ++ fn offset(&self, second: &Self) -> usize { ++ let fst = self.as_ptr(); ++ let snd = second.as_ptr(); + +-impl<'a> AsChar for &'a u8 { +- #[inline] +- fn as_char(self) -> char { *self as char } +- #[inline] +- fn is_alpha(self) -> bool { +- (*self >= 0x41 && *self <= 0x5A) || (*self >= 0x61 && *self <= 0x7A) +- } +- #[inline] +- fn is_alphanum(self) -> bool { self.is_alpha() || self.is_0_to_9() } +- #[inline] +- fn is_0_to_9(self) -> bool { +- *self >= 0x30 && *self <= 0x39 ++ snd as usize - fst as usize + } +- #[inline] +- fn is_hex_digit(self) -> bool { +- (*self >= 0x30 && *self <= 0x39) || +- (*self >= 0x41 && *self <= 0x46) || +- (*self >= 0x61 && *self <= 0x66) +- } +- #[inline] +- fn is_oct_digit(self) -> bool { +- *self >= 0x30 && *self <= 0x37 +- } +-} +- +-impl AsChar for char { +- #[inline] +- fn as_char(self) -> char { self } +- #[inline] +- fn is_alpha(self) -> bool { self.is_alphabetic() } +- #[inline] +- fn is_alphanum(self) -> bool { self.is_alpha() || self.is_0_to_9() } +- #[inline] +- fn is_0_to_9(self) -> bool { self.is_digit(10) } +- #[inline] +- fn is_hex_digit(self) -> bool { self.is_digit(16) } +- #[inline] +- fn is_oct_digit(self) -> bool { self.is_digit(8) } + } + +-pub trait IterIndices { +- type Item: AsChar; +- type Iter : Iterator; +- fn iter_indices(self) -> Self::Iter; +-} +- +-impl<'a> IterIndices for &'a [u8] { +- type Item = &'a u8; +- type Iter = Enumerate<::std::slice::Iter<'a, u8>>; +- #[inline] +- fn iter_indices(self) -> Enumerate<::std::slice::Iter<'a, u8>> { +- self.iter().enumerate() +- } +-} +- +-#[cfg(not(feature = "core"))] +-impl<'a> IterIndices for &'a str { +- type Item = char; +- type Iter = CharIndices<'a>; +- #[inline] +- fn iter_indices(self) -> CharIndices<'a> { +- self.char_indices() +- } +-} +- +-static CHARS: &'static[u8] = b"0123456789abcdef"; +- +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] + impl HexDisplay for [u8] { +- fn offset(&self, second:&[u8]) -> usize { +- let fst = self.as_ptr(); +- let snd = second.as_ptr(); +- +- snd as usize - fst as usize +- } +- + #[allow(unused_variables)] + fn to_hex(&self, chunk_size: usize) -> String { + self.to_hex_from(chunk_size, 0) +@@ -241,7 +147,7 @@ macro_rules! dbg ( + /// + /// It also displays the input in hexdump format + /// +-/// ``` ++/// ```ignore + /// # #[macro_use] extern crate nom; + /// # fn main() { + /// named!(f, dbg_dmp!( tag!( "abcd" ) ) ); +@@ -278,32 +184,44 @@ macro_rules! dbg_dmp ( + ); + ); + ++#[cfg(feature = "verbose-errors")] + pub fn error_to_list(e:&Err) -> Vec> { + let mut v:Vec> = Vec::new(); +- let mut err = e; +- loop { +- match *err { +- Err::Code(ref i) | Err::Position(ref i,_) => { ++ match e { ++ &Err::Code(ref i) | &Err::Position(ref i,_) => { + v.push(i.clone()); + return v; +- }, +- Err::Node(ref i, ref next) | Err::NodePosition(ref i, _, ref next) => { +- v.push(i.clone()); +- err = &*next; +- } +- } ++ }, ++ &Err::Node(ref i, ref next) | &Err::NodePosition(ref i, _, ref next) => { ++ //v.push(i.clone()); ++ for error in next.iter() { ++ if let &Err::Code(ref i2) = error { ++ v.push(i2.clone()); ++ } ++ if let &Err::Position(ref i2,_) = error { ++ v.push(i2.clone()); ++ } ++ } ++ v.push(i.clone()); ++ v.reverse() ++ } + } ++ ++ v + } + ++#[cfg(feature = "verbose-errors")] + pub fn compare_error_paths(e1:&Err, e2:&Err) -> bool { + error_to_list(e1) == error_to_list(e2) + } + + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] ++#[cfg(feature = "verbose-errors")] + use std::hash::Hash; + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] ++#[cfg(feature = "verbose-errors")] + pub fn add_error_pattern<'a,I,O,E: Clone+Hash+Eq>(h: &mut HashMap>, &'a str>, res: IResult, message: &'a str) -> bool { + if let IResult::Error(e) = res { + h.insert(error_to_list(&e), message); +@@ -320,32 +238,33 @@ pub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) { + (off1, off2) + } + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] ++#[cfg(feature = "verbose-errors")] + pub fn prepare_errors(input: &[u8], res: IResult<&[u8],O,E>) -> Option, usize, usize)> > { + if let IResult::Error(e) = res { + let mut v:Vec<(ErrorKind, usize, usize)> = Vec::new(); +- let mut err = e.clone(); +- loop { +- match err { +- Err::Position(i,s) => { +- let (o1, o2) = slice_to_offsets(input, s); +- v.push((i, o1, o2)); +- //println!("v is: {:?}", v); +- break; +- }, +- Err::NodePosition(i, s, next) => { +- let (o1, o2) = slice_to_offsets(input, s); ++ ++ match e { ++ Err::Code(_) => {}, ++ Err::Position(i, p) => { ++ let (o1, o2) = slice_to_offsets(input, p); + v.push((i, o1, o2)); +- err = *next; +- }, +- Err::Node(_, next) => { +- err = *next; +- }, +- Err::Code(_) => { +- break; +- } +- } ++ }, ++ Err::Node(_, _) => {}, ++ Err::NodePosition(i, p, next) => { ++ //v.push(i.clone()); ++ for error in next.iter() { ++ if let &Err::Position(ref i2, ref p2) = error { ++ let (o1, o2) = slice_to_offsets(input, p2); ++ v.push((i2.clone(), o1, o2)); ++ } ++ } ++ let (o1, o2) = slice_to_offsets(input, p); ++ v.push((i, o1, o2)); ++ v.reverse() ++ } + } ++ + v.sort_by(|a, b| a.1.cmp(&b.1)); + Some(v) + } else { +@@ -353,7 +272,8 @@ pub fn prepare_errors(input: &[u8], res: IResult<&[u8],O,E>) -> Opti + } + } + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] ++#[cfg(feature = "verbose-errors")] + pub fn print_error(input: &[u8], res: IResult<&[u8],O,E>) { + if let Some(v) = prepare_errors(input, res) { + let colors = generate_colors(&v); +@@ -365,7 +285,8 @@ pub fn print_error(input: &[u8], res: IResult<&[u8],O,E>) { + } + } + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] ++#[cfg(feature = "verbose-errors")] + pub fn generate_colors(v: &[(ErrorKind, usize, usize)]) -> HashMap { + let mut h: HashMap = HashMap::new(); + let mut color = 0; +@@ -417,7 +338,7 @@ pub fn write_color(v: &mut Vec, color: u8) { + v.push('m' as u8); + } + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] + pub fn print_codes(colors: HashMap, names: HashMap) -> String { + let mut v = Vec::new(); + for (code, &color) in &colors { +@@ -439,7 +360,8 @@ pub fn print_codes(colors: HashMap, names: HashMap) -> Strin + String::from_utf8_lossy(&v[..]).into_owned() + } + +-#[cfg(not(feature = "core"))] ++#[cfg(feature = "std")] ++#[cfg(feature = "verbose-errors")] + pub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String { + let mut v = Vec::with_capacity(input.len() * 3); + let mut i = from; +@@ -599,6 +521,7 @@ pub enum ErrorKind { + SeparatedNonEmptyList, + Many0, + Many1, ++ ManyTill, + Count, + TakeUntilAndConsume, + TakeUntil, +@@ -642,7 +565,10 @@ pub enum ErrorKind { + ManyMN, + TakeUntilAndConsumeStr, + TakeUntilStr, +- Not ++ Not, ++ Permutation, ++ Verify, ++ TakeTill1, + } + + pub fn error_to_u32(e: &ErrorKind) -> u32 { +@@ -702,6 +628,10 @@ pub fn error_to_u32(e: &ErrorKind) -> u32 { + ErrorKind::OctDigit => 61, + ErrorKind::Many0 => 62, + ErrorKind::Not => 63, ++ ErrorKind::Permutation => 64, ++ ErrorKind::ManyTill => 65, ++ ErrorKind::Verify => 66, ++ ErrorKind::TakeTill1 => 67, + } + } + +@@ -763,7 +693,46 @@ pub fn error_to_u32(e: &ErrorKind) -> u32 { + ErrorKind::TakeUntilStr => "Take until on strings", + ErrorKind::OctDigit => "Octal digit", + ErrorKind::Not => "Negation", ++ ErrorKind::Permutation => "Permutation", ++ ErrorKind::ManyTill => "ManyTill", ++ ErrorKind::Verify => "predicate verification", ++ ErrorKind::TakeTill1 => "TakeTill1", + } + + } ++ /// Convert Err into an ErrorKind. ++ /// ++ /// This allows application code to use ErrorKind and stay independent from the `verbose-errors` features activation. ++ pub fn into_error_kind(self) -> ErrorKind { ++ self ++ } + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ ++ #[test] ++ fn test_offset_u8() { ++ let s = b"abcd123"; ++ let a = &s[..]; ++ let b = &a[2..]; ++ let c = &a[..4]; ++ let d = &a[3..5]; ++ assert_eq!(a.offset(b), 2); ++ assert_eq!(a.offset(c), 0); ++ assert_eq!(a.offset(d), 3); ++ } ++ ++ #[test] ++ fn test_offset_str() { ++ let s = "abcřèÂßÇd123"; ++ let a = &s[..]; ++ let b = &a[7..]; ++ let c = &a[..5]; ++ let d = &a[5..9]; ++ assert_eq!(a.offset(b), 7); ++ assert_eq!(a.offset(c), 0); ++ assert_eq!(a.offset(d), 5); ++ } ++} +diff --git third_party/rust/nom/src/verbose_errors.rs third_party/rust/nom/src/verbose_errors.rs +new file mode 100644 +index 000000000000..fe236b6c930a +--- /dev/null ++++ third_party/rust/nom/src/verbose_errors.rs +@@ -0,0 +1,227 @@ ++//! Error management ++//! ++//! there are two ways to handle errors in nom. The first one, ++//! activated by default, uses the `nom::ErrorKind` enum ++//! in the error branch of `IResult`. This enum can hold either ++//! a parser specific error code, or a custom error type you ++//! specify. ++//! ++//! If you need more advanced error management, you can activate ++//! the "verbose-errors" compilation feature, which will give you ++//! the error system available in nom 1.0. The verbose errors ++//! accumulate error codes and positions as you backtrack through ++//! the parser tree. From there, you can precisely identify which ++//! parts of the input triggered the error case. ++//! ++//! Please note that the verbose error management is a bit slower ++//! than the simple one. ++use util::ErrorKind; ++use internal::{IResult, IError}; ++use internal::IResult::*; ++ ++/// Contains the error that a parser can return ++/// ++/// If you use the `verbose-errors` compilation feature, ++/// `nom::Err` will be the enum defined here, ++/// otherwise, it will amount to a `ErrorKind`. ++/// ++/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data. ++/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32) ++#[derive(Debug,PartialEq,Eq,Clone)] ++pub enum Err{ ++ /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E ++ Code(ErrorKind), ++ /// An error code, and the next error ++ Node(ErrorKind, Vec>), ++ /// An error code, and the input position ++ Position(ErrorKind, P), ++ /// An error code, the input position and the next error ++ NodePosition(ErrorKind, P, Vec>) ++} ++ ++impl Err { ++ /// Convert Err into ErrorKind. ++ /// ++ /// This allows application code to use ErrorKind and stay independent from the verbose-errors features activation. ++ pub fn into_error_kind(self) -> ErrorKind { ++ match self { ++ Err::Code(kind) => kind, ++ Err::Node(kind, _) => kind, ++ Err::Position(kind, _) => kind, ++ Err::NodePosition(kind, _, _) => kind, ++ } ++ } ++} ++ ++impl IResult { ++ /// Maps a `IResult` to `IResult` by appling a function ++ /// to a contained `Error` value, leaving `Done` and `Incomplete` value ++ /// untouched. ++ #[inline] ++ pub fn map_err(self, f: F) -> IResult ++ where F: FnOnce(Err) -> Err { ++ match self { ++ Error(e) => Error(f(e)), ++ Incomplete(n) => Incomplete(n), ++ Done(i, o) => Done(i, o), ++ } ++ } ++ ++ /// Unwrap the contained `Error(I, E)` value, or panic if the `IResult` is not ++ /// `Error`. ++ pub fn unwrap_err(self) -> Err { ++ match self { ++ Error(e) => e, ++ Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"), ++ Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"), ++ } ++ } ++ ++ /// Convert the IResult to a std::result::Result ++ pub fn to_full_result(self) -> Result> { ++ match self { ++ Done(_, o) => Ok(o), ++ Incomplete(n) => Err(IError::Incomplete(n)), ++ Error(e) => Err(IError::Error(e)) ++ } ++ } ++ ++ /// Convert the IResult to a std::result::Result ++ pub fn to_result(self) -> Result> { ++ match self { ++ Done(_, o) => Ok(o), ++ Error(e) => Err(e), ++ Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete") ++ } ++ } ++} ++ ++#[cfg(feature = "std")] ++use std::any::Any; ++#[cfg(feature = "std")] ++use std::{error,fmt}; ++#[cfg(feature = "std")] ++use std::fmt::Debug; ++#[cfg(feature = "std")] ++impl error::Error for Err { ++ fn description(&self) -> &str { ++ let kind = match *self { ++ Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e ++ }; ++ kind.description() ++ } ++} ++ ++#[cfg(feature = "std")] ++impl fmt::Display for Err { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ match *self { ++ Err::Code(ref e) | Err::Node(ref e, _) => { ++ write!(f, "{:?}", e) ++ }, ++ Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => { ++ write!(f, "{:?}:{:?}", p, e) ++ } ++ } ++ } ++} ++ ++ ++/// translate parser result from IResult to IResult with a custom type ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use std::collections; ++/// # use nom::IResult::Error; ++/// # use nom::Err::{Position,NodePosition}; ++/// # use nom::ErrorKind; ++/// # fn main() { ++/// // will add a Custom(42) error to the error chain ++/// named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd"))); ++/// // Convert to IREsult<&[u8], &[u8], &str> ++/// named!(parser<&[u8], &[u8], &str>, add_return_error!(ErrorKind::Custom("custom error message"), fix_error!(&str, err_test))); ++/// ++/// let a = &b"efghblah"[..]; ++/// let res_a = parser(a); ++/// assert_eq!(res_a, Error(NodePosition( ErrorKind::Custom("custom error message"), a, vec!(Position(ErrorKind::Fix, a))))); ++/// # } ++/// ``` ++#[macro_export] ++macro_rules! fix_error ( ++ ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o), ++ $crate::IResult::Error(e) => { ++ let err = match e { ++ $crate::Err::Code($crate::ErrorKind::Custom(_)) | ++ $crate::Err::Node($crate::ErrorKind::Custom(_), _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Code(e) ++ }, ++ $crate::Err::Position($crate::ErrorKind::Custom(_), p) | ++ $crate::Err::NodePosition($crate::ErrorKind::Custom(_), p, _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Position(e, p) ++ }, ++ $crate::Err::Code(_) | ++ $crate::Err::Node(_, _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Code(e) ++ }, ++ $crate::Err::Position(_, p) | ++ $crate::Err::NodePosition(_, p, _) => { ++ let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix; ++ $crate::Err::Position(e, p) ++ }, ++ }; ++ $crate::IResult::Error(err) ++ } ++ } ++ } ++ ); ++ ($i:expr, $t:ty, $f:expr) => ( ++ fix_error!($i, $t, call!($f)); ++ ); ++); ++ ++/// `flat_map!(R -> IResult, S -> IResult) => R -> IResult` ++/// ++/// combines a parser R -> IResult and ++/// a parser S -> IResult to return another ++/// parser R -> IResult ++#[macro_export] ++macro_rules! flat_map( ++ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ { ++ match $submac!($i, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)), ++ $crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) { ++ $crate::IResult::Error(e) => { ++ let err = match e { ++ $crate::Err::Code(k) | $crate::Err::Node(k, _) | $crate::Err::Position(k, _) | $crate::Err::NodePosition(k, _, _) => { ++ $crate::Err::Position(k, $i) ++ } ++ }; ++ $crate::IResult::Error(err) ++ }, ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(ref i2)) => $crate::IResult::Incomplete($crate::Needed::Size(*i2)), ++ $crate::IResult::Done(_, o2) => $crate::IResult::Done(i, o2) ++ } ++ } ++ } ++ ); ++ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ flat_map!($i, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $f:expr, $g:expr) => ( ++ flat_map!($i, call!($f), call!($g)); ++ ); ++ ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ flat_map!($i, call!($f), $submac!($($args)*)); ++ ); ++); +diff --git third_party/rust/nom/src/whitespace.rs third_party/rust/nom/src/whitespace.rs +new file mode 100644 +index 000000000000..3b8f7bd5bdae +--- /dev/null ++++ third_party/rust/nom/src/whitespace.rs +@@ -0,0 +1,1056 @@ ++//! Support for whitespace delimited formats ++//! ++//! a lot of textual formats allows spaces and other ++//! types of separators between tokens. Handling it ++//! manually with nom means wrapping all parsers ++//! like this: ++//! ++//! ```ignore ++//! named!(token, delimited!(space, tk, space)); ++//! ``` ++//! ++//! To ease the development of such parsers, you ++//! can use the whitespace parsing facility, which works ++//! as follows: ++//! ++//! ``` ++//! # #[macro_use] extern crate nom; ++//! # use nom::IResult::Done; ++//! # fn main() { ++//! named!(tuple<&[u8], (&[u8], &[u8]) >, ++//! ws!(tuple!( take!(3), tag!("de") )) ++//! ); ++//! ++//! assert_eq!( ++//! tuple(&b" \t abc de fg"[..]), ++//! Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])) ++//! ); ++//! # } ++//! ``` ++//! ++//! The `ws!` combinator will modify the parser to ++//! intersperse space parsers everywhere. By default, ++//! it will consume the following characters: " \t\r\n". ++//! ++//! If you want to modify that behaviour, you can make ++//! your own whitespace wrapper. As an example, if ++//! you don't want to consume ends of lines, only ++//! spaces and tabs, you can do it like this: ++//! ++//! ``` ++//! # #[macro_use] extern crate nom; ++//! # use nom::IResult::Done; ++//! named!(pub space, eat_separator!(&b" \t"[..])); ++//! ++//! #[macro_export] ++//! macro_rules! sp ( ++//! ($i:expr, $($args:tt)*) => ( ++//! { ++//! sep!($i, space, $($args)*) ++//! } ++//! ) ++//! ); ++//! ++//! # fn main() { ++//! named!(tuple<&[u8], (&[u8], &[u8]) >, ++//! sp!(tuple!( take!(3), tag!("de") )) ++//! ); ++//! ++//! assert_eq!( ++//! tuple(&b" \t abc de fg"[..]), ++//! Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])) ++//! ); ++//! # } ++//! ``` ++//! ++//! This combinator works by replacing each combinator with ++//! a version that supports wrapping with separator parsers. ++//! It will not support the combinators you wrote in your ++//! own code. You can still manually wrap them with the separator ++//! you want, or you can copy the macros defined in src/whitespace.rs ++//! and modify them to support a new combinator: ++//! * copy the combinator's code here, add the _sep suffix ++//! * add the `$separator:expr` as second argument ++//! * wrap any sub parsers with sep!($separator, $submac!($($args)*)) ++//! * reference it in the definition of `sep!` as follows: ++//! ++//! ```ignore ++//! ($i:expr, $separator:ident, my_combinator ! ($($rest:tt)*) ) => { ++//! wrap_sep!($i, ++//! $separator, ++//! my_combinator_sep!($separator, $($rest)*) ++//! ) ++//! }; ++//! ``` ++//! ++ ++#[macro_export] ++macro_rules! wrap_sep ( ++ ($i:expr, $separator:expr, $submac:ident!( $($args:tt)* )) => ( ++ match ($separator)($i) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i1,_) => { ++ match $submac!(i1, $($args)*) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i1)))), ++ $crate::IResult::Done(i2,o) => { ++ match ($separator)(i2) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i2)))), ++ $crate::IResult::Done(i3,_) => $crate::IResult::Done(i3, o) ++ } ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $separator:expr, $f:expr) => ( ++ wrap_sep!($i, $separator, call!($f)) ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! pair_sep ( ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ tuple!( ++ $i, ++ sep!($separator, $submac!($($args)*)), ++ sep!($separator, $submac2!($($args2)*)) ++ ) ++ ); ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ pair_sep!($i, $separator, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ pair_sep!($i, $separator, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $g:expr) => ( ++ pair_sep!($i, $separator, call!($f), call!($g)); ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! delimited_sep ( ++ ($i:expr, $separator:ident, $submac1:ident!( $($args1:tt)* ), $($rest:tt)+) => ( ++ match tuple_sep!($i, $separator, 0usize, (), $submac1!($($args1)*), $($rest)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (_,o,_)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $f:expr, $($rest:tt)+) => ( ++ delimited_sep!($i, $separator, call!($f), $($rest)*); ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! separated_pair_sep ( ++ ($i:expr, $separator:ident, $submac1:ident!( $($args1:tt)* ), $($rest:tt)+) => ( ++ match tuple_sep!($i, $separator, 0usize, (), $submac1!($($args1)*), $($rest)*) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (o1,_,o2)) => { ++ $crate::IResult::Done(remaining, (o1,o2)) ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $f:expr, $($rest:tt)+) => ( ++ separated_pair_sep!($i, $separator, call!($f), $($rest)*); ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! preceded_sep ( ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (_,o)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ preceded_sep!($i, $separator, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ preceded_sep!($i, $separator, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $g:expr) => ( ++ preceded_sep!($i, $separator, call!($f), call!($g)); ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! terminated_sep ( ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) { ++ $crate::IResult::Error(a) => $crate::IResult::Error(a), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(remaining, (o,_)) => { ++ $crate::IResult::Done(remaining, o) ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ terminated_sep!($i, $separator, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ terminated_sep!($i, $separator, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $g:expr) => ( ++ terminated_sep!($i, $separator, call!($f), call!($g)); ++ ); ++); ++ ++/// Internal parser, do not use directly ++#[doc(hidden)] ++#[macro_export] ++macro_rules! tuple_sep ( ++ ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => ( ++ tuple_sep!($i, $separator, $consumed, ($($parsed),*), call!($e), $($rest)*); ++ ); ++ ($i:expr, $separator:ident, $consumed:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ tuple_sep!(i, $separator, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), (o), $($rest)*) ++ } ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ tuple_sep!(i, $separator, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), ($($parsed)* , o), $($rest)*) ++ } ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt),*), $e:ident) => ( ++ tuple_sep!($i, $separator, $consumed, ($($parsed),*), call!($e)); ++ ); ++ ($i:expr, $separator:ident, $consumed:expr, (), $submac:ident!( $($args:tt)* )) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ $crate::IResult::Done(i, (o)) ++ } ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $consumed:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ $crate::IResult::Done(i, ($($parsed),* , o)) ++ } ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $consumed:expr, ($($parsed:expr),*)) => ( ++ { ++ $crate::IResult::Done($i, ($($parsed),*)) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! do_parse_sep ( ++ (__impl $i:expr, $separator:ident, $consumed:expr, ( $($rest:expr),* )) => ( ++ $crate::IResult::Done($i, ( $($rest),* )) ++ ); ++ ++ (__impl $i:expr, $separator:ident, $consumed:expr, $e:ident >> $($rest:tt)*) => ( ++ do_parse_sep!(__impl $i, $separator, $consumed, call!($e) >> $($rest)*); ++ ); ++ (__impl $i:expr, $separator:ident, $consumed:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => ++ $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,_) => { ++ do_parse_sep!(__impl i, $separator, ++ $consumed + ($crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&i)), $($rest)*) ++ }, ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $separator:ident, $consumed:expr, $field:ident : $e:ident >> $($rest:tt)*) => ( ++ do_parse_sep!(__impl $i, $separator, $consumed, $field: call!($e) >> $($rest)*); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => ++ $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ let $field = o; ++ do_parse_sep!(__impl i, $separator, ++ $consumed + ($crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&i)), $($rest)*) ++ }, ++ } ++ } ++ ); ++ ++ // ending the chain ++ (__impl $i:expr, $separator:ident, $consumed:expr, $e:ident >> ( $($rest:tt)* )) => ( ++ do_parse_sep!(__impl $i, $separator, $consumed, call!($e) >> ( $($rest)* )); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $consumed:expr, $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ( ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => ++ $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,_) => { ++ $crate::IResult::Done(i, ( $($rest)* )) ++ }, ++ } ++ ); ++ ++ (__impl $i:expr, $separator:ident, $consumed:expr, $field:ident : $e:ident >> ( $($rest:tt)* )) => ( ++ do_parse_sep!(__impl $i, $separator, $consumed, $field: call!($e) >> ( $($rest)* ) ); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ( ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(e), ++ $crate::IResult::Incomplete($crate::Needed::Unknown) => ++ $crate::IResult::Incomplete($crate::Needed::Unknown), ++ $crate::IResult::Incomplete($crate::Needed::Size(i)) => ++ $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)), ++ $crate::IResult::Done(i,o) => { ++ let $field = o; ++ $crate::IResult::Done(i, ( $($rest)* )) ++ }, ++ } ++ ); ++ ++ ($i:expr, $separator:ident, $($rest:tt)*) => ( ++ { ++ do_parse_sep!(__impl $i, $separator, 0usize, $($rest)*) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! permutation_sep ( ++ ($i:expr, $separator:ident, $($rest:tt)*) => ( ++ { ++ let mut res = permutation_init!((), $($rest)*); ++ let mut input = $i; ++ let mut error = ::std::option::Option::None; ++ let mut needed = ::std::option::Option::None; ++ ++ loop { ++ let mut all_done = true; ++ permutation_iterator_sep!(0, input, $separator, all_done, needed, res, $($rest)*); ++ ++ //if we reach that part, it means none of the parsers were able to read anything ++ if !all_done { ++ //FIXME: should wrap the error returned by the child parser ++ error = ::std::option::Option::Some(error_position!($crate::ErrorKind::Permutation, input)); ++ } ++ break; ++ } ++ ++ if let ::std::option::Option::Some(need) = needed { ++ if let $crate::Needed::Size(sz) = need { ++ $crate::IResult::Incomplete( ++ $crate::Needed::Size( ++ $crate::InputLength::input_len(&($i)) - ++ $crate::InputLength::input_len(&input) + ++ sz ++ ) ++ ) ++ } else { ++ $crate::IResult::Incomplete($crate::Needed::Unknown) ++ } ++ } else if let ::std::option::Option::Some(e) = error { ++ $crate::IResult::Error(e) ++ } else { ++ let unwrapped_res = permutation_unwrap!(0, (), res, $($rest)*); ++ $crate::IResult::Done(input, unwrapped_res) ++ } ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! permutation_iterator_sep ( ++ ($it:tt,$i:expr, $separator:ident, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => ( ++ permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, call!($e), $($rest)*); ++ ); ++ ($it:tt, $i:expr, $separator:ident, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { ++ if acc!($it, $res) == ::std::option::Option::None { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Done(i,o) => { ++ $i = i; ++ acc!($it, $res) = ::std::option::Option::Some(o); ++ continue; ++ }, ++ $crate::IResult::Error(_) => { ++ $all_done = false; ++ }, ++ $crate::IResult::Incomplete(i) => { ++ $needed = ::std::option::Option::Some(i); ++ break; ++ } ++ }; ++ } ++ succ!($it, permutation_iterator_sep!($i, $separator, $all_done, $needed, $res, $($rest)*)); ++ }; ++ ($it:tt,$i:expr, $separator:ident, $all_done:expr, $needed:expr, $res:expr, $e:ident) => ( ++ permutation_iterator_sep!($it, $i, $separator, $all_done, $res, call!($e)); ++ ); ++ ($it:tt, $i:expr, $separator:ident, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => { ++ if acc!($it, $res) == ::std::option::Option::None { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Done(i,o) => { ++ $i = i; ++ acc!($it, $res) = ::std::option::Option::Some(o); ++ continue; ++ }, ++ $crate::IResult::Error(_) => { ++ $all_done = false; ++ }, ++ $crate::IResult::Incomplete(i) => { ++ $needed = ::std::option::Option::Some(i); ++ break; ++ } ++ }; ++ } ++ }; ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! alt_sep ( ++ (__impl $i:expr, $separator:ident, $e:ident | $($rest:tt)*) => ( ++ alt_sep!(__impl $i, $separator, call!($e) | $($rest)*); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( ++ { ++ let res = sep!($i, $separator, $subrule!($($args)*)); ++ match res { ++ $crate::IResult::Done(_,_) => res, ++ $crate::IResult::Incomplete(_) => res, ++ _ => alt_sep!(__impl $i, $separator, $($rest)*) ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $separator:ident, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( ++ { ++ match sep!($i, $separator, $subrule!( $($args)* )) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(_) => { ++ alt_sep!(__impl $i, $separator, $($rest)*) ++ } ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $separator:ident, $e:ident => { $gen:expr } | $($rest:tt)*) => ( ++ alt_sep!(__impl $i, $separator, call!($e) => { $gen } | $($rest)*); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $e:ident => { $gen:expr }) => ( ++ alt_sep!(__impl $i, $separator, call!($e) => { $gen }); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( ++ { ++ match sep!($i, $separator, $subrule!( $($args)* )) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(_) => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Alt,$i)) ++ } ++ } ++ } ++ ); ++ ++ (__impl $i:expr, $separator:ident, $e:ident) => ( ++ alt_sep!(__impl $i, $separator, call!($e)); ++ ); ++ ++ (__impl $i:expr, $separator:ident, $subrule:ident!( $($args:tt)*)) => ( ++ { ++ match sep!($i, $separator, $subrule!( $($args)* )) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,o), ++ $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x), ++ $crate::IResult::Error(_) => { ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Alt,$i)) ++ } ++ } ++ } ++ ); ++ ++ (__impl $i:expr) => ( ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Alt,$i)) ++ ); ++ ++ (__impl $i:expr, $separator:ident) => ( ++ $crate::IResult::Error(error_position!($crate::ErrorKind::Alt,$i)) ++ ); ++ ++ ($i:expr, $separator:ident, $($rest:tt)*) => ( ++ { ++ alt_sep!(__impl $i, $separator, $($rest)*) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! alt_complete_sep ( ++ ($i:expr, $separator:ident, $e:ident | $($rest:tt)*) => ( ++ alt_complete_sep!($i, $separator, complete!(call!($e)) | $($rest)*); ++ ); ++ ++ ($i:expr, $separator:ident, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( ++ { ++ let res = complete!($i, sep!($separator, $subrule!($($args)*))); ++ match res { ++ $crate::IResult::Done(_,_) => res, ++ _ => alt_complete_sep!($i, $separator, $($rest)*), ++ } ++ } ++ ); ++ ++ ($i:expr, $separator:ident, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( ++ { ++ match complete!($i, sep!($separator, $subrule!($($args)*))) { ++ $crate::IResult::Done(i,o) => $crate::IResult::Done(i,$gen(o)), ++ _ => alt_complete_sep!($i, $separator, $($rest)*), ++ } ++ } ++ ); ++ ++ ($i:expr, $separator:ident, $e:ident => { $gen:expr } | $($rest:tt)*) => ( ++ alt_complete_sep!($i, $separator, complete!(call!($e)) => { $gen } | $($rest)*); ++ ); ++ ++ // Tail (non-recursive) rules ++ ++ ($i:expr, $separator:ident, $e:ident => { $gen:expr }) => ( ++ alt_complete_sep!($i, $separator, call!($e) => { $gen }); ++ ); ++ ++ ($i:expr, $separator:ident, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( ++ alt_sep!(__impl $i, $separator, $subrule!($($args)*) => { $gen }) ++ ); ++ ++ ($i:expr, $separator:ident, $e:ident) => ( ++ alt_complete_sep!($i, $separator, call!($e)); ++ ); ++ ++ ($i:expr, $separator:ident, $subrule:ident!( $($args:tt)*)) => ( ++ alt_sep!(__impl $i, $separator, $subrule!($($args)*)) ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! switch_sep ( ++ (__impl $i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => ( ++ { ++ match sep!($i, $separator, $submac!($($args)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(error_node_position!( ++ $crate::ErrorKind::Switch, $i, e ++ )), ++ $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i), ++ $crate::IResult::Done(i, o) => { ++ match o { ++ $($p => match sep!(i, $separator, $subrule!($($args2)*)) { ++ $crate::IResult::Error(e) => $crate::IResult::Error(error_node_position!( ++ $crate::ErrorKind::Switch, $i, e ++ )), ++ a => a, ++ }),*, ++ _ => $crate::IResult::Error(error_position!($crate::ErrorKind::Switch,$i)) ++ } ++ } ++ } ++ } ++ ); ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)*), $($rest:tt)*) => ( ++ { ++ switch_sep!(__impl $i, $separator, $submac!($($args)*), $($rest)*) ++ } ++ ); ++ ($i:expr, $separator:ident, $e:ident, $($rest:tt)*) => ( ++ { ++ switch_sep!(__impl $i, $separator, call!($e), $($rest)*) ++ } ++ ); ++); ++ ++#[doc(hidden)] ++#[macro_export] ++macro_rules! separated_list_sep ( ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( ++ separated_list!( ++ $i, ++ sep!($separator, $submac!($($args)*)), ++ sep!($separator, $submac2!($($args2)*)) ++ ) ++ ); ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => ( ++ separated_list_sep!($i, $separator, $submac!($($args)*), call!($g)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => ( ++ separated_list_sep!($i, $separator, call!($f), $submac!($($args)*)); ++ ); ++ ($i:expr, $separator:ident, $f:expr, $g:expr) => ( ++ separated_list_sep!($i, $separator, call!($f), call!($g)); ++ ); ++); ++ ++/// helper macros to build a separator parser ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// named!(pub space, eat_separator!(&b" \t"[..])); ++/// # fn main() {} ++/// ``` ++#[macro_export] ++macro_rules! eat_separator ( ++ ($i:expr, $arr:expr) => ( ++ { ++ use $crate::{AsChar,InputLength,InputIter,Slice}; ++ if ($i).input_len() == 0 { ++ $crate::IResult::Done(($i).slice(0..), ($i).slice(0..0)) ++ } else { ++ match ($i).iter_indices().position(|(_, item)| { ++ let i = item.as_char(); ++ for (_,c) in ($arr).iter_indices() { ++ if c.as_char() == i { return false; } ++ } ++ true ++ }) { ++ ::std::option::Option::Some(index) => { ++ $crate::IResult::Done(($i).slice(index..), ($i).slice(..index)) ++ }, ++ ::std::option::Option::None => { ++ $crate::IResult::Done(($i).slice(($i).input_len()..), ($i)) ++ } ++ } ++ } ++ } ++ ); ++); ++ ++/// sep is the parser rewriting macro for whitespace separated formats ++/// ++/// it takes as argument a space eating function and a parser tree, ++/// and will intersperse the space parser everywhere ++/// ++/// ```ignore ++/// #[macro_export] ++/// macro_rules! ws ( ++/// ($i:expr, $($args:tt)*) => ( ++/// { ++/// use $crate::sp; ++/// sep!($i, sp, $($args)*) ++/// } ++/// ) ++/// ); ++/// ``` ++#[macro_export] ++macro_rules! sep ( ++ ($i:expr, $separator:ident, tuple ! ($($rest:tt)*) ) => { ++ tuple_sep!($i, $separator, 0usize, (), $($rest)*) ++ }; ++ ($i:expr, $separator:ident, pair ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ pair_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, delimited ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ delimited_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, separated_pair ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ separated_pair_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, preceded ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ preceded_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, terminated ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ terminated_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, do_parse ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ do_parse_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, permutation ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ permutation_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, alt ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ alt_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, alt_complete ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ alt_complete_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, switch ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ switch_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, separated_list ! ($($rest:tt)*) ) => { ++ wrap_sep!($i, ++ $separator, ++ separated_list_sep!($separator, $($rest)*) ++ ) ++ }; ++ ($i:expr, $separator:ident, many0 ! ($($rest:tt)*) ) => { ++ many0!($i, wrap_sep!($separator, $($rest)*)) ++ }; ++ ($i:expr, $separator:ident, many1 ! ($($rest:tt)*) ) => { ++ many1!($i, wrap_sep!($separator, $($rest)*)) ++ }; ++//FIXME: missing separated_nonempty_list, ++// many_till, many_m_n, count, count_fixed, fold_many0, fold_many1, ++// fold_many_m_n ++ ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* )) => { ++ wrap_sep!($i, $separator, $submac!($($args)*)) ++ }; ++ ($i:expr, $separator:ident, $f:expr) => { ++ wrap_sep!($i, $separator, call!($f)) ++ }; ++); ++ ++use std::ops::{Range,RangeFrom,RangeTo}; ++use internal::IResult; ++#[allow(unused_imports)] ++pub fn sp<'a,T>(input:T) -> IResult where ++ T: ::traits::Slice>+::traits::Slice>+::traits::Slice>, ++ T: ::traits::InputIter+::traits::InputLength, ++ ::Item: ::traits::AsChar { ++ eat_separator!(input, &b" \t\r\n"[..]) ++} ++ ++/// `ws!(I -> IResult) => I -> IResult` ++/// ++/// transforms a parser to automatically consume ++/// whitespace between each token. By default, ++/// it takes the following characters: " \t\r\n". ++/// ++/// If you need a whitespace parser consuming a ++/// different set of characters, you can make ++/// your own by reusing the `sep!` combinator. ++/// ++/// To use `ws!`, pass your parser as argument: ++/// ++/// ``` ++/// # #[macro_use] extern crate nom; ++/// # use nom::IResult::Done; ++/// # fn main() { ++/// named!(tuple<&[u8], (&[u8], &[u8]) >, ++/// ws!(tuple!( take!(3), tag!("de") )) ++/// ); ++/// ++/// assert_eq!( ++/// tuple(&b" \t abc de fg"[..]), ++/// Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])) ++/// ); ++/// # } ++/// ``` ++/// ++#[macro_export] ++macro_rules! ws ( ++ ($i:expr, $($args:tt)*) => ( ++ { ++ use $crate::sp; ++ sep!($i, sp, $($args)*) ++ } ++ ) ++); ++ ++#[cfg(test)] ++#[allow(dead_code)] ++mod tests { ++ use internal::IResult::*; ++ use internal::{IResult,Needed}; ++ use super::sp; ++ use util::ErrorKind; ++ ++ #[test] ++ fn spaaaaace() { ++ assert_eq!(sp(&b" \t abc "[..]), Done(&b"abc "[..], &b" \t "[..])); ++ } ++ ++ #[test] ++ fn tag() { ++ named!(abc, ws!(tag!("abc"))); ++ ++ assert_eq!(abc(&b" \t abc def"[..]), Done(&b"def"[..], &b"abc"[..])); ++ } ++ ++ #[test] ++ fn pair() { ++ named!(pair_2<&[u8], (&[u8], &[u8]) >, ++ ws!(pair!( take!(3), tag!("de") )) ++ ); ++ ++ assert_eq!(pair_2(&b" \t abc de fg"[..]), Done(&b"fg"[..], (&b"abc"[..], &b"de"[..]))); ++ } ++ ++ #[test] ++ fn preceded() { ++ named!(prec<&[u8], &[u8] >, ++ ws!(preceded!( take!(3), tag!("de") )) ++ ); ++ ++ assert_eq!(prec(&b" \t abc de fg"[..]), Done(&b"fg"[..], &b"de"[..])); ++ } ++ ++ #[test] ++ fn terminated() { ++ named!(term<&[u8], &[u8] >, ++ ws!(terminated!( take!(3), tag!("de") )) ++ ); ++ ++ assert_eq!(term(&b" \t abc de fg"[..]), Done(&b"fg"[..], &b"abc"[..])); ++ } ++ ++ #[test] ++ fn tuple() { ++ //trace_macros!(true); ++ named!(tuple_2<&[u8], (&[u8], &[u8]) >, ++ ws!(tuple!( take!(3), tag!("de") )) ++ ); ++ //trace_macros!(false); ++ ++ assert_eq!(tuple_2(&b" \t abc de fg"[..]), Done(&b"fg"[..], (&b"abc"[..], &b"de"[..]))); ++ } ++ ++ #[test] ++ fn levels() { ++ //trace_macros!(true); ++ named!(level_2<&[u8], (&[u8], (&[u8], &[u8])) >, ++ ws!(pair!(take!(3), tuple!( tag!("de"), tag!("fg ") ))) ++ ); ++ //trace_macros!(false); ++ ++ assert_eq!(level_2(&b" \t abc de fg \t hi "[..]), Done(&b"hi "[..], (&b"abc"[..], (&b"de"[..], &b"fg "[..])))); ++ } ++ ++ #[test] ++ fn do_parse() { ++ fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Done(i,1) }; ++ fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Done(i,2) }; ++ ++ //trace_macros!(true); ++ named!(do_parser<&[u8], (u8, u8)>, ++ ws!(do_parse!( ++ tag!("abcd") >> ++ opt!(tag!("abcd")) >> ++ aa: ret_int1 >> ++ tag!("efgh") >> ++ bb: ret_int2 >> ++ tag!("efgh") >> ++ (aa, bb) ++ )) ++ ); ++ ++ //trace_macros!(false); ++ ++ assert_eq!(do_parser(&b"abcd abcd\tefghefghX"[..]), Done(&b"X"[..], (1, 2))); ++ assert_eq!(do_parser(&b"abcd\tefgh efgh X"[..]), Done(&b"X"[..], (1, 2))); ++ assert_eq!(do_parser(&b"abcd ab"[..]), Incomplete(Needed::Size(10))); ++ assert_eq!(do_parser(&b" abcd\tefgh\tef"[..]), Incomplete(Needed::Size(15))); ++ } ++ ++ #[test] ++ fn permutation() { ++ //trace_macros!(true); ++ named!(perm<(&[u8], &[u8], &[u8])>, ++ ws!(permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))) ++ ); ++ //trace_macros!(false); ++ ++ let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); ++ ++ let a = &b"abcd\tefg \thijk"[..]; ++ assert_eq!(perm(a), Done(&b"jk"[..], expected)); ++ let b = &b" efg \tabcdhi jk"[..]; ++ assert_eq!(perm(b), Done(&b"jk"[..], expected)); ++ let c = &b" hi efg\tabcdjk"[..]; ++ assert_eq!(perm(c), Done(&b"jk"[..], expected)); ++ ++ let d = &b"efg xyzabcdefghi"[..]; ++ assert_eq!(perm(d), Error(error_position!(ErrorKind::Permutation, &b"xyzabcdefghi"[..]))); ++ ++ let e = &b" efg \tabc"[..]; ++ assert_eq!(perm(e), Incomplete(Needed::Size(10))); ++ } ++ ++ #[test] ++ fn alt() { ++ fn work(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ Done(&b""[..], input) ++ } ++ ++ #[allow(unused_variables)] ++ fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8],&'static str> { ++ Error(error_code!(ErrorKind::Custom("abcd"))) ++ } ++ ++ fn work2(input: &[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ Done(input, &b""[..]) ++ } ++ ++ fn alt1(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | dont_work) ++ } ++ fn alt2(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | work) ++ } ++ fn alt3(i:&[u8]) -> IResult<&[u8],&[u8], &'static str> { ++ alt!(i, dont_work | dont_work | work2 | dont_work) ++ } ++ ++ let a = &b"\tabcd"[..]; ++ assert_eq!(alt1(a), Error(error_position!(ErrorKind::Alt, a))); ++ assert_eq!(alt2(a), Done(&b""[..], a)); ++ assert_eq!(alt3(a), Done(a, &b""[..])); ++ ++ named!(alt4, ws!(alt!(tag!("abcd") | tag!("efgh")))); ++ let b = &b" efgh "[..]; ++ assert_eq!(alt4(a), Done(&b""[..], &b"abcd"[..])); ++ assert_eq!(alt4(b), Done(&b""[..], &b"efgh"[..])); ++ ++ // test the alternative syntax ++ named!(alt5, ws!(alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true }))); ++ assert_eq!(alt5(a), Done(&b""[..], false)); ++ assert_eq!(alt5(b), Done(&b""[..], true)); ++ } ++ ++ #[test] ++ fn alt_complete() { ++ named!(ac<&[u8], &[u8]>, ++ ws!(alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl"))) ++ ); ++ ++ let a = &b""[..]; ++ assert_eq!(ac(a), Incomplete(Needed::Size(2))); ++ let a = &b" \tef "[..]; ++ assert_eq!(ac(a), Done(&b""[..], &b"ef"[..])); ++ let a = &b" cde"[..]; ++ assert_eq!(ac(a), Error(error_position!(ErrorKind::Alt, &a[1..]))); ++ } ++ ++ #[allow(unused_variables)] ++ #[test] ++ fn switch() { ++ named!(sw, ++ ws!(switch!(take!(4), ++ b"abcd" => take!(2) | ++ b"efgh" => take!(4) ++ )) ++ ); ++ ++ let a = &b" abcd ef gh"[..]; ++ assert_eq!(sw(a), Done(&b"gh"[..], &b"ef"[..])); ++ ++ let b = &b"\tefgh ijkl "[..]; ++ assert_eq!(sw(b), Done(&b""[..], &b"ijkl"[..])); ++ let c = &b"afghijkl"[..]; ++ assert_eq!(sw(c), Error(error_position!(ErrorKind::Switch, &b"afghijkl"[..]))); ++ } ++ ++ named!(str_parse(&str) -> &str, ws!(tag!("test"))); ++ #[allow(unused_variables)] ++ #[test] ++ fn str_test() { ++ assert_eq!(str_parse(" \n test\t a\nb"), Done("a\nb", "test")); ++ } ++ ++ // test whitespace parser generation for alt ++ named!(space, tag!(" ")); ++ named!(pipeline_statement<&[u8], ()>, ++ ws!( ++ do_parse!( ++ tag!("pipeline") >> ++ attributes: delimited!(char!('{'), ++ separated_list!(char!(','), alt!( ++ space | ++ space ++ )), ++ char!('}')) >> ++ ++ ( () ) ++ ) ++ ) ++ ); ++ ++} +diff --git third_party/rust/nom/tests/arithmetic.rs third_party/rust/nom/tests/arithmetic.rs +index eea990fb07cf..40ffc8cbfdcc 100644 +--- third_party/rust/nom/tests/arithmetic.rs ++++ third_party/rust/nom/tests/arithmetic.rs +@@ -1,22 +1,24 @@ + #[macro_use] + extern crate nom; + +-use nom::{IResult,digit, multispace}; ++use nom::{IResult,digit}; ++ ++// Parser definition + + use std::str; + use std::str::FromStr; + +-named!(parens, delimited!( +- delimited!(opt!(multispace), tag!("("), opt!(multispace)), +- expr, +- delimited!(opt!(multispace), tag!(")"), opt!(multispace)) +- ) +-); ++// We parse any expr surrounded by parens, ignoring all whitespaces around those ++named!(parens, ws!(delimited!( tag!("("), expr, tag!(")") )) ); + ++// We transform an integer string into a i64, ignoring surrounding whitespaces ++// We look for a digit suite, and try to convert it. ++// If either str::from_utf8 or FromStr::from_str fail, ++// we fallback to the parens parser defined above + named!(factor, alt!( + map_res!( + map_res!( +- delimited!(opt!(multispace), digit, opt!(multispace)), ++ ws!(digit), + str::from_utf8 + ), + FromStr::from_str +@@ -25,27 +27,32 @@ named!(factor, alt!( + ) + ); + +-named!(term , chain!( +- mut acc: factor ~ +- many0!( +- alt!( +- tap!(mul: preceded!(tag!("*"), factor) => acc = acc * mul) | +- tap!(div: preceded!(tag!("/"), factor) => acc = acc / div) +- ) +- ), +- || { return acc } ++// We read an initial factor and for each time we find ++// a * or / operator followed by another factor, we do ++// the math by folding everything ++named!(term , do_parse!( ++ init: factor >> ++ res: fold_many0!( ++ pair!(alt!(tag!("*") | tag!("/")), factor), ++ init, ++ |acc, (op, val): (&[u8], i64)| { ++ if (op[0] as char) == '*' { acc * val } else { acc / val } ++ } ++ ) >> ++ (res) + ) + ); + +-named!(expr , chain!( +- mut acc: term ~ +- many0!( +- alt!( +- tap!(add: preceded!(tag!("+"), term) => acc = acc + add) | +- tap!(sub: preceded!(tag!("-"), term) => acc = acc - sub) +- ) +- ), +- || { return acc } ++named!(expr , do_parse!( ++ init: term >> ++ res: fold_many0!( ++ pair!(alt!(tag!("+") | tag!("-")), term), ++ init, ++ |acc, (op, val): (&[u8], i64)| { ++ if (op[0] as char) == '+' { acc + val } else { acc - val } ++ } ++ ) >> ++ (res) + ) + ); + +diff --git third_party/rust/nom/tests/arithmetic_ast.rs third_party/rust/nom/tests/arithmetic_ast.rs +index 9a8956936ff8..d48b9028b9f7 100644 +--- third_party/rust/nom/tests/arithmetic_ast.rs ++++ third_party/rust/nom/tests/arithmetic_ast.rs +@@ -86,27 +86,27 @@ fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr { + }) + } + +-named!(term< Expr >, chain!( +- initial: factor ~ ++named!(term< Expr >, do_parse!( ++ initial: factor >> + remainder: many0!( + alt!( +- chain!(tag!("*") ~ mul: factor, || { (Oper::Mul, mul) }) | +- chain!(tag!("/") ~ div: factor, || { (Oper::Div, div) }) ++ do_parse!(tag!("*") >> mul: factor >> (Oper::Mul, mul)) | ++ do_parse!(tag!("/") >> div: factor >> (Oper::Div, div)) + ) +- ), +- || fold_exprs(initial, remainder)) +-); ++ ) >> ++ (fold_exprs(initial, remainder)) ++)); + +-named!(expr< Expr >, chain!( +- initial: term ~ ++named!(expr< Expr >, do_parse!( ++ initial: term >> + remainder: many0!( + alt!( +- chain!(tag!("+") ~ add: term, || { (Oper::Add, add) }) | +- chain!(tag!("-") ~ sub: term, || { (Oper::Sub, sub) }) ++ do_parse!(tag!("+") >> add: term >> (Oper::Add, add)) | ++ do_parse!(tag!("-") >> sub: term >> (Oper::Sub, sub)) + ) +- ), +- || fold_exprs(initial, remainder)) +-); ++ ) >> ++ (fold_exprs(initial, remainder)) ++)); + + #[test] + fn factor_test() { +diff --git third_party/rust/nom/tests/blockbuf-arithmetic.rs third_party/rust/nom/tests/blockbuf-arithmetic.rs +new file mode 100644 +index 000000000000..fe655185df54 +--- /dev/null ++++ third_party/rust/nom/tests/blockbuf-arithmetic.rs +@@ -0,0 +1,321 @@ ++/* ++#[macro_use] ++extern crate nom; ++extern crate bytes; ++ ++use nom::{Compare,CompareResult,InputLength,InputIter,Slice,HexDisplay}; ++ ++use std::str; ++use std::str::FromStr; ++use bytes::{Buf,MutBuf}; ++use bytes::buf::{BlockBuf,BlockBufCursor}; ++use std::ops::{Range,RangeTo,RangeFrom,RangeFull}; ++use std::iter::{Enumerate,Iterator}; ++use std::fmt; ++use std::cmp::{min,PartialEq}; ++ ++#[derive(Clone,Copy)] ++#[repr(C)] ++pub struct BlockSlice<'a> { ++ buf: &'a BlockBuf, ++ start: usize, ++ end: usize, ++} ++ ++impl<'a> BlockSlice<'a> { ++ fn cursor(&self) -> WrapCursor<'a> { ++ let mut cur = self.buf.buf(); ++ cur.advance(self.start); ++ WrapCursor { ++ cursor: cur, ++ length: self.end - self.start, ++ } ++ } ++} ++ ++impl<'a> fmt::Debug for BlockSlice<'a> { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ write!(f, "BlockSlice {{ start: {}, end: {}, data:\n{}\n}}", self.start, self.end, self.buf.bytes().unwrap_or(&b""[..]).to_hex(16)) ++ } ++} ++ ++impl<'a> PartialEq for BlockSlice<'a> { ++ fn eq(&self, other: &BlockSlice<'a>) -> bool { ++ let bufs = (self.buf as *const BlockBuf) == (other.buf as *const BlockBuf); ++ self.start == other.start && self.end == other.end && bufs ++ } ++} ++ ++impl<'a> Slice> for BlockSlice<'a> { ++ fn slice(&self, range:Range) -> Self { ++ BlockSlice { ++ buf: self.buf, ++ start: self.start + range.start, ++ //FIXME: check for valid end here ++ end: self.start + range.end, ++ } ++ } ++} ++ ++impl<'a> Slice> for BlockSlice<'a> { ++ fn slice(&self, range:RangeTo) -> Self { ++ self.slice(0..range.end) ++ } ++} ++ ++impl<'a> Slice> for BlockSlice<'a> { ++ fn slice(&self, range:RangeFrom) -> Self { ++ self.slice(range.start..self.end - self.start) ++ } ++} ++ ++impl<'a> Slice for BlockSlice<'a> { ++ fn slice(&self, _:RangeFull) -> Self { ++ BlockSlice { ++ buf: self.buf, ++ start: self.start, ++ end: self.end, ++ } ++ } ++} ++ ++ ++impl<'a> InputIter for BlockSlice<'a> { ++ type Item = u8; ++ type RawItem = u8; ++ type Iter = Enumerate>; ++ type IterElem = WrapCursor<'a>; ++ ++ fn iter_indices(&self) -> Self::Iter { ++ self.cursor().enumerate() ++ } ++ fn iter_elements(&self) -> Self::IterElem { ++ self.cursor() ++ } ++ fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool { ++ self.cursor().position(|b| predicate(b)) ++ } ++ fn slice_index(&self, count:usize) -> Option { ++ if self.end - self.start >= count { ++ Some(count) ++ } else { ++ None ++ } ++ } ++} ++ ++ ++impl<'a> InputLength for BlockSlice<'a> { ++ fn input_len(&self) -> usize { ++ self.end - self.start ++ } ++} ++ ++impl<'a,'b> Compare<&'b[u8]> for BlockSlice<'a> { ++ fn compare(&self, t: &'b[u8]) -> CompareResult { ++ let len = self.end - self.start; ++ let blen = t.len(); ++ let m = if len < blen { len } else { blen }; ++ let reduced = self.slice(..m); ++ let b = &t[..m]; ++ ++ for (a,b) in reduced.cursor().zip(b.iter()) { ++ if a != *b { ++ return CompareResult::Error; ++ } ++ } ++ if m < blen { ++ CompareResult::Incomplete ++ } else { ++ CompareResult::Ok ++ } ++ } ++ ++ ++ #[inline(always)] ++ fn compare_no_case(&self, t: &'b[u8]) -> CompareResult { ++ let len = self.end - self.start; ++ let blen = t.len(); ++ let m = if len < blen { len } else { blen }; ++ let reduced = self.slice(..m); ++ let other = &t[..m]; ++ ++ if !reduced.cursor().zip(other).all(|(a, b)| { ++ match (a,*b) { ++ (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == *b, ++ (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122 ) |(97...122, 65...90) => { ++ a & 0b01000000 == *b & 0b01000000 ++ } ++ _ => false ++ } ++ }) { ++ CompareResult::Error ++ } else if m < blen { ++ CompareResult::Incomplete ++ } else { ++ CompareResult::Ok ++ } ++ } ++} ++ ++impl<'a,'b> Compare<&'b str> for BlockSlice<'a> { ++ fn compare(&self, t: &'b str) -> CompareResult { ++ self.compare(str::as_bytes(t)) ++ } ++ fn compare_no_case(&self, t: &'b str) -> CompareResult { ++ self.compare_no_case(str::as_bytes(t)) ++ } ++} ++ ++//Wrapper to implement Iterator on BlockBufCursor ++pub struct WrapCursor<'a> { ++ pub cursor: BlockBufCursor<'a>, ++ pub length: usize, ++} ++ ++impl<'a> Iterator for WrapCursor<'a> { ++ type Item = u8; ++ fn next(&mut self) -> Option { ++ //println!("NEXT: length={}, remaining={}", self.length, self.cursor.remaining()); ++ if min(self.length, self.cursor.remaining()) > 0 { ++ self.length -=1; ++ Some(self.cursor.read_u8()) ++ } else { ++ None ++ } ++ } ++} ++ ++//Reimplement eat_separator instead of fixing iterators ++#[macro_export] ++macro_rules! block_eat_separator ( ++ ($i:expr, $arr:expr) => ( ++ { ++ use nom::{InputLength,InputIter,Slice}; ++ if ($i).input_len() == 0 { ++ nom::IResult::Done($i, ($i).slice(0..0)) ++ } else { ++ match ($i).iter_indices().position(|(_, item)| { ++ for (_,c) in ($arr).iter_indices() { ++ if *c == item { return false; } ++ } ++ true ++ }) { ++ Some(index) => { ++ nom::IResult::Done(($i).slice(index..), ($i).slice(..index)) ++ }, ++ None => { ++ nom::IResult::Done(($i).slice(($i).input_len()..), $i) ++ } ++ } ++ } ++ } ++ ) ++); ++ ++#[macro_export] ++macro_rules! block_named ( ++ ($name:ident, $submac:ident!( $($args:tt)* )) => ( ++ fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult, BlockSlice<'a>, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++ ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( ++ fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult, $o, u32> { ++ $submac!(i, $($args)*) ++ } ++ ); ++); ++ ++block_named!(sp, block_eat_separator!(&b" \t\r\n"[..])); ++ ++macro_rules! block_ws ( ++ ($i:expr, $($args:tt)*) => ( ++ { ++ sep!($i, sp, $($args)*) ++ } ++ ) ++); ++ ++block_named!(digit, is_a!("0123456789")); ++ ++block_named!(parens, block_ws!(delimited!( tag!("("), expr, tag!(")") )) ); ++ ++ ++block_named!(factor, alt!( ++ map_res!( ++ block_ws!(digit), ++ to_i64 ++ ) ++ | parens ++ ) ++); ++ ++block_named!(term , do_parse!( ++ init: factor >> ++ res: fold_many0!( ++ pair!(alt!(tag!("*") | tag!("/")), factor), ++ init, ++ |acc, (op, val): (BlockSlice, i64)| { ++ if (op.cursor().next().unwrap() as char) == '*' { acc * val } else { acc / val } ++ } ++ ) >> ++ (res) ++ ) ++); ++ ++block_named!(expr , do_parse!( ++ init: term >> ++ res: fold_many0!( ++ pair!(alt!(tag!("+") | tag!("-")), term), ++ init, ++ |acc, (op, val): (BlockSlice, i64)| { ++ if (op.cursor().next().unwrap() as char) == '+' { acc + val } else { acc - val } ++ } ++ ) >> ++ (res) ++ ) ++); ++ ++ ++fn blockbuf_from(input: &[u8]) -> BlockBuf { ++ let mut b = BlockBuf::new(2, 100); ++ b.copy_from(input); ++ b ++} ++ ++ ++fn sl<'a>(input: &'a BlockBuf) -> BlockSlice<'a> { ++ BlockSlice { ++ buf: input, ++ start: 0, ++ end: input.len(), ++ } ++} ++ ++fn to_i64<'a>(input: BlockSlice<'a>) -> Result { ++ let v: Vec = input.cursor().collect(); ++ ++ match str::from_utf8(&v) { ++ Err(_) => Err(()), ++ Ok(s) => match FromStr::from_str(s) { ++ Err(_) => Err(()), ++ Ok(i) => Ok(i) ++ } ++ } ++} ++ ++#[test] ++fn factor_test() { ++ let a = blockbuf_from(&b"3"[..]); ++ println!("calculated: {:?}", factor(sl(&a))); ++} ++ ++#[test] ++fn parens_test() { ++ let input1 = blockbuf_from(&b" 2* ( 3 + 4 ) "[..]); ++ println!("calculated 1: {:?}", expr(sl(&input1))); ++ let input2 = blockbuf_from(&b" 2*2 / ( 5 - 1) + 3"[..]); ++ println!("calculated 2: {:?}", expr(sl(&input2))); ++} ++*/ +diff --git third_party/rust/nom/tests/cross_function_backtracking.rs third_party/rust/nom/tests/cross_function_backtracking.rs +index 592670c43999..3163037377a0 100644 +--- third_party/rust/nom/tests/cross_function_backtracking.rs ++++ third_party/rust/nom/tests/cross_function_backtracking.rs +@@ -5,9 +5,10 @@ + /// The solution here wraps `IResult` in a `Result`: a `Ok` indicates usual + /// backtracking, `Err` indicates that we must "cut". + +-#[macro_use] +-extern crate nom; ++#[allow(unused_imports)] ++#[macro_use] extern crate nom; + ++#[cfg(feature = "verbose_errors")] + macro_rules! n ( + ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( + fn $name( i: $i ) -> std::result::Result, nom::Err<$i, u32>> { +@@ -61,6 +62,7 @@ macro_rules! n ( + ); + ); + ++#[cfg(feature = "verbose_errors")] + macro_rules! cut ( + ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => ( + { +@@ -82,6 +84,7 @@ macro_rules! cut ( + ); + ); + ++#[cfg(feature = "verbose_errors")] + macro_rules! c ( + ($i:expr, $f:expr) => ( + { +@@ -97,14 +100,16 @@ macro_rules! c ( + ); + ); + ++#[cfg(feature = "verbose_errors")] + n!(pub foo< bool >, +- chain!( +- tag!("a") ~ +- cut!(nom::ErrorKind::Custom(42),dbg_dmp!(tag!("b"))) , +- || { true } ++ do_parse!( ++ tag!("a") >> ++ cut!(nom::ErrorKind::Custom(42),dbg_dmp!(tag!("b"))) >> ++ (true) + ) + ); + ++#[cfg(feature = "verbose_errors")] + n!(pub foos< Vec >, + delimited!( + tag!("("), +@@ -113,6 +118,7 @@ n!(pub foos< Vec >, + ) + ); + ++#[cfg(feature = "verbose_errors")] + #[test] + fn test_ok() { + let r = foos(b"(abab)"); +@@ -123,6 +129,7 @@ fn test_ok() { + } + } + ++#[cfg(feature = "verbose_errors")] + #[test] + fn test_err() { + let input = b"(ac)"; +diff --git third_party/rust/nom/tests/float.rs third_party/rust/nom/tests/float.rs +new file mode 100644 +index 000000000000..5710e260365b +--- /dev/null ++++ third_party/rust/nom/tests/float.rs +@@ -0,0 +1,46 @@ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,digit}; ++ ++use std::str; ++use std::str::FromStr; ++ ++named!(unsigned_float , map_res!( ++ map_res!( ++ recognize!( ++ alt!( ++ delimited!(digit, tag!("."), opt!(complete!(digit))) | ++ delimited!(opt!(digit), tag!("."), digit) ++ ) ++ ), ++ str::from_utf8 ++ ), ++ FromStr::from_str ++)); ++ ++named!(float , map!( ++ pair!( ++ opt!(alt!(tag!("+") | tag!("-"))), ++ unsigned_float ++ ), ++ |(sign, value): (Option<&[u8]>, f32)| { ++ sign.and_then(|s| if s[0] == ('-' as u8) { Some(-1f32) } else { None }).unwrap_or(1f32) * value ++ } ++)); ++ ++#[test] ++fn unsigned_float_test() { ++ assert_eq!(unsigned_float(&b"123.456"[..]), IResult::Done(&b""[..], 123.456)); ++ assert_eq!(unsigned_float(&b"0.123"[..]), IResult::Done(&b""[..], 0.123)); ++ assert_eq!(unsigned_float(&b"123.0"[..]), IResult::Done(&b""[..], 123.0)); ++ assert_eq!(unsigned_float(&b"123."[..]), IResult::Done(&b""[..], 123.0)); ++ assert_eq!(unsigned_float(&b".123"[..]), IResult::Done(&b""[..], 0.123)); ++} ++ ++#[test] ++fn float_test() { ++ assert_eq!(float(&b"123.456"[..]), IResult::Done(&b""[..], 123.456)); ++ assert_eq!(float(&b"+123.456"[..]), IResult::Done(&b""[..], 123.456)); ++ assert_eq!(float(&b"-123.456"[..]), IResult::Done(&b""[..], -123.456)); ++} +diff --git third_party/rust/nom/tests/ini.rs third_party/rust/nom/tests/ini.rs +index a3a33431bf02..c72177071697 100644 +--- third_party/rust/nom/tests/ini.rs ++++ third_party/rust/nom/tests/ini.rs +@@ -1,83 +1,68 @@ +- + #[macro_use] + extern crate nom; + +-use nom::{IResult,not_line_ending, space, alphanumeric, multispace}; ++use nom::{IResult, space, alphanumeric, multispace}; + + use std::str; + use std::collections::HashMap; + + named!(category<&str>, map_res!( +- terminated!( +- delimited!(tag!("["), take_until!("]"), tag!("]")), +- opt!(multispace) ++ delimited!( ++ char!('['), ++ take_while!(call!(|c| c != ']' as u8)), ++ char!(']') + ), + str::from_utf8 + )); + + named!(key_value <&[u8],(&str,&str)>, +- chain!( +- key: map_res!(alphanumeric, std::str::from_utf8) ~ +- space? ~ +- tag!("=") ~ +- space? ~ +- val: map_res!( +- take_until_either!("\n;"), ++ do_parse!( ++ key: map_res!(alphanumeric, str::from_utf8) ++ >> opt!(space) ++ >> char!('=') ++ >> opt!(space) ++ >> val: map_res!( ++ take_while!(call!(|c| c != '\n' as u8 && c != ';' as u8)), + str::from_utf8 +- ) ~ +- space? ~ +- chain!( +- tag!(";") ~ +- not_line_ending , +- ||{} +- ) ? ~ +- multispace? , +- ||{(key, val)} ++ ) ++ >> opt!(pair!(char!(';'), take_while!(call!(|c| c != '\n' as u8)))) ++ >> (key, val) + ) + ); + + +-named!(keys_and_values_aggregator<&[u8], Vec<(&str,&str)> >, many0!(key_value)); ++named!(keys_and_values<&[u8], HashMap<&str, &str> >, ++ map!( ++ many0!(terminated!(key_value, opt!(multispace))), ++ |vec: Vec<_>| vec.into_iter().collect() ++ ) ++); + +-fn keys_and_values(input:&[u8]) -> IResult<&[u8], HashMap<&str, &str> > { +- let mut h: HashMap<&str, &str> = HashMap::new(); +- +- match keys_and_values_aggregator(input) { +- IResult::Done(i,tuple_vec) => { +- for &(k,v) in &tuple_vec { +- h.insert(k, v); +- } +- IResult::Done(i, h) +- }, +- IResult::Incomplete(a) => IResult::Incomplete(a), +- IResult::Error(a) => IResult::Error(a) +- } +-} + + named!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>, +- chain!( +- category: category ~ +- keys: keys_and_values , +- move ||{(category, keys)} ++ do_parse!( ++ category: category >> ++ opt!(multispace) >> ++ keys: keys_and_values >> ++ (category, keys) + ) + ); + +-named!(categories_aggregator<&[u8], Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys)); +- +-fn categories(input: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str> > > { +- let mut h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); +- +- match categories_aggregator(input) { +- IResult::Done(i,tuple_vec) => { +- for &(k,ref v) in &tuple_vec { +- h.insert(k, v.clone()); +- } +- IResult::Done(i, h) +- }, +- IResult::Incomplete(a) => IResult::Incomplete(a), +- IResult::Error(a) => IResult::Error(a) +- } +-} ++named!(categories<&[u8], HashMap<&str, HashMap<&str,&str> > >, ++ map!( ++ many0!( ++ separated_pair!( ++ category, ++ opt!(multispace), ++ map!( ++ many0!(terminated!(key_value, opt!(multispace))), ++ |vec: Vec<_>| vec.into_iter().collect() ++ ) ++ ) ++ ), ++ |vec: Vec<_>| vec.into_iter().collect() ++ ) ++); + + #[test] + fn parse_category_test() { +@@ -86,7 +71,7 @@ fn parse_category_test() { + parameter=value + key = value2"[..]; + +- let ini_without_category = &b"parameter=value ++ let ini_without_category = &b"\n\nparameter=value + key = value2"[..]; + + let res = category(ini_file); +@@ -104,7 +89,7 @@ fn parse_key_value_test() { + let ini_file = &b"parameter=value + key = value2"[..]; + +- let ini_without_key_value = &b"key = value2"[..]; ++ let ini_without_key_value = &b"\nkey = value2"[..]; + + let res = key_value(ini_file); + println!("{:?}", res); +@@ -122,7 +107,7 @@ fn parse_key_value_with_space_test() { + let ini_file = &b"parameter = value + key = value2"[..]; + +- let ini_without_key_value = &b"key = value2"[..]; ++ let ini_without_key_value = &b"\nkey = value2"[..]; + + let res = key_value(ini_file); + println!("{:?}", res); +@@ -139,7 +124,7 @@ fn parse_key_value_with_comment_test() { + let ini_file = &b"parameter=value;abc + key = value2"[..]; + +- let ini_without_key_value = &b"key = value2"[..]; ++ let ini_without_key_value = &b"\nkey = value2"[..]; + + let res = key_value(ini_file); + println!("{:?}", res); +diff --git third_party/rust/nom/tests/ini_str.rs third_party/rust/nom/tests/ini_str.rs +index c69756dc2aca..330e4901f58a 100644 +--- third_party/rust/nom/tests/ini_str.rs ++++ third_party/rust/nom/tests/ini_str.rs +@@ -1,4 +1,3 @@ +- + #[macro_use] + extern crate nom; + +@@ -36,40 +35,35 @@ fn right_bracket(c:char) -> bool { + } + + named!(category <&str, &str>, +- chain!( +- tag_s!("[") ~ +- name: take_till_s!(right_bracket) ~ +- tag_s!("]") ~ +- space_or_line_ending? , +- ||{ name } ++ do_parse!( ++ tag_s!("[") >> ++ name: take_till_s!(right_bracket) >> ++ tag_s!("]") >> ++ opt!(space_or_line_ending) >> ++ (name) + ) + ); + + named!(key_value <&str,(&str,&str)>, +- chain!( +- key: alphanumeric ~ +- space? ~ +- tag_s!("=") ~ +- space? ~ +- val: take_till_s!(is_line_ending_or_comment) ~ +- space? ~ +- pair!(tag_s!(";"), not_line_ending)? ~ +- space_or_line_ending? , +- ||{(key, val)} ++ do_parse!( ++ key: alphanumeric >> ++ opt!(space) >> ++ tag_s!("=") >> ++ opt!(space) >> ++ val: take_till_s!(is_line_ending_or_comment) >> ++ opt!(space) >> ++ opt!(pair!(tag_s!(";"), not_line_ending)) >> ++ opt!(space_or_line_ending) >> ++ (key, val) + ) + ); + + named!(keys_and_values_aggregator<&str, Vec<(&str,&str)> >, many0!(key_value)); + + fn keys_and_values(input:&str) -> IResult<&str, HashMap<&str, &str> > { +- let mut h: HashMap<&str, &str> = HashMap::new(); +- + match keys_and_values_aggregator(input) { + IResult::Done(i,tuple_vec) => { +- for &(k,v) in &tuple_vec { +- h.insert(k, v); +- } +- IResult::Done(i, h) ++ IResult::Done(i, tuple_vec.into_iter().collect()) + }, + IResult::Incomplete(a) => IResult::Incomplete(a), + IResult::Error(a) => IResult::Error(a) +@@ -84,14 +78,9 @@ named!(category_and_keys<&str,(&str,HashMap<&str,&str>)>, + named!(categories_aggregator<&str, Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys)); + + fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str> > > { +- let mut h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); +- + match categories_aggregator(input) { + IResult::Done(i,tuple_vec) => { +- for &(k,ref v) in &tuple_vec { +- h.insert(k, v.clone()); +- } +- IResult::Done(i, h) ++ IResult::Done(i, tuple_vec.into_iter().collect()) + }, + IResult::Incomplete(a) => IResult::Incomplete(a), + IResult::Error(a) => IResult::Error(a) +diff --git third_party/rust/nom/tests/issues.rs third_party/rust/nom/tests/issues.rs +index 6466d7f2e069..7a726dc0591b 100644 +--- third_party/rust/nom/tests/issues.rs ++++ third_party/rust/nom/tests/issues.rs +@@ -1,9 +1,10 @@ + //#![feature(trace_macros)] ++#![allow(dead_code)] ++ + #[macro_use] + extern crate nom; + +-use nom::{IResult,Needed,HexDisplay,space,digit,be_u16}; +-use std::str; ++use nom::{IResult,Needed,space,be_u16,le_u64}; + + #[allow(dead_code)] + struct Range { +@@ -24,23 +25,21 @@ pub fn take_char(input: &[u8]) -> IResult<&[u8], char> { + #[allow(dead_code)] + named!(range<&[u8], Range>, + alt!( +- chain!( +- start: take_char ~ +- tag!("-") ~ +- end: take_char, +- || { +- Range { +- start: start, +- end: end, +- } +- } ++ do_parse!( ++ start: take_char >> ++ tag!("-") >> ++ end: take_char >> ++ (Range { ++ start: start, ++ end: end, ++ }) + ) | + map!( + take_char, + |c| { + Range { + start: c, +- end: c, ++ end: c, + } + } + ) +@@ -66,35 +65,43 @@ fn issue_58() { + + //trace_macros!(false); + +-named!(parse_ints< Vec >, many0!(spaces_or_int)); +- +-fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{ +- println!("{}", input.to_hex(8)); +- chain!(input, +- opt!(space) ~ +- x: digit, +- || { +- println!("x: {:?}", x); +- let result = str::from_utf8(x).unwrap(); +- println!("Result: {}", result); +- println!("int is empty?: {}", x.is_empty()); +- match result.parse(){ +- Ok(i) => i, +- Err(_) => panic!("UH OH! NOT A DIGIT!") +- } +- } +- ) +-} ++#[cfg(feature = "std")] ++mod parse_int { ++ use nom::HexDisplay; ++ use nom::{IResult,space,digit}; ++ use std::str; ++ ++ named!(parse_ints< Vec >, many0!(spaces_or_int)); ++ ++ fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{ ++ println!("{}", input.to_hex(8)); ++ do_parse!(input, ++ opt!(complete!(space)) >> ++ res: map!(complete!(digit), ++ |x| { ++ println!("x: {:?}", x); ++ let result = str::from_utf8(x).unwrap(); ++ println!("Result: {}", result); ++ println!("int is empty?: {}", x.is_empty()); ++ match result.parse(){ ++ Ok(i) => i, ++ Err(_) => panic!("UH OH! NOT A DIGIT!") ++ } ++ }) >> ++ (res) ++ ) ++ } + +-#[test] +-fn issue_142(){ +- let subject = parse_ints(&b"12 34 5689"[..]); +- let expected = IResult::Done(&b""[..], vec![12, 34, 5689]); +- assert_eq!(subject, expected); +- +- let subject = parse_ints(&b"12 34 5689 "[..]); +- let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]); +- assert_eq!(subject, expected) ++ #[test] ++ fn issue_142(){ ++ let subject = parse_ints(&b"12 34 5689"[..]); ++ let expected = IResult::Done(&b""[..], vec![12, 34, 5689]); ++ assert_eq!(subject, expected); ++ ++ let subject = parse_ints(&b"12 34 5689 "[..]); ++ let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]); ++ assert_eq!(subject, expected) ++ } + } + + #[test] +@@ -129,3 +136,22 @@ fn take_till_issue() { + assert_eq!(nothing(b""), IResult::Done(&b""[..], &b""[..])); + assert_eq!(nothing(b"abc"), IResult::Done(&b"abc"[..], &b""[..])); + } ++ ++named!(issue_498< Vec<&[u8]> >, separated_nonempty_list!( opt!(space), tag!("abcd") )); ++ ++named!(issue_308(&str) -> bool, ++ do_parse! ( ++ tag_s! ("foo") >> ++ b: alt_complete! ( ++ map! (tag_s! ("1"), |_: &str|->bool {true}) | ++ value! (false) ++ ) >> ++ (b) )); ++ ++ ++fn issue_302(input: &[u8]) -> IResult<&[u8], Option> > { ++ do_parse!(input, ++ entries: cond!(true, count!(le_u64, 3)) >> ++ ( entries ) ++ ) ++} +diff --git third_party/rust/nom/tests/json.rs third_party/rust/nom/tests/json.rs +new file mode 100644 +index 000000000000..b0369166c3b1 +--- /dev/null ++++ third_party/rust/nom/tests/json.rs +@@ -0,0 +1,130 @@ ++//#![feature(trace_macros)] ++ ++#[macro_use] ++extern crate nom; ++ ++use nom::{digit, alphanumeric}; ++ ++use std::str::{self,FromStr}; ++use std::collections::HashMap; ++ ++#[derive(Debug,PartialEq)] ++pub enum JsonValue { ++ Str(String), ++ Num(f32), ++ Array(Vec), ++ Object(HashMap) ++} ++ ++// FIXME: since we already parsed a serie of digits and dots, ++// we know it is correct UTF-8. no need to use from_utf8 to ++// verify it is correct ++// FIXME: use alt_complete (implement ws for alt_complete) ++named!(unsigned_float , map_res!( ++ map_res!( ++ recognize!( ++ alt_complete!( ++ delimited!(digit, tag!("."), opt!(complete!(digit))) | ++ delimited!(opt!(digit), tag!("."), digit) | ++ digit ++ ) ++ ), ++ str::from_utf8 ++ ), ++ FromStr::from_str ++)); ++named!(float, map!( ++ pair!( ++ opt!(alt!(tag!("+") | tag!("-"))), ++ unsigned_float ++ ), ++ |(sign, value): (Option<&[u8]>, f32)| { ++ sign.and_then(|s| if s[0] == ('-' as u8) { Some(-1f32) } else { None }).unwrap_or(1f32) * value ++ } ++)); ++ ++//FIXME: verify how json strings are formatted ++named!(string<&str>, ++ delimited!( ++ tag!("\""), ++ map_res!(escaped!(call!(alphanumeric), '\\', is_a!("\"n\\")), str::from_utf8), ++ tag!("\"") ++ ) ++); ++ ++named!(array < Vec >, ++ ws!( ++ delimited!( ++ tag!("["), ++ separated_list!(tag!(","), value), ++ tag!("]") ++ ) ++ ) ++); ++ ++named!(key_value<(&str,JsonValue)>, ++ ws!( ++ separated_pair!( ++ string, ++ tag!(":"), ++ value ++ ) ++ ) ++); ++ ++named!(hash< HashMap >, ++ ws!( ++ map!( ++ delimited!( ++ tag!("{"), ++ separated_list!(tag!(","), key_value), ++ tag!("}") ++ ), ++ |tuple_vec| { ++ let mut h: HashMap = HashMap::new(); ++ for (k, v) in tuple_vec { ++ h.insert(String::from(k), v); ++ } ++ h ++ } ++ ) ++ ) ++); ++ ++named!(value, ++ ws!( ++ alt!( ++ hash => { |h| JsonValue::Object(h) } | ++ array => { |v| JsonValue::Array(v) } | ++ string => { |s| JsonValue::Str(String::from(s)) } | ++ float => { |num| JsonValue::Num(num) } ++ ) ++ ) ++); ++ ++ ++ ++#[test] ++fn hash_test() { ++ let test = &b" { \"a\"\t: 42, ++ \"b\": \"x\" ++ }"; ++ ++//FIXME: top level value must be an object? ++ println!("{:?}", value(&test[..])); ++ //assert!(false); ++} ++ ++#[test] ++fn parse_example_test() { ++ let test = &b" { \"a\"\t: 42, ++ \"b\": [ \"x\", \"y\", 12 ] , ++ \"c\": { \"hello\" : \"world\" ++ } ++ }"; ++ ++//FIXME: top level value must be an object? ++ println!("{:?}", value(&test[..])); ++ //assert!(false); ++} ++ +diff --git third_party/rust/nom/tests/mp4.rs third_party/rust/nom/tests/mp4.rs +index 8c128f57a928..e6d5c9fce7c0 100644 +--- third_party/rust/nom/tests/mp4.rs ++++ third_party/rust/nom/tests/mp4.rs +@@ -4,10 +4,9 @@ + #[macro_use] + extern crate nom; + +-use nom::{HexDisplay,Needed,IResult,be_u16,be_u32,be_u64,be_f32,ErrorKind}; ++use nom::{HexDisplay,Offset,Needed,IResult,be_u16,be_u32,be_u64,be_f32,ErrorKind}; + use nom::{Consumer,ConsumerState,Move,Input,Producer,FileProducer,FileProducerState}; + use nom::IResult::*; +-use nom::Err::*; + + use std::str; + use std::io::SeekFrom; +@@ -94,30 +93,30 @@ pub struct Mvhd64 { + + #[allow(non_snake_case)] + named!(mvhd32 <&[u8], MvhdBox>, +- chain!( +- version_flags: be_u32 ~ +- created_date: be_u32 ~ +- modified_date: be_u32 ~ +- scale: be_u32 ~ +- duration: be_u32 ~ +- speed: be_f32 ~ +- volume: be_u16 ~ // actually a 2 bytes decimal +- take!(10) ~ +- scale_a: be_f32 ~ +- rotate_b: be_f32 ~ +- angle_u: be_f32 ~ +- rotate_c: be_f32 ~ +- scale_d: be_f32 ~ +- angle_v: be_f32 ~ +- position_x: be_f32 ~ +- position_y: be_f32 ~ +- scale_w: be_f32 ~ +- preview: be_u64 ~ +- poster: be_u32 ~ +- selection: be_u64 ~ +- current_time: be_u32 ~ +- track_id: be_u32, +- ||{ ++ do_parse!( ++ version_flags: be_u32 >> ++ created_date: be_u32 >> ++ modified_date: be_u32 >> ++ scale: be_u32 >> ++ duration: be_u32 >> ++ speed: be_f32 >> ++ volume: be_u16 >> // actually a 2 bytes decimal ++ take!(10) >> ++ scale_a: be_f32 >> ++ rotate_b: be_f32 >> ++ angle_u: be_f32 >> ++ rotate_c: be_f32 >> ++ scale_d: be_f32 >> ++ angle_v: be_f32 >> ++ position_x: be_f32 >> ++ position_y: be_f32 >> ++ scale_w: be_f32 >> ++ preview: be_u64 >> ++ poster: be_u32 >> ++ selection: be_u64 >> ++ current_time: be_u32 >> ++ track_id: be_u32 >> ++ ( + MvhdBox::M32(Mvhd32 { + version_flags: version_flags, + created_date: created_date, +@@ -141,36 +140,35 @@ named!(mvhd32 <&[u8], MvhdBox>, + current_time: current_time, + track_id: track_id + }) +- } +- ) ++ )) + ); + + #[allow(non_snake_case)] + named!(mvhd64 <&[u8], MvhdBox>, +- chain!( +- version_flags: be_u32 ~ +- created_date: be_u64 ~ +- modified_date: be_u64 ~ +- scale: be_u32 ~ +- duration: be_u64 ~ +- speed: be_f32 ~ +- volume: be_u16 ~ // actually a 2 bytes decimal +- take!(10) ~ +- scale_a: be_f32 ~ +- rotate_b: be_f32 ~ +- angle_u: be_f32 ~ +- rotate_c: be_f32 ~ +- scale_d: be_f32 ~ +- angle_v: be_f32 ~ +- position_x: be_f32 ~ +- position_y: be_f32 ~ +- scale_w: be_f32 ~ +- preview: be_u64 ~ +- poster: be_u32 ~ +- selection: be_u64 ~ +- current_time: be_u32 ~ +- track_id: be_u32, +- ||{ ++ do_parse!( ++ version_flags: be_u32 >> ++ created_date: be_u64 >> ++ modified_date: be_u64 >> ++ scale: be_u32 >> ++ duration: be_u64 >> ++ speed: be_f32 >> ++ volume: be_u16 >> // actually a 2 bytes decimal ++ take!(10) >> ++ scale_a: be_f32 >> ++ rotate_b: be_f32 >> ++ angle_u: be_f32 >> ++ rotate_c: be_f32 >> ++ scale_d: be_f32 >> ++ angle_v: be_f32 >> ++ position_x: be_f32 >> ++ position_y: be_f32 >> ++ scale_w: be_f32 >> ++ preview: be_u64 >> ++ poster: be_u32 >> ++ selection: be_u64 >> ++ current_time: be_u32 >> ++ track_id: be_u32 >> ++ ( + MvhdBox::M64(Mvhd64 { + version_flags: version_flags, + created_date: created_date, +@@ -194,8 +192,7 @@ named!(mvhd64 <&[u8], MvhdBox>, + current_time: current_time, + track_id: track_id + }) +- } +- ) ++ )) + ); + + #[derive(Debug,Clone)] +@@ -246,11 +243,11 @@ struct MP4BoxHeader { + named!(brand_name<&[u8],&str>, map_res!(take!(4), str::from_utf8)); + + named!(filetype_parser<&[u8], FileType>, +- chain!( +- m: brand_name ~ +- v: take!(4) ~ +- c: many0!(brand_name) , +- ||{ FileType{ major_brand: m, major_brand_version:v, compatible_brands: c } } ++ do_parse!( ++ m: brand_name >> ++ v: take!(4) >> ++ c: many0!(brand_name) >> ++ (FileType{ major_brand: m, major_brand_version:v, compatible_brands: c }) + ) + ); + +@@ -262,7 +259,7 @@ fn mvhd_box(input:&[u8]) -> IResult<&[u8],MvhdBox> { + } else if input.len() == 112 { + mvhd64(input) + } else { +- Error(Position(ErrorKind::Custom(32),input)) ++ Error(error_position!(ErrorKind::Custom(32),input)) + }; + println!("res: {:?}", res); + res +@@ -303,18 +300,18 @@ named!(moov_type<&[u8], MP4BoxType>, + ); + + named!(box_header<&[u8],MP4BoxHeader>, +- chain!( +- length: be_u32 ~ +- tag: box_type , +- || { MP4BoxHeader{ length: length, tag: tag} } ++ do_parse!( ++ length: be_u32 >> ++ tag: box_type >> ++ (MP4BoxHeader{ length: length, tag: tag}) + ) + ); + + named!(moov_header<&[u8],MP4BoxHeader>, +- chain!( +- length: be_u32 ~ +- tag: moov_type , +- || { MP4BoxHeader{ length: length, tag: tag} } ++ do_parse!( ++ length: be_u32 >> ++ tag: moov_type >> ++ (MP4BoxHeader{ length: length, tag: tag}) + ) + ); + +diff --git third_party/rust/nom/tests/multiline.rs third_party/rust/nom/tests/multiline.rs +new file mode 100644 +index 000000000000..90164729f46a +--- /dev/null ++++ third_party/rust/nom/tests/multiline.rs +@@ -0,0 +1,21 @@ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,alphanumeric,eol}; ++ ++use std::str; ++ ++named!(end_of_line, alt!(eof!() | eol)); ++named!(read_line <&str>, map_res!( ++ terminated!(alphanumeric, end_of_line), ++ str::from_utf8 ++)); ++named!(read_lines >, many0!(read_line)); ++ ++#[test] ++fn read_lines_test() { ++ let res = IResult::Done(&b""[..], vec!["Duck", "Dog", "Cow"]); ++ ++ assert_eq!(read_lines(&b"Duck\nDog\nCow\n"[..]), res); ++ assert_eq!(read_lines(&b"Duck\nDog\nCow"[..]), res); ++} +diff --git third_party/rust/nom/tests/named_args.rs third_party/rust/nom/tests/named_args.rs +new file mode 100644 +index 000000000000..e998a0845d45 +--- /dev/null ++++ third_party/rust/nom/tests/named_args.rs +@@ -0,0 +1,108 @@ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,digit}; ++ ++// Parser definition ++ ++use std::str; ++use std::str::FromStr; ++ ++use self::Operator::*; ++ ++enum Operator { ++ Slash, ++ Star, ++} ++ ++impl Operator { ++ fn to_str(&self) -> &'static str { ++ match *self { ++ Slash => "/", ++ Star => "*", ++ } ++ } ++} ++ ++// Parse the specified `Operator`. ++named_args!(operator(op: Operator) <&[u8]>, ++ tag!(op.to_str()) ++); ++ ++// We parse any expr surrounded by the tags `open_tag` and `close_tag`, ignoring all whitespaces around those ++named_args!(brackets<'a>(open_tag: &str, close_tag: &str) , ws!(delimited!( tag!(open_tag), expr, tag!(close_tag) )) ); ++ ++// We transform an integer string into a i64, ignoring surrounding whitespaces ++// We look for a digit suite, and try to convert it. ++// If either str::from_utf8 or FromStr::from_str fail, ++// we fallback to the brackets parser defined above ++named!(factor, alt!( ++ map_res!( ++ map_res!( ++ ws!(digit), ++ str::from_utf8 ++ ), ++ FromStr::from_str ++ ) ++ | call!(brackets, "(", ")") ++ ) ++); ++ ++// We read an initial factor and for each time we find ++// a * or / operator followed by another factor, we do ++// the math by folding everything ++named!(term , do_parse!( ++ init: factor >> ++ res: fold_many0!( ++ pair!(alt!(call!(operator, Star) | call!(operator, Slash)), factor), ++ init, ++ |acc, (op, val): (&[u8], i64)| { ++ if (op[0] as char) == '*' { acc * val } else { acc / val } ++ } ++ ) >> ++ (res) ++ ) ++); ++ ++named!(expr , do_parse!( ++ init: term >> ++ res: fold_many0!( ++ pair!(alt!(tag!("+") | tag!("-")), term), ++ init, ++ |acc, (op, val): (&[u8], i64)| { ++ if (op[0] as char) == '+' { acc + val } else { acc - val } ++ } ++ ) >> ++ (res) ++ ) ++); ++ ++#[test] ++fn factor_test() { ++ assert_eq!(factor(&b"3"[..]), IResult::Done(&b""[..], 3)); ++ assert_eq!(factor(&b" 12"[..]), IResult::Done(&b""[..], 12)); ++ assert_eq!(factor(&b"537 "[..]), IResult::Done(&b""[..], 537)); ++ assert_eq!(factor(&b" 24 "[..]), IResult::Done(&b""[..], 24)); ++} ++ ++ ++#[test] ++fn term_test() { ++ assert_eq!(term(&b" 12 *2 / 3"[..]), IResult::Done(&b""[..], 8)); ++ assert_eq!(term(&b" 2* 3 *2 *2 / 3"[..]), IResult::Done(&b""[..], 8)); ++ assert_eq!(term(&b" 48 / 3/2"[..]), IResult::Done(&b""[..], 8)); ++} ++ ++#[test] ++fn expr_test() { ++ assert_eq!(expr(&b" 1 + 2 "[..]), IResult::Done(&b""[..], 3)); ++ assert_eq!(expr(&b" 12 + 6 - 4+ 3"[..]), IResult::Done(&b""[..], 17)); ++ assert_eq!(expr(&b" 1 + 2*3 + 4"[..]), IResult::Done(&b""[..], 11)); ++} ++ ++#[test] ++fn parens_test() { ++ assert_eq!(expr(&b" ( 2 )"[..]), IResult::Done(&b""[..], 2)); ++ assert_eq!(expr(&b" 2* ( 3 + 4 ) "[..]), IResult::Done(&b""[..], 14)); ++ assert_eq!(expr(&b" 2*2 / ( 5 - 1) + 3"[..]), IResult::Done(&b""[..], 4)); ++} +diff --git third_party/rust/nom/tests/omnom.rs third_party/rust/nom/tests/omnom.rs +index b8cfa04fb7e4..f90b37919120 100644 +--- third_party/rust/nom/tests/omnom.rs ++++ third_party/rust/nom/tests/omnom.rs +@@ -3,7 +3,7 @@ + #[macro_use] + extern crate nom; + +-use nom::{Producer,Consumer,ConsumerState,Input,Move,MemProducer,IResult,HexDisplay}; ++use nom::{Producer,Consumer,ConsumerState,Input,Move,MemProducer,IResult,Offset}; + + #[derive(PartialEq,Eq,Debug)] + enum State { +diff --git third_party/rust/nom/tests/overflow.rs third_party/rust/nom/tests/overflow.rs +new file mode 100644 +index 000000000000..d20099fe42ed +--- /dev/null ++++ third_party/rust/nom/tests/overflow.rs +@@ -0,0 +1,99 @@ ++#[macro_use] ++extern crate nom; ++ ++use nom::{IResult,Needed,be_u8,be_u64}; ++ ++// Parser definition ++ ++// We request a length that would trigger an overflow if computing consumed + requested ++named!(parser01<&[u8],()>, ++ do_parse!( ++ hdr: take!(1) >> ++ data: take!(18446744073709551615) >> ++ ( () ) ++ ) ++); ++ ++// We request a length that would trigger an overflow if computing consumed + requested ++named!(parser02<&[u8],(&[u8],&[u8])>, ++ tuple!(take!(1),take!(18446744073709551615)) ++); ++ ++#[test] ++fn overflow_incomplete_do_parse() { ++ assert_eq!(parser01(&b"3"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_tuple() { ++ assert_eq!(parser02(&b"3"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_length_bytes() { ++ named!(multi<&[u8], Vec<&[u8]> >, many0!( length_bytes!(be_u64) ) ); ++ ++ // Trigger an overflow in length_bytes ++ assert_eq!(multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_many0() { ++ named!(multi<&[u8], Vec<&[u8]> >, many0!( length_bytes!(be_u64) ) ); ++ ++ // Trigger an overflow in many0 ++ assert_eq!(multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++#[cfg(feature = "std")] ++fn overflow_incomplete_many1() { ++ named!(multi<&[u8], Vec<&[u8]> >, many1!( length_bytes!(be_u64) ) ); ++ ++ // Trigger an overflow in many1 ++ assert_eq!(multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_many_till() { ++ named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( length_bytes!(be_u64), tag!("abc") ) ); ++ ++ // Trigger an overflow in many_till ++ assert_eq!(multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_many_m_n() { ++ named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, length_bytes!(be_u64) ) ); ++ ++ // Trigger an overflow in many_m_n ++ assert_eq!(multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_count() { ++ named!(counter<&[u8], Vec<&[u8]> >, count!( length_bytes!(be_u64), 2 ) ); ++ ++ assert_eq!(counter(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_count_fixed() { ++ named!(counter< [&[u8]; 2] >, count_fixed!( &[u8], length_bytes!(be_u64), 2 ) ); ++ ++ assert_eq!(counter(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_length_count() { ++ named!(multi<&[u8], Vec<&[u8]> >, length_count!( be_u8, length_bytes!(be_u64) ) ); ++ ++ assert_eq!(multi(&b"\x04\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xee\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} ++ ++#[test] ++fn overflow_incomplete_length_data() { ++ named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) ); ++ ++ assert_eq!(multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff\xaa"[..]), IResult::Incomplete(Needed::Unknown)); ++} +diff --git third_party/rust/nom/tests/reborrow_fold.rs third_party/rust/nom/tests/reborrow_fold.rs +new file mode 100644 +index 000000000000..0527cb2c83ee +--- /dev/null ++++ third_party/rust/nom/tests/reborrow_fold.rs +@@ -0,0 +1,16 @@ ++#![allow(dead_code)] ++#![allow(unused_variables)] ++ ++ ++#[macro_use] ++extern crate nom; ++ ++use std::str; ++ ++ ++named_args!(atom<'a>(tomb: &'a mut ()), ++ map!(map_res!(is_not_s!(" \t\r\n()"), str::from_utf8), ToString::to_string)); ++ ++ ++named_args!(list<'a>(tomb: &'a mut ()), ++ delimited!(char!('('), fold_many0!(call!(atom, tomb), "".to_string(), |acc: String, next: String| acc + next.as_str()), char!(')'))); Index: head/mail/thunderbird/files/patch-z-bug1436911 =================================================================== --- head/mail/thunderbird/files/patch-z-bug1436911 +++ head/mail/thunderbird/files/patch-z-bug1436911 @@ -0,0 +1,1163 @@ +commit 6b81d0b99f20 +Author: Nicholas Nethercote +Date: Thu Mar 8 15:47:24 2018 +1100 + + Bug 1436911 - Avoid the early/late prefs split. r=glandium + + All prefs that need to be sent to a new content process are now put into the + shared memory segment, and they are identified by the pref name instead of an + index into a list. The old IPC used at process startup (in XPCOMInitData) is + removed. + + Benefits: + + - It removes the need for the early prefs list + (dom/ipc/ContentProcesses.{h,cpp}) and the associated checking, which is ugly + and often trips people up (e.g. bug 1432979, bug 1439406). + + - Using prefnames instead of indices fixes some fragility (fixing bug 1419432). + + - It fixes the problem of early prefs being installed as unlocked default + values even if they are locked and/or have user values. + + MozReview-Commit-ID: FRIzHF8Tjd +--- + dom/ipc/ContentChild.cpp | 2 - + dom/ipc/ContentParent.cpp | 4 +- + dom/ipc/ContentPrefs.cpp | 357 ------------------------------ + dom/ipc/ContentPrefs.h | 27 --- + dom/ipc/ContentProcess.cpp | 5 +- + dom/ipc/PContent.ipdl | 7 +- + dom/ipc/moz.build | 2 - + layout/style/nsCSSProps.h | 2 +- + modules/libpref/Preferences.cpp | 470 ++++++++++++++++++++++------------------ + modules/libpref/Preferences.h | 15 +- + 10 files changed, 278 insertions(+), 613 deletions(-) + +diff --git dom/ipc/ContentChild.cpp dom/ipc/ContentChild.cpp +index f61ab07b81e2..af1ef9cf4c7e 100644 +--- dom/ipc/ContentChild.cpp ++++ dom/ipc/ContentChild.cpp +@@ -1185,8 +1185,6 @@ void + ContentChild::InitXPCOM(const XPCOMInitData& aXPCOMInit, + const mozilla::dom::ipc::StructuredCloneData& aInitialData) + { +- Preferences::SetLatePreferences(&aXPCOMInit.prefs()); +- + // Do this as early as possible to get the parent process to initialize the + // background thread since we'll likely need database information very soon. + BackgroundChild::Startup(); +diff --git dom/ipc/ContentParent.cpp dom/ipc/ContentParent.cpp +index 208bb47a970b..4ce5c6bf23d5 100644 +--- dom/ipc/ContentParent.cpp ++++ dom/ipc/ContentParent.cpp +@@ -197,7 +197,6 @@ + + #include "nsLayoutStylesheetCache.h" + +-#include "ContentPrefs.h" + #include "mozilla/Sprintf.h" + + #ifdef MOZ_WEBRTC +@@ -2009,7 +2008,7 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR + + // Serialize the early prefs. + nsAutoCStringN<1024> prefs; +- Preferences::SerializeEarlyPreferences(prefs); ++ Preferences::SerializePreferences(prefs); + + // Set up the shared memory. + base::SharedMemory shm; +@@ -2228,7 +2227,6 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority) + + XPCOMInitData xpcomInit; + +- Preferences::GetPreferences(&xpcomInit.prefs()); + nsCOMPtr io(do_GetIOService()); + MOZ_ASSERT(io, "No IO service?"); + DebugOnly rv = io->GetOffline(&xpcomInit.isOffline()); +diff --git dom/ipc/ContentPrefs.cpp dom/ipc/ContentPrefs.cpp +deleted file mode 100644 +index 808b797d9bee..000000000000 +--- dom/ipc/ContentPrefs.cpp ++++ /dev/null +@@ -1,361 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this +- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "ContentPrefs.h" +- +-/****************************************************************************** +- * +- * DO NOT ADD PREFS TO THIS LIST WITHOUT DOM PEER REVIEW +- * +- * This is the list of preferences that are sent to the content process on +- * startup. Only prefs that are required immediately upon startup should be +- * listed here. The first IPC message received in the content process will +- * contain all the other prefs. Prefs should only be listed here if they must be +- * read before the first IPC message is received. +- * +- ******************************************************************************/ +- +-const char* mozilla::dom::ContentPrefs::gEarlyPrefs[] = { +- "accessibility.monoaudio.enable", +- "accessibility.mouse_focuses_formcontrol", +- "accessibility.tabfocus_applies_to_xul", +- "app.update.channel", +- "browser.autofocus", +- "browser.dom.window.dump.enabled", +- "browser.sessionhistory.max_entries", +- "browser.sessionhistory.max_total_viewers", +-#if defined(NIGHTLY_BUILD) || defined(DEBUG) +- "browser.startup.record", +-#endif +-#if defined(ANDROID) +- "consoleservice.logcat", +-#endif +- "content.cors.disable", +- "content.cors.no_private_data", +- "content.notify.backoffcount", +- "content.notify.interval", +- "content.notify.ontimer", +- "content.sink.enable_perf_mode", +- "content.sink.event_probe_rate", +- "content.sink.initial_perf_time", +- "content.sink.interactive_deflect_count", +- "content.sink.interactive_parse_time", +- "content.sink.interactive_time", +- "content.sink.pending_event_mode", +- "content.sink.perf_deflect_count", +- "content.sink.perf_parse_time", +- "device.storage.prompt.testing", +- "device.storage.writable.name", +- "devtools.enabled", +- "dom.allow_XUL_XBL_for_file", +- "dom.allow_cut_copy", +- "dom.animations-api.core.enabled", +- "dom.animations-api.element-animate.enabled", +- "dom.animations-api.pending-member.enabled", +- "dom.enable_frame_timing", +- "dom.enable_performance", +- "dom.enable_performance_navigation_timing", +- "dom.enable_resource_timing", +- "dom.event.handling-user-input-time-limit", +- "dom.event.touch.coalescing.enabled", +- "dom.forms.autocomplete.formautofill", +- "dom.forms.inputmode", +- "dom.input.skip_cursor_move_for_same_value_set", +- "dom.ipc.processPriorityManager.backgroundGracePeriodMS", +- "dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", +- "dom.ipc.useNativeEventProcessing.content", +- "dom.max_chrome_script_run_time", +- "dom.max_ext_content_script_run_time", +- "dom.max_script_run_time", +- "dom.mozBrowserFramesEnabled", +- "dom.performance.enable_notify_performance_timing", +- "dom.performance.enable_user_timing_logging", +- "dom.placeholder.show_on_focus", +- "dom.requestIdleCallback.enabled", +- "dom.script_loader.bytecode_cache.enabled", +- "dom.script_loader.bytecode_cache.strategy", +- "dom.storage.testing", +- "dom.url.encode_decode_hash", +- "dom.url.getters_decode_hash", +- "dom.use_watchdog", +- "dom.vibrator.enabled", +- "dom.vibrator.max_vibrate_list_len", +- "dom.vibrator.max_vibrate_ms", +- "dom.webcomponents.customelements.enabled", +- "dom.webcomponents.shadowdom.enabled", +- "focusmanager.testmode", +- "font.size.inflation.disabledInMasterProcess", +- "font.size.inflation.emPerLine", +- "font.size.inflation.forceEnabled", +- "font.size.inflation.lineThreshold", +- "font.size.inflation.mappingIntercept", +- "font.size.inflation.maxRatio", +- "font.size.inflation.minTwips", +- "font.size.systemFontScale", +- "full-screen-api.allow-trusted-requests-only", +- "full-screen-api.enabled", +- "full-screen-api.unprefix.enabled", +-#ifdef FUZZING +- "fuzzing.enabled", +-#endif +- "gfx.font_rendering.opentype_svg.enabled", +- "hangmonitor.timeout", +- "html5.flushtimer.initialdelay", +- "html5.flushtimer.subsequentdelay", +- "html5.offmainthread", +- "intl.charset.fallback.tld", +- "intl.charset.fallback.utf8_for_file", +- "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", +- "javascript.enabled", +- "javascript.options.array_prototype_values", +- "javascript.options.asmjs", +- "javascript.options.asyncstack", +- "javascript.options.baselinejit", +- "javascript.options.baselinejit.threshold", +- "javascript.options.baselinejit.unsafe_eager_compilation", +- "javascript.options.discardSystemSource", +- "javascript.options.dump_stack_on_debuggee_would_run", +- "javascript.options.gczeal", +- "javascript.options.gczeal.frequency", +- "javascript.options.ion", +- "javascript.options.ion.offthread_compilation", +- "javascript.options.ion.threshold", +- "javascript.options.ion.unsafe_eager_compilation", +- "javascript.options.jit.full_debug_checks", +- "javascript.options.native_regexp", +- "javascript.options.parallel_parsing", +- "javascript.options.shared_memory", +- "javascript.options.spectre.index_masking", +- "javascript.options.spectre.jit_to_C++_calls", +- "javascript.options.spectre.object_mitigations.barriers", +- "javascript.options.spectre.object_mitigations.misc", +- "javascript.options.spectre.string_mitigations", +- "javascript.options.spectre.value_masking", +- "javascript.options.streams", +- "javascript.options.strict", +- "javascript.options.strict.debug", +- "javascript.options.throw_on_asmjs_validation_failure", +- "javascript.options.throw_on_debuggee_would_run", +- "javascript.options.wasm", +- "javascript.options.wasm_baselinejit", +- "javascript.options.wasm_ionjit", +- "javascript.options.werror", +- "javascript.use_us_english_locale", +- "jsloader.shareGlobal", +- "layout.css.all-shorthand.enabled", +- "layout.css.background-blend-mode.enabled", +- "layout.css.box-decoration-break.enabled", +- "layout.css.color-adjust.enabled", +- "layout.css.column-span.enabled", +- "layout.css.contain.enabled", +- "layout.css.control-characters.visible", +- "layout.css.emulate-moz-box-with-flex", +- "layout.css.expensive-style-struct-assertions.enabled", +- "layout.css.float-logical-values.enabled", +- "layout.css.font-display.enabled", +- "layout.css.font-variations.enabled", +- "layout.css.frames-timing.enabled", +- "layout.css.getBoxQuads.enabled", +- "layout.css.grid-template-subgrid-value.enabled", +- "layout.css.grid.enabled", +- "layout.css.image-orientation.enabled", +- "layout.css.individual-transform.enabled", +- "layout.css.initial-letter.enabled", +- "layout.css.isolation.enabled", +- "layout.css.mix-blend-mode.enabled", +- "layout.css.moz-document.content.enabled", +- "layout.css.osx-font-smoothing.enabled", +- "layout.css.overflow-clip-box.enabled", +- "layout.css.overscroll-behavior.enabled", +- "layout.css.prefixes.animations", +- "layout.css.prefixes.border-image", +- "layout.css.prefixes.box-sizing", +- "layout.css.prefixes.device-pixel-ratio-webkit", +- "layout.css.prefixes.font-features", +- "layout.css.prefixes.gradients", +- "layout.css.prefixes.transforms", +- "layout.css.prefixes.transitions", +- "layout.css.prefixes.webkit", +- "layout.css.scope-pseudo.enabled", +- "layout.css.scoped-style.enabled", +- "layout.css.scroll-behavior.property-enabled", +- "layout.css.scroll-snap.enabled", +-#ifdef MOZ_STYLO +- "layout.css.servo.chrome.enabled", +- "layout.css.servo.enabled", +-#endif +- "layout.css.shape-outside.enabled", +- "layout.css.text-align-unsafe-value.enabled", +- "layout.css.text-combine-upright-digits.enabled", +- "layout.css.text-combine-upright.enabled", +- "layout.css.text-justify.enabled", +- "layout.css.touch_action.enabled", +- "layout.css.visited_links_enabled", +- "layout.idle_period.required_quiescent_frames", +- "layout.idle_period.time_limit", +- "layout.interruptible-reflow.enabled", +- "mathml.disabled", +- "media.audio-max-decode-error", +- "media.cache_readahead_limit", +- "media.cache_resume_threshold", +- "media.cache_size", +- "media.clearkey.persistent-license.enabled", +- "media.cubeb.backend", +- "media.cubeb.sandbox", +- "media.cubeb_latency_msg_frames", +- "media.cubeb_latency_playback_ms", +- "media.decoder-doctor.wmf-disabled-is-failure", +- "media.decoder.recycle.enabled", +- "media.decoder.skip-to-next-key-frame.enabled", +- "media.dormant-on-pause-timeout-ms", +- "media.eme.audio.blank", +- "media.eme.chromium-api.video-shmems", +- "media.eme.enabled", +- "media.eme.video.blank", +- "media.ffmpeg.enabled", +- "media.ffmpeg.low-latency.enabled", +- "media.ffvpx.enabled", +- "media.ffvpx.low-latency.enabled", +- "media.flac.enabled", +- "media.forcestereo.enabled", +- "media.gmp.decoder.enabled", +- "media.gmp.insecure.allow", +- "media.gpu-process-decoder", +- "media.hls.enabled", +- "media.libavcodec.allow-obsolete", +- "media.memory_cache_max_size", +- "media.memory_caches_combined_limit_kb", +- "media.memory_caches_combined_limit_pc_sysmem", +- "media.mp4.enabled", +- "media.navigator.mediadatadecoder_enabled", +- "media.ogg.enabled", +- "media.ogg.flac.enabled", +- "media.playback.warnings-as-errors", +- "media.playback.warnings-as-errors.stagefright-vs-rust", +- "media.resampling.enabled", +- "media.resume-bkgnd-video-on-tabhover", +- "media.ruin-av-sync.enabled", +- "media.rust.mp4parser", +- "media.rust.test_mode", +- "media.seamless-looping", +- "media.suspend-bkgnd-video.delay-ms", +- "media.suspend-bkgnd-video.enabled", +- "media.use-blank-decoder", +- "media.video-max-decode-error", +- "media.video_stats.enabled", +- "media.videocontrols.lock-video-orientation", +- "media.volume_scale", +- "media.webspeech.recognition.enable", +- "media.webspeech.recognition.force_enable", +- "media.webspeech.synth.force_global_queue", +- "media.webspeech.test.enable", +- "media.webspeech.test.fake_fsm_events", +- "media.webspeech.test.fake_recognition_service", +- "media.wmf.allow-unsupported-resolutions", +- "media.wmf.enabled", +- "media.wmf.skip-blacklist", +- "media.wmf.vp9.enabled", +- "network.IDN.blacklist_chars", +- "network.IDN.restriction_profile", +- "network.IDN.use_whitelist", +- "network.IDN_show_punycode", +- "network.buffer.cache.count", +- "network.buffer.cache.size", +- "network.captive-portal-service.enabled", +- "network.cookie.cookieBehavior", +- "network.cookie.lifetimePolicy", +- "network.dns.disablePrefetch", +- "network.dns.disablePrefetchFromHTTPS", +- "network.file.disable_unc_paths", +- "network.http.tailing.enabled", +- "network.jar.block-remote-files", +- "network.loadinfo.skip_type_assertion", +- "network.notify.changed", +- "network.offline-mirrors-connectivity", +- "network.protocol-handler.external.jar", +- "network.proxy.type", +- "network.security.ports.banned", +- "network.security.ports.banned.override", +- "network.standard-url.enable-rust", +- "network.standard-url.max-length", +- "network.standard-url.punycode-host", +- "network.sts.max_time_for_events_between_two_polls", +- "network.sts.max_time_for_pr_close_during_shutdown", +- "network.tcp.keepalive.enabled", +- "network.tcp.keepalive.idle_time", +- "network.tcp.keepalive.probe_count", +- "network.tcp.keepalive.retry_interval", +- "network.tcp.sendbuffer", +- "nglayout.debug.invalidation", +- "privacy.donottrackheader.enabled", +- "privacy.firstparty.isolate", +- "privacy.firstparty.isolate.restrict_opener_access", +- "privacy.reduceTimerPrecision", +- "privacy.resistFingerprinting", +- "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts", +- "privacy.resistFingerprinting.reduceTimerPrecision.jitter", +- "privacy.resistFingerprinting.reduceTimerPrecision.microseconds", +- "privacy.resistFingerprinting.target_video_res", +- "privacy.resistFingerprinting.video_dropped_ratio", +- "privacy.resistFingerprinting.video_frames_per_sec", +- "privacy.trackingprotection.lower_network_priority", +- "privacy.window.maxInnerHeight", +- "privacy.window.maxInnerWidth", +- "security.csp.enable", +- "security.data_uri.block_toplevel_data_uri_navigations", +- "security.data_uri.unique_opaque_origin", +- "security.fileuri.strict_origin_policy", +- "security.mixed_content.block_active_content", +- "security.mixed_content.block_display_content", +- "security.mixed_content.block_object_subrequest", +- "security.mixed_content.hsts_priming_cache_timeout", +- "security.mixed_content.send_hsts_priming", +- "security.mixed_content.upgrade_display_content", +- "security.mixed_content.use_hsts", +- "security.sandbox.content.level", +- "security.sandbox.content.tempDirSuffix", +- "security.sandbox.logging.enabled", +- "security.sandbox.mac.track.violations", +- "security.sandbox.windows.log.stackTraceDepth", +- "svg.disabled", +- "svg.display-lists.hit-testing.enabled", +- "svg.display-lists.painting.enabled", +- "svg.new-getBBox.enabled", +- "svg.path-caching.enabled", +- "svg.transform-box.enabled", +- "toolkit.asyncshutdown.crash_timeout", +- "toolkit.asyncshutdown.log", +- "toolkit.osfile.log", +- "toolkit.osfile.log.redirect", +- "toolkit.telemetry.enabled", +- "toolkit.telemetry.idleTimeout", +- "toolkit.telemetry.initDelay", +- "toolkit.telemetry.log.dump", +- "toolkit.telemetry.log.level", +- "toolkit.telemetry.minSubsessionLength", +- "toolkit.telemetry.scheduler.idleTickInterval", +- "toolkit.telemetry.scheduler.tickInterval", +- "toolkit.telemetry.testing.overridePreRelease", +- "toolkit.telemetry.unified", +- "ui.key.menuAccessKeyFocuses", +- "ui.popup.disable_autohide", +- "ui.use_activity_cursor", +- "view_source.editor.external", +- "zoom.maxPercent", +- "zoom.minPercent" +-}; +- +-const char** mozilla::dom::ContentPrefs::GetEarlyPrefs(size_t* aCount) +-{ +- *aCount = ArrayLength(ContentPrefs::gEarlyPrefs); +- return gEarlyPrefs; +-} +- +-const char* mozilla::dom::ContentPrefs::GetEarlyPref(size_t aIndex) +-{ +- MOZ_ASSERT(aIndex < ArrayLength(ContentPrefs::gEarlyPrefs)); +- return gEarlyPrefs[aIndex]; +-} +diff --git dom/ipc/ContentPrefs.h dom/ipc/ContentPrefs.h +deleted file mode 100644 +index 72ce8d236c11..000000000000 +--- dom/ipc/ContentPrefs.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this +- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#ifndef mozilla_dom_ContentPrefs_h +-#define mozilla_dom_ContentPrefs_h +- +-// See the comment in ContentPrefs.cpp for more information. +- +-namespace mozilla { +-namespace dom { +- +-class ContentPrefs { +-public: +- static const char** GetEarlyPrefs(size_t* aCount); +- static const char* GetEarlyPref(size_t aIndex); +- +-private: +- static const char* gEarlyPrefs[]; +-}; +- +-} +-} +- +-#endif +diff --git dom/ipc/ContentProcess.cpp dom/ipc/ContentProcess.cpp +index 2441c8cb9224..c00283dc5084 100644 +--- dom/ipc/ContentProcess.cpp ++++ dom/ipc/ContentProcess.cpp +@@ -7,7 +7,6 @@ + #include "mozilla/ipc/IOThreadChild.h" + + #include "ContentProcess.h" +-#include "ContentPrefs.h" + #include "base/shared_memory.h" + #include "mozilla/Preferences.h" + #include "mozilla/Scheduler.h" +@@ -226,8 +225,8 @@ ContentProcess::Init(int aArgc, char* aArgv[]) + NS_ERROR("failed to map shared memory in the child"); + return false; + } +- Preferences::DeserializeEarlyPreferences(static_cast(shm.memory()), +- prefsLen); ++ Preferences::DeserializePreferences(static_cast(shm.memory()), ++ prefsLen); + + Scheduler::SetPrefs(schedulerPrefs); + mContent.Init(IOThreadChild::message_loop(), +diff --git dom/ipc/PContent.ipdl dom/ipc/PContent.ipdl +index 5d077976569a..fb967ffc53a9 100644 +--- dom/ipc/PContent.ipdl ++++ dom/ipc/PContent.ipdl +@@ -155,6 +155,12 @@ union MaybePrefValue { + null_t; + }; + ++// This serialization form mirrors that used in mozilla::Pref in ++// Preferences.cpp. The two should be kept in sync, e.g. if something is added ++// to one it should also be added to the other. ++// ++// Note: there is no need to pass the isSticky attribute because that's an ++// immutable attribute obtained from file at startup. + struct Pref { + nsCString name; + bool isLocked; +@@ -273,7 +279,6 @@ struct XPCOMInitData + ClipboardCapabilities clipboardCaps; + DomainPolicyClone domainPolicy; + OptionalURIParams userContentSheetURL; +- Pref[] prefs; + GfxVarUpdate[] gfxNonDefaultVarUpdates; + ContentDeviceData contentDeviceData; + GfxInfoFeatureStatus[] gfxFeatureStatus; +diff --git dom/ipc/moz.build dom/ipc/moz.build +index 3c5541c7791b..5e92a0d52b5d 100644 +--- dom/ipc/moz.build ++++ dom/ipc/moz.build +@@ -26,7 +26,6 @@ EXPORTS.mozilla.dom += [ + 'ContentBridgeParent.h', + 'ContentChild.h', + 'ContentParent.h', +- 'ContentPrefs.h', + 'ContentProcess.h', + 'ContentProcessHost.h', + 'ContentProcessManager.h', +@@ -59,7 +58,6 @@ UNIFIED_SOURCES += [ + 'ContentBridgeChild.cpp', + 'ContentBridgeParent.cpp', + 'ContentParent.cpp', +- 'ContentPrefs.cpp', + 'ContentProcess.cpp', + 'ContentProcessHost.cpp', + 'ContentProcessManager.cpp', +diff --git layout/style/nsCSSProps.h layout/style/nsCSSProps.h +index dce44bf61b35..80288336a08b 100644 +--- layout/style/nsCSSProps.h ++++ layout/style/nsCSSProps.h +@@ -645,7 +645,7 @@ public: + // In the child process, assert that we're not trying to parse stylesheets + // before we've gotten all our prefs. + MOZ_ASSERT_IF(!XRE_IsParentProcess(), +- mozilla::Preferences::AreAllPrefsSetInContentProcess()); ++ mozilla::Preferences::ArePrefsInitedInContentProcess()); + return gPropertyEnabled[aProperty]; + } + +diff --git modules/libpref/Preferences.cpp modules/libpref/Preferences.cpp +index fe780686f2eb..488095f49236 100644 +--- modules/libpref/Preferences.cpp ++++ modules/libpref/Preferences.cpp +@@ -15,7 +15,6 @@ + #include "mozilla/ArenaAllocator.h" + #include "mozilla/ArrayUtils.h" + #include "mozilla/Attributes.h" +-#include "mozilla/dom/ContentPrefs.h" + #include "mozilla/dom/PContent.h" + #include "mozilla/HashFunctions.h" + #include "mozilla/Logging.h" +@@ -131,6 +130,29 @@ enum class PrefType : uint8_t + Bool = 3, + }; + ++// This is used for pref names and string pref values. We encode the string ++// length, then a '/', then the string chars. This encoding means there are no ++// special chars that are forbidden or require escaping. ++static void ++SerializeAndAppendString(const char* aChars, nsCString& aStr) ++{ ++ aStr.AppendInt(uint32_t(strlen(aChars))); ++ aStr.Append('/'); ++ aStr.Append(aChars); ++} ++ ++static char* ++DeserializeString(char* aChars, nsCString& aStr) ++{ ++ char* p = aChars; ++ uint32_t length = strtol(p, &p, 10); ++ MOZ_ASSERT(p[0] == '/'); ++ p++; // move past the '/' ++ aStr.Assign(p, length); ++ p += length; // move past the string itself ++ return p; ++} ++ + // Keep this in sync with PrefValue in prefs_parser/src/lib.rs. + union PrefValue { + const char* mStringVal; +@@ -223,6 +245,64 @@ union PrefValue { + MOZ_CRASH(); + } + } ++ ++ void SerializeAndAppend(PrefType aType, nsCString& aStr) ++ { ++ switch (aType) { ++ case PrefType::Bool: ++ aStr.Append(mBoolVal ? 'T' : 'F'); ++ break; ++ ++ case PrefType::Int: ++ aStr.AppendInt(mIntVal); ++ break; ++ ++ case PrefType::String: { ++ SerializeAndAppendString(mStringVal, aStr); ++ break; ++ } ++ ++ case PrefType::None: ++ default: ++ MOZ_CRASH(); ++ } ++ } ++ ++ static char* Deserialize(PrefType aType, ++ char* aStr, ++ dom::MaybePrefValue* aDomValue) ++ { ++ char* p = aStr; ++ ++ switch (aType) { ++ case PrefType::Bool: ++ if (*p == 'T') { ++ *aDomValue = true; ++ } else if (*p == 'F') { ++ *aDomValue = false; ++ } else { ++ *aDomValue = false; ++ NS_ERROR("bad bool pref value"); ++ } ++ p++; ++ return p; ++ ++ case PrefType::Int: { ++ *aDomValue = int32_t(strtol(p, &p, 10)); ++ return p; ++ } ++ ++ case PrefType::String: { ++ nsCString str; ++ p = DeserializeString(p, str); ++ *aDomValue = str; ++ return p; ++ } ++ ++ default: ++ MOZ_CRASH(); ++ } ++ } + }; + + #ifdef DEBUG +@@ -694,6 +774,159 @@ public: + return false; + } + ++ // Prefs are serialized in a manner that mirrors dom::Pref. The two should be ++ // kept in sync. E.g. if something is added to one it should also be added to ++ // the other. (It would be nice to be able to use the code generated from ++ // IPDL for serializing dom::Pref here instead of writing by hand this ++ // serialization/deserialization. Unfortunately, that generated code is ++ // difficult to use directly, outside of the IPDL IPC code.) ++ // ++ // The grammar for the serialized prefs has the following form. ++ // ++ // = ':' ':' ? ':' ? '\n' ++ // = 'B' | 'I' | 'S' ++ // = 'L' | '-' ++ // = ++ // = | | ++ // = 'T' | 'F' ++ // = an integer literal accepted by strtol() ++ // = '/' ++ // = any char sequence of length dictated by the preceding ++ // . ++ // ++ // No whitespace is tolerated between tokens. must match the types of ++ // the values. ++ // ++ // The serialization is text-based, rather than binary, for the following ++ // reasons. ++ // ++ // - The size difference wouldn't be much different between text-based and ++ // binary. Most of the space is for strings (pref names and string pref ++ // values), which would be the same in both styles. And other differences ++ // would be minimal, e.g. small integers are shorter in text but long ++ // integers are longer in text. ++ // ++ // - Likewise, speed differences should be negligible. ++ // ++ // - It's much easier to debug a text-based serialization. E.g. you can ++ // print it and inspect it easily in a debugger. ++ // ++ // Examples of unlocked boolean prefs: ++ // - "B-:8/my.bool1:F:T\n" ++ // - "B-:8/my.bool2:F:\n" ++ // - "B-:8/my.bool3::T\n" ++ // ++ // Examples of locked integer prefs: ++ // - "IL:7/my.int1:0:1\n" ++ // - "IL:7/my.int2:123:\n" ++ // - "IL:7/my.int3::-99\n" ++ // ++ // Examples of unlocked string prefs: ++ // - "S-:10/my.string1:3/abc:4/wxyz\n" ++ // - "S-:10/my.string2:5/1.234:\n" ++ // - "S-:10/my.string3::7/string!\n" ++ ++ void SerializeAndAppend(nsCString& aStr) ++ { ++ switch (Type()) { ++ case PrefType::Bool: ++ aStr.Append('B'); ++ break; ++ ++ case PrefType::Int: ++ aStr.Append('I'); ++ break; ++ ++ case PrefType::String: { ++ aStr.Append('S'); ++ break; ++ } ++ ++ case PrefType::None: ++ default: ++ MOZ_CRASH(); ++ } ++ ++ aStr.Append(mIsLocked ? 'L' : '-'); ++ aStr.Append(':'); ++ ++ SerializeAndAppendString(mName, aStr); ++ aStr.Append(':'); ++ ++ if (mHasDefaultValue) { ++ mDefaultValue.SerializeAndAppend(Type(), aStr); ++ } ++ aStr.Append(':'); ++ ++ if (mHasUserValue) { ++ mUserValue.SerializeAndAppend(Type(), aStr); ++ } ++ aStr.Append('\n'); ++ } ++ ++ static char* Deserialize(char* aStr, dom::Pref* aDomPref) ++ { ++ char* p = aStr; ++ ++ // The type. ++ PrefType type; ++ if (*p == 'B') { ++ type = PrefType::Bool; ++ } else if (*p == 'I') { ++ type = PrefType::Int; ++ } else if (*p == 'S') { ++ type = PrefType::String; ++ } else { ++ NS_ERROR("bad pref type"); ++ type = PrefType::None; ++ } ++ p++; // move past the type char ++ ++ // Locked? ++ bool isLocked; ++ if (*p == 'L') { ++ isLocked = true; ++ } else if (*p == '-') { ++ isLocked = false; ++ } else { ++ NS_ERROR("bad pref locked status"); ++ isLocked = false; ++ } ++ p++; // move past the isLocked char ++ ++ MOZ_ASSERT(*p == ':'); ++ p++; // move past the ':' ++ ++ // The pref name. ++ nsCString name; ++ p = DeserializeString(p, name); ++ ++ MOZ_ASSERT(*p == ':'); ++ p++; // move past the ':' preceding the default value ++ ++ dom::MaybePrefValue maybeDefaultValue; ++ if (*p != ':') { ++ dom::PrefValue defaultValue; ++ p = PrefValue::Deserialize(type, p, &maybeDefaultValue); ++ } ++ ++ MOZ_ASSERT(*p == ':'); ++ p++; // move past the ':' between the default and user values ++ ++ dom::MaybePrefValue maybeUserValue; ++ if (*p != '\n') { ++ dom::PrefValue userValue; ++ p = PrefValue::Deserialize(type, p, &maybeUserValue); ++ } ++ ++ MOZ_ASSERT(*p == '\n'); ++ p++; // move past the '\n' following the user value ++ ++ *aDomPref = dom::Pref(name, isLocked, maybeDefaultValue, maybeUserValue); ++ ++ return p; ++ } ++ + void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) + { + // Note: mName is allocated in gPrefNameArena, measured elsewhere. +@@ -880,41 +1113,9 @@ pref_savePrefs() + + #ifdef DEBUG + +-// For content processes, what prefs have been initialized? +-enum class ContentProcessPhase +-{ +- eNoPrefsSet, +- eEarlyPrefsSet, +- eEarlyAndLatePrefsSet, +-}; +- + // Note that this never changes in the parent process, and is only read in + // content processes. +-static ContentProcessPhase gPhase = ContentProcessPhase::eNoPrefsSet; +- +-struct StringComparator +-{ +- const char* mPrefName; +- +- explicit StringComparator(const char* aPrefName) +- : mPrefName(aPrefName) +- { +- } +- +- int operator()(const char* aPrefName) const +- { +- return strcmp(mPrefName, aPrefName); +- } +-}; +- +-static bool +-IsEarlyPref(const char* aPrefName) +-{ +- size_t prefsLen; +- size_t found; +- const char** list = mozilla::dom::ContentPrefs::GetEarlyPrefs(&prefsLen); +- return BinarySearchIf(list, 0, prefsLen, StringComparator(aPrefName), &found); +-} ++static bool gContentProcessPrefsAreInited = false; + + #endif // DEBUG + +@@ -923,23 +1124,7 @@ pref_HashTableLookupInner(const char* aPrefName) + { + MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal()); + +-#ifdef DEBUG +- if (!XRE_IsParentProcess()) { +- if (gPhase == ContentProcessPhase::eNoPrefsSet) { +- MOZ_CRASH_UNSAFE_PRINTF("accessing pref %s before early prefs are set", +- aPrefName); +- } +- +- if (gPhase == ContentProcessPhase::eEarlyPrefsSet && +- !IsEarlyPref(aPrefName)) { +- // If you hit this crash, you have an early access of a non-early pref. +- // Consider moving the access later or add the pref to the whitelist of +- // early prefs in ContentPrefs.cpp and get review from a DOM peer. +- MOZ_CRASH_UNSAFE_PRINTF( +- "accessing non-early pref %s before late prefs are set", aPrefName); +- } +- } +-#endif ++ MOZ_ASSERT_IF(!XRE_IsParentProcess(), gContentProcessPrefsAreInited); + + return static_cast(gHashTable->Search(aPrefName)); + } +@@ -2932,8 +3117,8 @@ public: + + } // namespace + +-// A list of prefs sent early from the parent, via shared memory. +-static InfallibleTArray* gEarlyDomPrefs; ++// A list of changed prefs sent from the parent via shared memory. ++static InfallibleTArray* gChangedDomPrefs; + + static const char kTelemetryPref[] = "toolkit.telemetry.enabled"; + static const char kChannelPref[] = "app.update.channel"; +@@ -3050,12 +3235,12 @@ Preferences::GetInstanceForService() + } + + if (!XRE_IsParentProcess()) { +- MOZ_ASSERT(gEarlyDomPrefs); +- for (unsigned int i = 0; i < gEarlyDomPrefs->Length(); i++) { +- Preferences::SetPreference(gEarlyDomPrefs->ElementAt(i)); ++ MOZ_ASSERT(gChangedDomPrefs); ++ for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) { ++ Preferences::SetPreference(gChangedDomPrefs->ElementAt(i)); + } +- delete gEarlyDomPrefs; +- gEarlyDomPrefs = nullptr; ++ delete gChangedDomPrefs; ++ gChangedDomPrefs = nullptr; + + } else { + // Check if there is a deployment configuration file. If so, set up the +@@ -3179,149 +3364,44 @@ NS_IMPL_ISUPPORTS(Preferences, + nsISupportsWeakReference) + + /* static */ void +-Preferences::SerializeEarlyPreferences(nsCString& aStr) ++Preferences::SerializePreferences(nsCString& aStr) + { + MOZ_RELEASE_ASSERT(InitStaticMembers()); + +- nsAutoCStringN<256> boolPrefs, intPrefs, stringPrefs; +- size_t numEarlyPrefs; +- dom::ContentPrefs::GetEarlyPrefs(&numEarlyPrefs); +- +- for (unsigned int i = 0; i < numEarlyPrefs; i++) { +- const char* prefName = dom::ContentPrefs::GetEarlyPref(i); +- MOZ_ASSERT_IF(i > 0, +- strcmp(prefName, dom::ContentPrefs::GetEarlyPref(i - 1)) > 0); +- +- Pref* pref = pref_HashTableLookup(prefName); +- if (!pref || !pref->MustSendToContentProcesses()) { +- continue; +- } ++ aStr.Truncate(); + +- switch (pref->Type()) { +- case PrefType::Bool: +- boolPrefs.Append( +- nsPrintfCString("%u:%d|", i, Preferences::GetBool(prefName))); +- break; +- case PrefType::Int: +- intPrefs.Append( +- nsPrintfCString("%u:%d|", i, Preferences::GetInt(prefName))); +- break; +- case PrefType::String: { +- nsAutoCString value; +- Preferences::GetCString(prefName, value); +- stringPrefs.Append( +- nsPrintfCString("%u:%d;%s|", i, value.Length(), value.get())); +- } break; +- case PrefType::None: +- break; +- default: +- printf_stderr("preference type: %d\n", int(pref->Type())); +- MOZ_CRASH(); ++ for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { ++ Pref* pref = static_cast(iter.Get())->mPref; ++ if (pref->MustSendToContentProcesses() && pref->HasAdvisablySizedValues()) { ++ pref->SerializeAndAppend(aStr); + } + } + +- aStr.Truncate(); +- aStr.Append(boolPrefs); +- aStr.Append('\n'); +- aStr.Append(intPrefs); +- aStr.Append('\n'); +- aStr.Append(stringPrefs); +- aStr.Append('\n'); + aStr.Append('\0'); + } + + /* static */ void +-Preferences::DeserializeEarlyPreferences(char* aStr, size_t aStrLen) ++Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) + { + MOZ_ASSERT(!XRE_IsParentProcess()); + +- MOZ_ASSERT(!gEarlyDomPrefs); +- gEarlyDomPrefs = new InfallibleTArray(); ++ MOZ_ASSERT(!gChangedDomPrefs); ++ gChangedDomPrefs = new InfallibleTArray(); + + char* p = aStr; +- +- // XXX: we assume these pref values are default values, which may not be +- // true. We also assume they are unlocked. Fortunately, these prefs get reset +- // properly by the first IPC message. +- +- // Get the bool prefs. +- while (*p != '\n') { +- int32_t index = strtol(p, &p, 10); +- MOZ_ASSERT(p[0] == ':'); +- p++; +- int v = strtol(p, &p, 10); +- MOZ_ASSERT(v == 0 || v == 1); +- dom::MaybePrefValue value(dom::PrefValue(!!v)); +- MOZ_ASSERT(p[0] == '|'); +- p++; +- dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)), +- /* isLocked */ false, +- value, +- dom::MaybePrefValue()); +- gEarlyDomPrefs->AppendElement(pref); +- } +- p++; +- +- // Get the int prefs. +- while (*p != '\n') { +- int32_t index = strtol(p, &p, 10); +- MOZ_ASSERT(p[0] == ':'); +- p++; +- dom::MaybePrefValue value( +- dom::PrefValue(static_cast(strtol(p, &p, 10)))); +- MOZ_ASSERT(p[0] == '|'); +- p++; +- dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)), +- /* isLocked */ false, +- value, +- dom::MaybePrefValue()); +- gEarlyDomPrefs->AppendElement(pref); +- } +- p++; +- +- // Get the string prefs. +- while (*p != '\n') { +- int32_t index = strtol(p, &p, 10); +- MOZ_ASSERT(p[0] == ':'); +- p++; +- int32_t length = strtol(p, &p, 10); +- MOZ_ASSERT(p[0] == ';'); +- p++; +- dom::MaybePrefValue value(dom::PrefValue(nsCString(p, length))); +- dom::Pref pref(nsCString(dom::ContentPrefs::GetEarlyPref(index)), +- /* isLocked */ false, +- value, +- dom::MaybePrefValue()); +- gEarlyDomPrefs->AppendElement(pref); +- p += length + 1; +- MOZ_ASSERT(*(p - 1) == '|'); +- } +- p++; +- +- MOZ_ASSERT(*p == '\0'); ++ while (*p != '\0') { ++ dom::Pref pref; ++ p = Pref::Deserialize(p, &pref); ++ gChangedDomPrefs->AppendElement(pref); ++ } + + // We finished parsing on a '\0'. That should be the last char in the shared +- // memory. +- MOZ_ASSERT(aStr + aStrLen - 1 == p); +- +-#ifdef DEBUG +- MOZ_ASSERT(gPhase == ContentProcessPhase::eNoPrefsSet); +- gPhase = ContentProcessPhase::eEarlyPrefsSet; +-#endif +-} +- +-/* static */ void +-Preferences::SetLatePreferences(const nsTArray* aDomPrefs) +-{ +- MOZ_ASSERT(!XRE_IsParentProcess()); +- +- for (unsigned int i = 0; i < aDomPrefs->Length(); i++) { +- Preferences::SetPreference(aDomPrefs->ElementAt(i)); +- } ++ // memory. (aPrefsLen includes the '\0'.) ++ MOZ_ASSERT(p == aStr + aPrefsLen - 1); + + #ifdef DEBUG +- MOZ_ASSERT(gPhase == ContentProcessPhase::eEarlyPrefsSet); +- gPhase = ContentProcessPhase::eEarlyAndLatePrefsSet; ++ MOZ_ASSERT(!gContentProcessPrefsAreInited); ++ gContentProcessPrefsAreInited = true; + #endif + } + +@@ -3558,36 +3638,12 @@ Preferences::GetPreference(dom::Pref* aDomPref) + } + } + +-void +-Preferences::GetPreferences(InfallibleTArray* aDomPrefs) +-{ +- MOZ_ASSERT(XRE_IsParentProcess()); +- MOZ_ASSERT(NS_IsMainThread()); +- +- aDomPrefs->SetCapacity(gHashTable->EntryCount()); +- for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { +- Pref* pref = static_cast(iter.Get())->mPref; +- +- if (!pref->MustSendToContentProcesses()) { +- // The pref value hasn't changed since it was initialized at startup. +- // Don't bother sending it, because the content process will initialize +- // it the same way. +- continue; +- } +- +- if (pref->HasAdvisablySizedValues()) { +- dom::Pref* setting = aDomPrefs->AppendElement(); +- pref->ToDomPref(setting); +- } +- } +-} +- + #ifdef DEBUG + bool +-Preferences::AreAllPrefsSetInContentProcess() ++Preferences::ArePrefsInitedInContentProcess() + { + MOZ_ASSERT(!XRE_IsParentProcess()); +- return gPhase == ContentProcessPhase::eEarlyAndLatePrefsSet; ++ return gContentProcessPrefsAreInited; + } + #endif + +diff --git modules/libpref/Preferences.h modules/libpref/Preferences.h +index 0d976483daae..901425b5b663 100644 +--- modules/libpref/Preferences.h ++++ modules/libpref/Preferences.h +@@ -328,15 +328,10 @@ public: + const char* aPref, + float aDefault = 0.0f); + +- // When a content process is created these methods are used to pass prefs in +- // bulk from the parent process. "Early" preferences are ones that are needed +- // very early on in the content process's lifetime; they are passed via a +- // special shared memory segment. "Late" preferences are the remainder, which +- // are passed via a standard IPC message. +- static void SerializeEarlyPreferences(nsCString& aStr); +- static void DeserializeEarlyPreferences(char* aStr, size_t aStrLen); +- static void GetPreferences(InfallibleTArray* aSettings); +- static void SetLatePreferences(const nsTArray* aSettings); ++ // When a content process is created these methods are used to pass changed ++ // prefs in bulk from the parent process, via shared memory. ++ static void SerializePreferences(nsCString& aStr); ++ static void DeserializePreferences(char* aStr, size_t aPrefsLen); + + // When a single pref is changed in the parent process, these methods are + // used to pass the update to content processes. +@@ -344,7 +339,7 @@ public: + static void SetPreference(const dom::Pref& aPref); + + #ifdef DEBUG +- static bool AreAllPrefsSetInContentProcess(); ++ static bool ArePrefsInitedInContentProcess(); + #endif + + static void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, Index: head/mail/thunderbird/files/patch-z-bug517422 =================================================================== --- head/mail/thunderbird/files/patch-z-bug517422 +++ head/mail/thunderbird/files/patch-z-bug517422 @@ -0,0 +1,496 @@ +# Allow more config/external/ libs built against system-wide version. + +diff --git build/moz.configure/old.configure build/moz.configure/old.configure +index d0fe7accffe6..c46bdd023225 100644 +--- build/moz.configure/old.configure ++++ build/moz.configure/old.configure +@@ -285,7 +285,12 @@ def old_configure_options(*options): + '--with-system-libvpx', + '--with-system-nspr', + '--with-system-nss', ++ '--with-system-ogg', + '--with-system-png', ++ '--with-system-soundtouch', ++ '--with-system-theora', ++ '--with-system-tremor', ++ '--with-system-vorbis', + '--with-system-zlib', + '--with-thumb', + '--with-thumb-interwork', +diff --git config/external/moz.build config/external/moz.build +index 029ff8504795..2c3a40caa1ba 100644 +--- config/external/moz.build ++++ config/external/moz.build +@@ -23,12 +23,21 @@ external_dirs += ['modules/woff2'] + + external_dirs += ['modules/xz-embedded'] + +-if CONFIG['MOZ_VORBIS']: ++if not CONFIG['MOZ_SYSTEM_OGG']: ++ external_dirs += ['media/libogg'] ++ ++if CONFIG['MOZ_VORBIS'] and not CONFIG['MOZ_SYSTEM_VORBIS']: + external_dirs += ['media/libvorbis'] + +-if CONFIG['MOZ_TREMOR']: ++if CONFIG['MOZ_TREMOR'] and not CONFIG['MOZ_SYSTEM_TREMOR']: + external_dirs += ['media/libtremor'] + ++if not CONFIG['MOZ_SYSTEM_THEORA']: ++ external_dirs += ['media/libtheora'] ++ ++if not CONFIG['MOZ_SYSTEM_SOUNDTOUCH']: ++ external_dirs += ['media/libsoundtouch'] ++ + if CONFIG['MOZ_WEBM_ENCODER']: + external_dirs += ['media/libmkv'] + +@@ -51,11 +60,8 @@ external_dirs += [ + 'media/kiss_fft', + 'media/libcubeb', + 'media/libnestegg', +- 'media/libogg', + 'media/libopus', +- 'media/libtheora', + 'media/libspeex_resampler', +- 'media/libsoundtouch', + 'media/mp4parse-rust', + 'media/psshparser' + ] +diff --git config/system-headers.mozbuild config/system-headers.mozbuild +index 09d3db5ca8c0..c6533b84c470 100644 +--- config/system-headers.mozbuild ++++ config/system-headers.mozbuild +@@ -1325,6 +1325,28 @@ if CONFIG['MOZ_SYSTEM_HARFBUZZ']: + 'harfbuzz/hb.h', + ] + ++if CONFIG['MOZ_SYSTEM_OGG']: ++ system_headers += [ ++ 'ogg/ogg.h', ++ 'ogg/os_types.h', ++ ] ++ ++if CONFIG['MOZ_SYSTEM_THEORA']: ++ system_headers += [ ++ 'theora/theoradec.h', ++ ] ++ ++if CONFIG['MOZ_SYSTEM_VORBIS']: ++ system_headers += [ ++ 'vorbis/codec.h', ++ 'vorbis/vorbisenc.h', ++ ] ++ ++if CONFIG['MOZ_SYSTEM_TREMOR']: ++ system_headers += [ ++ 'tremor/ivorbiscodec.h', ++ ] ++ + if CONFIG['MOZ_SYSTEM_LIBVPX']: + system_headers += [ + 'vpx_mem/vpx_mem.h', +diff --git dom/media/AudioStream.cpp dom/media/AudioStream.cpp +index 93ecda4319af..ff674c64ea07 100644 +--- dom/media/AudioStream.cpp ++++ dom/media/AudioStream.cpp +@@ -121,7 +121,9 @@ AudioStream::AudioStream(DataSource& aSource) + : mMonitor("AudioStream") + , mChannels(0) + , mOutChannels(0) ++#ifndef MOZ_SYSTEM_SOUNDTOUCH + , mTimeStretcher(nullptr) ++#endif + , mDumpFile(nullptr) + , mState(INITIALIZED) + , mDataSource(aSource) +@@ -142,9 +144,11 @@ AudioStream::~AudioStream() + if (mDumpFile) { + fclose(mDumpFile); + } ++#ifndef MOZ_SYSTEM_SOUNDTOUCH + if (mTimeStretcher) { + soundtouch::destroySoundTouchObj(mTimeStretcher); + } ++#endif + #if defined(XP_WIN) + if (XRE_IsContentProcess()) { + audio::AudioNotificationReceiver::Unregister(this); +@@ -168,7 +172,11 @@ nsresult AudioStream::EnsureTimeStretcherInitializedUnlocked() + { + mMonitor.AssertCurrentThreadOwns(); + if (!mTimeStretcher) { ++#ifdef MOZ_SYSTEM_SOUNDTOUCH ++ mTimeStretcher = new soundtouch::SoundTouch(); ++#else + mTimeStretcher = soundtouch::createSoundTouchObj(); ++#endif + mTimeStretcher->setSampleRate(mAudioClock.GetInputRate()); + mTimeStretcher->setChannels(mOutChannels); + mTimeStretcher->setPitch(1.0); +diff --git dom/media/AudioStream.h dom/media/AudioStream.h +index 7dc1f60f95cc..67d402a4117f 100644 +--- dom/media/AudioStream.h ++++ dom/media/AudioStream.h +@@ -15,7 +15,11 @@ + #include "mozilla/TimeStamp.h" + #include "mozilla/UniquePtr.h" + #include "CubebUtils.h" ++#ifdef MOZ_SYSTEM_SOUNDTOUCH ++#include "soundtouch/SoundTouch.h" ++#else + #include "soundtouch/SoundTouchFactory.h" ++#endif + + #if defined(XP_WIN) + #include "mozilla/audio/AudioNotificationReceiver.h" +@@ -297,7 +301,11 @@ private: + uint32_t mChannels; + uint32_t mOutChannels; + AudioClock mAudioClock; ++#ifdef MOZ_SYSTEM_SOUNDTOUCH ++ nsAutoPtr mTimeStretcher; ++#else + soundtouch::SoundTouch* mTimeStretcher; ++#endif + + // Output file for dumping audio + FILE* mDumpFile; +diff --git dom/media/moz.build dom/media/moz.build +index 86b051c58d33..fb6186dce78b 100644 +--- dom/media/moz.build ++++ dom/media/moz.build +@@ -326,6 +326,21 @@ if CONFIG['MOZ_WEBRTC']: + + DEFINES['MOZILLA_INTERNAL_API'] = True + ++if CONFIG['MOZ_SYSTEM_OGG']: ++ CXXFLAGS += CONFIG['MOZ_OGG_CFLAGS'] ++ ++if CONFIG['MOZ_SYSTEM_THEORA']: ++ CXXFLAGS += CONFIG['MOZ_THEORA_CFLAGS'] ++ ++if CONFIG['MOZ_SYSTEM_VORBIS']: ++ CXXFLAGS += CONFIG['MOZ_VORBIS_CFLAGS'] ++ ++if CONFIG['MOZ_SYSTEM_TREMOR']: ++ CXXFLAGS += CONFIG['MOZ_TREMOR_CFLAGS'] ++ ++if CONFIG['MOZ_SYSTEM_SOUNDTOUCH']: ++ CXXFLAGS += CONFIG['MOZ_SOUNDTOUCH_CFLAGS'] ++ + if CONFIG['MOZ_ANDROID_HLS_SUPPORT']: + DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True + +diff --git dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp +index 078f6ea5ef60..c600db067539 100644 +--- dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp ++++ dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp +@@ -15,9 +15,13 @@ + #include + #endif + ++#ifdef MOZ_SYSTEM_SOUNDTOUCH ++#include "nsXPCOMPrivate.h" // for XUL_DLL ++#else + // We use a known symbol located in lgpllibs to determine its location. + // soundtouch happens to be always included in lgpllibs + #include "soundtouch/SoundTouch.h" ++#endif + + namespace mozilla { + +@@ -64,6 +68,12 @@ FFVPXRuntimeLinker::Init() + + sLinkStatus = LinkStatus_FAILED; + ++#ifdef MOZ_SYSTEM_SOUNDTOUCH ++ // We retrieve the path of the XUL library as this is where mozavcodec and ++ // mozavutil libs are located. ++ char* path = ++ PR_GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Init); ++#else + // We retrieve the path of the lgpllibs library as this is where mozavcodec + // and mozavutil libs are located. + PathString lgpllibsname = GetLibraryName(nullptr, "lgpllibs"); +@@ -73,6 +83,7 @@ FFVPXRuntimeLinker::Init() + PathString path = + GetLibraryFilePathname(lgpllibsname.get(), + (PRFuncPtr)&soundtouch::SoundTouch::getVersionId); ++#endif + if (path.IsEmpty()) { + return false; + } +diff --git media/libogg/README_MOZILLA media/libogg/README_MOZILLA +index 6213fdc7770c..ada799916a17 100644 +--- media/libogg/README_MOZILLA ++++ media/libogg/README_MOZILLA +@@ -6,3 +6,6 @@ package downloaded from xiph.org and copied using the update.sh script. + The int-types.patch address a bug that config_types.h generated from + Linux platform can't be used on OpenSolaris directly see Mozilla bug + 449754 ++ ++The in-tree copy may be omitted during build by --with-system-ogg. ++Keep version in old-configure.in in sync on updates. +diff --git media/libsoundtouch/README_MOZILLA media/libsoundtouch/README_MOZILLA +index dc0dbe8f6886..ea73b55e3e39 100644 +--- media/libsoundtouch/README_MOZILLA ++++ media/libsoundtouch/README_MOZILLA +@@ -6,3 +6,5 @@ The whole library is not used, only the relevant files are imported in the tree, + using the script `update.sh`. Some changes have been made to the files, using + the patch `moz-libsoundtouch.patch`. We also use a custom soundtouch_config.h. + ++The in-tree copy may be omitted during build by --with-system-soundtouch. ++Keep version in old-configure.in in sync on updates. +diff --git media/libsoundtouch/src/soundtouch_perms.h media/libsoundtouch/src/soundtouch_perms.h +index 0af2fe618311..10973564e7a4 100644 +--- media/libsoundtouch/src/soundtouch_perms.h ++++ media/libsoundtouch/src/soundtouch_perms.h +@@ -12,7 +12,9 @@ + + #pragma GCC visibility push(default) + #include "SoundTouch.h" ++#ifndef MOZ_SYSTEM_SOUNDTOUCH + #include "SoundTouchFactory.h" ++#endif + #pragma GCC visibility pop + + #endif // MOZILLA_SOUNDTOUCH_PERMS_H +diff --git media/libtheora/README_MOZILLA media/libtheora/README_MOZILLA +index d48dbfa6f63d..6f30f250220e 100644 +--- media/libtheora/README_MOZILLA ++++ media/libtheora/README_MOZILLA +@@ -3,3 +3,6 @@ using the update.sh script. The changes made were those applied by update.sh, + the addition/update of Makefile.in files for the Mozilla build system. + + The subversion revision used was r17578. ++ ++The in-tree copy may be omitted during build by --with-system-theora. ++Keep version in old-configure.in in sync on updates. +diff --git media/libtheora/moz.build media/libtheora/moz.build +index c7f85eebff95..aae7b814adb5 100644 +--- media/libtheora/moz.build ++++ media/libtheora/moz.build +@@ -21,6 +21,9 @@ FINAL_LIBRARY = 'gkmedias' + # The encoder is currently not included. + DEFINES['THEORA_DISABLE_ENCODE'] = True + ++if CONFIG['MOZ_SYSTEM_OGG']: ++ CFLAGS += CONFIG['MOZ_OGG_CFLAGS'] ++ + # Suppress warnings in third-party code. + if CONFIG['CC_TYPE'] in ('clang', 'clang-cl', 'gcc'): + CFLAGS += ['-Wno-type-limits'] +diff --git media/libtremor/README_MOZILLA media/libtremor/README_MOZILLA +index ee67b53a05c5..81c971773d55 100644 +--- media/libtremor/README_MOZILLA ++++ media/libtremor/README_MOZILLA +@@ -5,3 +5,6 @@ Makefile.in files for the Mozilla build system. + + The upstream release used was http://svn.xiph.org/trunk/Tremor/ + The subversion revision used was r17547. ++ ++The in-tree copy may be omitted during build by --with-system-tremor. ++Keep version in old-configure.in in sync on updates. +diff --git media/libtremor/moz.build media/libtremor/moz.build +index 83afc8e37c64..71ef159da3d7 100644 +--- media/libtremor/moz.build ++++ media/libtremor/moz.build +@@ -9,3 +9,5 @@ with Files('*'): + + DIRS += ['include/tremor', 'lib'] + ++if CONFIG['MOZ_SYSTEM_OGG']: ++ CFLAGS += CONFIG['MOZ_OGG_CFLAGS'] +diff --git media/libvorbis/README_MOZILLA media/libvorbis/README_MOZILLA +index 1211ac074b33..eb31084aed25 100644 +--- media/libvorbis/README_MOZILLA ++++ media/libvorbis/README_MOZILLA +@@ -8,3 +8,6 @@ from https://git.xiph.org/vorbis.git + + Some files are renamed during the copy to prevent clashes with object + file names with other Mozilla libraries. ++ ++The in-tree copy may be omitted during build by --with-system-vorbis. ++Keep version in old-configure.in in sync on updates. +diff --git media/libvorbis/moz.build media/libvorbis/moz.build +index adf393782cc9..923b76231107 100644 +--- media/libvorbis/moz.build ++++ media/libvorbis/moz.build +@@ -56,3 +56,6 @@ FINAL_LIBRARY = 'gkmedias' + # Suppress warnings in third-party code. + if CONFIG['CC_TYPE'] in ('clang', 'gcc'): + CFLAGS += ['-Wno-uninitialized'] ++ ++if CONFIG['MOZ_SYSTEM_OGG']: ++ CFLAGS += CONFIG['MOZ_OGG_CFLAGS'] +diff --git old-configure.in old-configure.in +index b614eef85c89..85f9099dba4d 100644 +--- old-configure.in ++++ old-configure.in +@@ -2627,6 +2627,111 @@ if test -n "$MOZ_APPLEMEDIA"; then + fi + fi # COMPILE_ENVIRONMENT + ++dnl ======================================================== ++dnl Check for libogg ++dnl ======================================================== ++ ++MOZ_ARG_WITH_BOOL(system-ogg, ++[ --with-system-ogg Use system libogg (located with pkgconfig)], ++MOZ_SYSTEM_OGG=1, ++MOZ_SYSTEM_OGG=) ++ ++if test -n "$MOZ_SYSTEM_OGG"; then ++ PKG_CHECK_MODULES(MOZ_OGG, ogg >= 1.3.3) ++ ++ _SAVE_LIBS=$LIBS ++ LIBS="$LIBS $MOZ_OGG_LIBS" ++ AC_CHECK_FUNC(ogg_set_mem_functions, [], ++ [AC_DEFINE(MOZ_OGG_NO_MEM_REPORTING)]) ++ LIBS=$_SAVE_LIBS ++fi ++ ++AC_SUBST(MOZ_SYSTEM_OGG) ++ ++dnl ======================================================== ++dnl Check for libvorbis ++dnl ======================================================== ++ ++MOZ_ARG_WITH_BOOL(system-vorbis, ++[ --with-system-vorbis Use system libvorbis (located with pkgconfig)], ++MOZ_SYSTEM_VORBIS=1, ++MOZ_SYSTEM_VORBIS=) ++ ++if test -n "$MOZ_SYSTEM_VORBIS"; then ++ PKG_CHECK_MODULES(MOZ_VORBIS, vorbis vorbisenc >= 1.3.6) ++fi ++ ++AC_SUBST(MOZ_SYSTEM_VORBIS) ++ ++dnl ======================================================== ++dnl Check for integer-only libvorbis aka tremor ++dnl ======================================================== ++ ++MOZ_ARG_WITH_BOOL(system-tremor, ++[ --with-system-tremor Use system libtremor (located with pkgconfig)], ++MOZ_SYSTEM_TREMOR=1, ++MOZ_SYSTEM_TREMOR=) ++ ++if test -n "$MOZ_SYSTEM_TREMOR"; then ++ PKG_CHECK_MODULES(MOZ_TREMOR, vorbisidec >= 1.2.1) ++fi ++ ++AC_SUBST(MOZ_SYSTEM_TREMOR) ++ ++dnl ======================================================== ++dnl Check for libtheora ++dnl ======================================================== ++ ++MOZ_ARG_WITH_BOOL(system-theora, ++[ --with-system-theora Use system libtheora (located with pkgconfig)], ++MOZ_SYSTEM_THEORA=1, ++MOZ_SYSTEM_THEORA=) ++ ++if test -n "$MOZ_SYSTEM_THEORA"; then ++ PKG_CHECK_MODULES(MOZ_THEORA, theora >= 1.2) ++fi ++ ++AC_SUBST(MOZ_SYSTEM_THEORA) ++ ++dnl ======================================================== ++dnl Check for libSoundTouch ++dnl ======================================================== ++ ++MOZ_ARG_WITH_BOOL(system-soundtouch, ++[ --with-system-soundtouch Use system libSoundTouch (located with pkgconfig)], ++MOZ_SYSTEM_SOUNDTOUCH=1, ++MOZ_SYSTEM_SOUNDTOUCH=) ++ ++if test -n "$MOZ_SYSTEM_SOUNDTOUCH"; then ++ PKG_CHECK_MODULES(MOZ_SOUNDTOUCH, soundtouch >= 1.9.0) ++ ++ AC_LANG_SAVE ++ AC_LANG_CPLUSPLUS ++ _SAVE_CXXFLAGS=$CXXFLAGS ++ CXXFLAGS="$CXXFLAGS $MOZ_SOUNDTOUCH_CFLAGS" ++ AC_CACHE_CHECK(for soundtouch sample type, ++ ac_cv_soundtouch_sample_type, ++ [AC_TRY_COMPILE([#include ++ #ifndef SOUNDTOUCH_INTEGER_SAMPLES ++ #error soundtouch expects float samples ++ #endif], ++ [], ++ [ac_cv_soundtouch_sample_type=short], ++ [ac_cv_soundtouch_sample_type=float])]) ++ CXXFLAGS=$_SAVE_CXXFLAGS ++ AC_LANG_RESTORE ++ ++ if test \( -n "$MOZ_SAMPLE_TYPE_S16" -a "$ac_cv_soundtouch_sample_type" != short \) \ ++ -o \( -n "$MOZ_SAMPLE_TYPE_FLOAT32" -a "$ac_cv_soundtouch_sample_type" != float \) ; then ++ AC_MSG_ERROR([SoundTouch library is built with incompatible sample type. Either rebuild the library with/without --enable-integer-samples, chase default Mozilla sample type or remove --with-system-soundtouch.]) ++ fi ++fi ++ ++if test -n "$MOZ_SYSTEM_SOUNDTOUCH"; then ++ AC_DEFINE(MOZ_SYSTEM_SOUNDTOUCH) ++fi ++AC_SUBST(MOZ_SYSTEM_SOUNDTOUCH) ++ + dnl system libvpx Support + dnl ======================================================== + MOZ_ARG_WITH_BOOL(system-libvpx, +diff --git toolkit/library/moz.build toolkit/library/moz.build +index 079a575adec3..514d901195de 100644 +--- toolkit/library/moz.build ++++ toolkit/library/moz.build +@@ -240,6 +240,21 @@ if CONFIG['MOZ_SYSTEM_HARFBUZZ']: + if CONFIG['MOZ_SYSTEM_HUNSPELL']: + OS_LIBS += CONFIG['MOZ_HUNSPELL_LIBS'] + ++if CONFIG['MOZ_SYSTEM_OGG']: ++ OS_LIBS += CONFIG['MOZ_OGG_LIBS'] ++ ++if CONFIG['MOZ_SYSTEM_THEORA']: ++ OS_LIBS += CONFIG['MOZ_THEORA_LIBS'] ++ ++if CONFIG['MOZ_SYSTEM_VORBIS']: ++ OS_LIBS += CONFIG['MOZ_VORBIS_LIBS'] ++ ++if CONFIG['MOZ_SYSTEM_TREMOR']: ++ OS_LIBS += CONFIG['MOZ_TREMOR_LIBS'] ++ ++if CONFIG['MOZ_SYSTEM_SOUNDTOUCH']: ++ OS_LIBS += CONFIG['MOZ_SOUNDTOUCH_LIBS'] ++ + if CONFIG['MOZ_SYSTEM_LIBEVENT']: + OS_LIBS += CONFIG['MOZ_LIBEVENT_LIBS'] + +diff --git xpcom/build/XPCOMInit.cpp xpcom/build/XPCOMInit.cpp +index c083ab4bc4f3..62b917043a2c 100644 +--- xpcom/build/XPCOMInit.cpp ++++ xpcom/build/XPCOMInit.cpp +@@ -132,7 +132,9 @@ extern nsresult nsStringInputStreamConstructor(nsISupports*, REFNSIID, void**); + + #include "mozilla/ipc/GeckoChildProcessHost.h" + ++#ifndef MOZ_OGG_NO_MEM_REPORTING + #include "ogg/ogg.h" ++#endif + #if defined(MOZ_VPX) && !defined(MOZ_VPX_NO_MEM_REPORTING) + #if defined(HAVE_STDINT_H) + // mozilla-config.h defines HAVE_STDINT_H, and then it's defined *again* in +@@ -639,11 +641,13 @@ NS_InitXPCOM2(nsIServiceManager** aResult, + // this oddness. + mozilla::SetICUMemoryFunctions(); + ++#ifndef MOZ_OGG_NO_MEM_REPORTING + // Do the same for libogg. + ogg_set_mem_functions(OggReporter::CountingMalloc, + OggReporter::CountingCalloc, + OggReporter::CountingRealloc, + OggReporter::CountingFree); ++#endif + + #if defined(MOZ_VPX) && !defined(MOZ_VPX_NO_MEM_REPORTING) + // And for VPX. Index: head/mail/thunderbird/files/thunderbird.desktop.in =================================================================== --- head/mail/thunderbird/files/thunderbird.desktop.in +++ head/mail/thunderbird/files/thunderbird.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Thunderbird +GenericName=Mail Client +Comment=Mail client and News Reader +Exec=@MOZILLA@ %u +Icon=@PORTNAME_ICON@ +StartupNotify=true +Terminal=false +Type=Application +Categories=Network;Email;News;InstantMessaging;