diff --git a/API.md b/API.md index 4a9ed552..b77ef9f8 100644 --- a/API.md +++ b/API.md @@ -35,6 +35,7 @@ contract development. * [\.decodeFunctionParams()](#tvmslicedecodefunctionparams) * [\.decodeStateVars()](#tvmslicedecodestatevars) * [\.skip()](#tvmsliceskip) + * [\.loadZeroes(), \.loadOnes() and \.loadSame()](#tvmsliceloadzeroes-tvmsliceloadones-and-tvmsliceloadsame) * [TvmBuilder](#tvmbuilder) * [\.toSlice()](#tvmbuildertoslice) * [\.toCell()](#tvmbuildertocell) @@ -46,8 +47,7 @@ contract development. * [\.remBitsAndRefs()](#tvmbuilderrembitsandrefs) * [\.depth()](#tvmbuilderdepth) * [\.store()](#tvmbuilderstore) - * [\.storeOnes()](#tvmbuilderstoreones) - * [\.storeZeroes()](#tvmbuilderstorezeroes) + * [\.storeZeroes(), \.storeOnes() and \.storeSame()](#tvmbuilderstorezeroes-tvmbuilderstoreones-and-tvmbuilderstoresame) * [\.storeSigned()](#tvmbuilderstoresigned) * [\.storeUnsigned()](#tvmbuilderstoreunsigned) * [\.storeRef()](#tvmbuilderstoreref) @@ -251,6 +251,7 @@ contract development. * [tx.storageFee](#txstoragefee) * [**block** namespace](#block-namespace) * [block.timestamp](#blocktimestamp) + * [block.logicaltime](#blocklogicaltime) * [**rnd** namespace](#rnd-namespace) * [rnd.next](#rndnext) * [rnd.getSeed](#rndgetseed) @@ -646,6 +647,24 @@ contract B { Skips the first `length` bits and `refs` references from the `TvmSlice`. +###### \.loadZeroes(), \.loadOnes() and \.loadSame() + +```TVMSolidity +(1) +.loadZeroes() returns (uint10 n); +(2) +.loadOnes() returns (uint10 n); +(3) +.loadSame(uint1 value) returns (uint10 n); +``` + +(1) Returns the count `n` of leading zero bits in `TvmSlice`, and removes these bits from `TvmSlice`. + +(2) Returns the count `n` of leading one bits in `TvmSlice`, and removes these bits from `TvmSlice`. + +(3) Returns the count `n` of leading bits equal to `0 ≤ value ≤ 1` in `TvmSlice`, and removes these bits from `TvmSlice`. + + #### TvmBuilder `TvmBuilder` represents *TVM cell builder* ([TVM][1] - 1.1.3). TON Solidity compiler defines the following @@ -769,21 +788,19 @@ builder.store(a, b, uint(33)); See also: [\.decode()](#tvmslicedecode). -##### \.storeOnes() +##### \.storeZeroes(), \.storeOnes() and \.storeSame() ```TVMSolidity -.storeOnes(uint n); +.storeZeroes(uint10 n); +.storeOnes(uint10 n); +.storeSame(uint10 n, uint1 value); ``` -Stores `n` binary ones into the `TvmBuilder`. +(1) Stores `n` binary zeroes into the `TvmBuilder`. -##### \.storeZeroes() +(2) Stores `n` binary ones into the `TvmBuilder`. -```TVMSolidity -.storeZeroes(uint n); -``` - -Stores `n` binary zeroes into the `TvmBuilder`. +(3) Stores `n` binary `value`s (0 ≤ value ≤ 1) into the `TvmBuilder`. ##### \.storeSigned() @@ -4198,7 +4215,15 @@ Returns the storage fee paid in the current transaction. ##### block.timestamp ```TVMSolidity -block.timestamp returns (uint64); +block.timestamp returns (uint32); +``` + +Returns the current Unix time. Unix time is the same for the all transactions from one block. + +##### block.logicaltime + +```TVMSolidity +block.logicaltime returns (uint64); ``` Returns the starting logical time of the current block. diff --git a/Cargo.lock b/Cargo.lock index 7949294d..608064d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,38 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes-ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" +dependencies = [ + "aes-soft", + "aesni", + "cipher", + "ctr", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -44,17 +76,60 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + [[package]] name = "anstyle" -version = "0.3.1" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c697cc33851b02ab0c26b2e8a211684fbe627ff1cc506131f35026dd7686dd" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +dependencies = [ + "anstyle", + "windows-sys", +] [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -64,14 +139,14 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "assert_cmd" -version = "2.0.9" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0dcbed38184f9219183fcf38beb4cdbf5df7163a6d7cd227c6ac89b7966d6fe" +checksum = "86d6b683edf8d1119fe420a94f8a7e389239666aa72e65495d91c00462510151" dependencies = [ "anstyle", - "bstr 1.3.0", + "bstr 1.4.0", "doc-comment", - "predicates 3.0.1", + "predicates", "predicates-core", "predicates-tree", "wait-timeout", @@ -170,9 +245,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ "memchr", "once_cell", @@ -180,12 +255,6 @@ dependencies = [ "serde", ] -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - [[package]] name = "bumpalo" version = "3.12.0" @@ -228,6 +297,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + [[package]] name = "clap" version = "2.34.0" @@ -245,46 +323,51 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.8" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +checksum = "49f9152d70e42172fdb87de2efd7327160beee37886027cf86f30a233d5b30b4" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e067b220911598876eb55d52725ddcc201ffe3f0904018195973bc5b012ea2ca" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim 0.10.0", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.8" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] name = "clap_lex" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "cmake" -version = "0.1.49" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] @@ -299,6 +382,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -307,28 +396,19 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -dependencies = [ - "build_const", -] - [[package]] name = "crc" version = "3.0.1" @@ -363,6 +443,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" version = "3.2.1" @@ -378,9 +467,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" dependencies = [ "cc", "cxxbridge-flags", @@ -390,9 +479,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" dependencies = [ "cc", "codespan-reporting", @@ -400,24 +489,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 2.0.15", ] [[package]] name = "cxxbridge-flags" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" [[package]] name = "cxxbridge-macro" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -508,13 +597,13 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys", ] [[package]] @@ -545,7 +634,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] @@ -560,9 +649,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -581,9 +670,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -631,16 +720,16 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows", ] [[package]] @@ -655,19 +744,20 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ + "hermit-abi 0.3.1", "libc", "windows-sys", ] [[package]] name = "is-terminal" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", @@ -716,9 +806,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "link-cplusplus" @@ -731,9 +821,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "3f508063cc7bb32987c71511216bd5a32be15bccb6a80b52df8b9d7f01fc3aa2" [[package]] name = "lockfree" @@ -815,7 +905,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -881,12 +971,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "owned-alloc" version = "0.2.0" @@ -907,10 +991,11 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "predicates" -version = "2.1.5" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" dependencies = [ + "anstyle", "difflib", "float-cmp", "itertools", @@ -919,18 +1004,6 @@ dependencies = [ "regex", ] -[[package]] -name = "predicates" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba7d6ead3e3966038f68caa9fc1f860185d95a793180bbcfe0d0da47b3961ed" -dependencies = [ - "anstyle", - "difflib", - "itertools", - "predicates-core", -] - [[package]] name = "predicates-core" version = "1.0.6" @@ -947,35 +1020,11 @@ dependencies = [ "termtree", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1048,7 +1097,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.9", ] [[package]] @@ -1079,9 +1128,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -1096,9 +1145,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "rust-argon2" @@ -1114,15 +1163,15 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.36.9" +version = "0.37.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "722529a737f5a942fdbac3a46cee213053196737c5eaa3386d52e85b786f2659" dependencies = [ "bitflags", "errno", @@ -1146,29 +1195,29 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.156" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -1216,9 +1265,9 @@ dependencies = [ [[package]] name = "simplelog" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e95345f185d5adeb8ec93459d2dc99654e294cc6ccf5b75414d8ea262de9a13" +checksum = "aa9c948a5a26cd38340ddbeaa557a8c8a5ce4442408eb60453bee2bb3c84a3fb" dependencies = [ "chrono", "log", @@ -1233,16 +1282,16 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "sold" -version = "0.67.0" +version = "0.68.0" dependencies = [ "assert_cmd", "atty", - "clap 4.1.8", + "clap 4.2.3", "cmake", "dunce", "failure", "once_cell", - "predicates 2.1.5", + "predicates", "serde", "serde_json", "strip-ansi-escapes", @@ -1290,6 +1339,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -1298,7 +1358,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "unicode-xid", ] @@ -1350,8 +1410,8 @@ dependencies = [ [[package]] name = "ton_abi" -version = "2.3.60" -source = "git+https://github.com/tonlabs/ton-labs-abi.git?tag=2.3.60#2b595a53e0c844c1cd4eaf2faa167de31909dd3c" +version = "2.3.80" +source = "git+https://github.com/tonlabs/ever-abi.git?tag=2.3.80#0c8efc4a4e43212316fd36cd6eec3911b87bf7df" dependencies = [ "base64 0.10.1", "byteorder", @@ -1372,11 +1432,11 @@ dependencies = [ [[package]] name = "ton_block" -version = "1.9.22" -source = "git+https://github.com/tonlabs/ton-labs-block.git?tag=1.9.22#bb1f4af6072e52618bdffcfa7614e8ca6ee6b947" +version = "1.9.43" +source = "git+https://github.com/tonlabs/ever-block.git?tag=1.9.43#a6d20909632b00bf73f0cbbea8d9a11534837f8d" dependencies = [ "base64 0.13.1", - "crc 3.0.1", + "crc", "ed25519", "ed25519-dalek", "failure", @@ -1390,8 +1450,8 @@ dependencies = [ [[package]] name = "ton_labs_assembler" -version = "1.2.77" -source = "git+https://github.com/tonlabs/ton-labs-assembler.git?tag=1.2.77#6257a674457627646237e74ee6eb402f052d214f" +version = "1.2.95" +source = "git+https://github.com/tonlabs/ever-assembler.git?tag=1.2.95#7e8fc6425227f9f0fc55db6e371fdd8fc684257b" dependencies = [ "failure", "hex 0.4.3", @@ -1405,11 +1465,15 @@ dependencies = [ [[package]] name = "ton_types" -version = "1.12.6" -source = "git+https://github.com/tonlabs/ton-labs-types.git?tag=1.12.6#8e218813db6bacc138dbbec7ab4ccbf84220da31" +version = "2.0.2" +source = "git+https://github.com/tonlabs/ever-types.git?tag=2.0.2#7f63474425e0102422e82fd8b18c489851875c14" dependencies = [ + "aes-ctr", "base64 0.13.1", - "crc 1.8.1", + "crc", + "curve25519-dalek", + "ed25519", + "ed25519-dalek", "failure", "hex 0.4.3", "lazy_static", @@ -1418,15 +1482,18 @@ dependencies = [ "num", "num-derive", "num-traits", - "rand 0.8.5", - "sha2 0.9.9", + "rand 0.7.3", + "serde", + "serde_json", + "sha2 0.10.6", "smallvec", + "x25519-dalek", ] [[package]] name = "ton_vm" -version = "1.8.108" -source = "git+https://github.com/tonlabs/ton-labs-vm.git?tag=1.8.108#f61649a6245fc8002a5a20062de75f49b5203652" +version = "1.8.132" +source = "git+https://github.com/tonlabs/ever-vm.git?tag=1.8.132#72b50dc57beaa21a5f62f64d7d03d686e9b1716d" dependencies = [ "diffy", "ed25519", @@ -1447,12 +1514,12 @@ dependencies = [ [[package]] name = "tvm_linker" -version = "0.19.5" -source = "git+https://github.com/tonlabs/TVM-linker.git?tag=0.19.5#5171e981fa892932a8a802f9d2fd937ea6a483a7" +version = "0.20.1" +source = "git+https://github.com/tonlabs/TVM-linker.git?tag=0.20.1#1a49f2a5d6322603bd77df77c35e9f6cf50a4004" dependencies = [ "base64 0.13.1", "clap 2.34.0", - "crc 3.0.1", + "crc", "ed25519", "ed25519-dalek", "failure", @@ -1585,7 +1652,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -1607,7 +1674,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1649,20 +1716,29 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1675,45 +1751,56 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "x25519-dalek" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +dependencies = [ + "curve25519-dalek", + "rand_core 0.5.1", + "zeroize", +] [[package]] name = "zeroize" @@ -1726,14 +1813,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", - "synstructure", + "syn 2.0.15", ] [[package]] @@ -1757,9 +1843,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.7+zstd.1.5.4" +version = "2.0.8+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" dependencies = [ "cc", "libc", diff --git a/Changelog_TON.md b/Changelog_TON.md index 864a69d4..98293490 100644 --- a/Changelog_TON.md +++ b/Changelog_TON.md @@ -1,3 +1,26 @@ +### 0.68.0 (2023-04-19) + +Breaking change: + * `require()` and `revert()` take `uint16` exception code instead of `uint256`. + * `tvm.rawConfigParam(...)` returns `optional(TvmCell)` instead of `(TvmCell, bool)`. + * Exit status of `solc`/`sold` is equal to `0` and it prints `Compiler run successful, no output requested.` if the source contain no deployable contracts. + +Compiler features: + * Supported [free functions](https://docs.soliditylang.org/en/latest/contracts.html#functions). + * Supported `.loadZeroes()`, `.loadOnes()` and `.loadSame()`. + * Supported `.storeSame()`. + +Bugfixes: + * Fixed a problem with lvalue expressions. The problem caused type check error. + * Fixed the bug that caused an exception in decoding the parameters of public function. + * Fixed compilation fail if you use `tvm.functionID(ContractName)` or `externalMsg`/`internalMsg`. + * Fixed bug when AST (`solc --ast-compact-json`) was generated with ignoring options in return statements (`return {value: ..., flag: ..., bounce: ...}(...);`). + * Fixed compilation fail when you have 2 files with the same names in your project. + +sold: + * Supported `--userdoc`/`--devdoc` options. + * `--ast-compact-json` option outputs to stdout now. + ### 0.67.0 (2023-03-16) Update compiler frontend (from original version 0.6.3 to 0.8.17): @@ -16,7 +39,7 @@ Bugfixes: * Support overloading for function `onCodeUpgrade`. Breaking change: - * Function `onCodeUpgrade` had function id = 2. Now, it has another id, but you can set `functionID(2)` in new + * Function `onCodeUpgrade` had function id = 2. Now, it has another id, but you can set `functionID(2)` in new contracts to upgrade old ones. ### 0.65.0 (2022-10-08) @@ -24,14 +47,14 @@ contracts to upgrade old ones. Compiler features: * Supported `delete` and binary operators for `varUintN/varIntN` types. * Supported function references for library function, e.g. `function(int, int) internal returns (int) op = Math.add;` - * Supported `gosh` functions: `applyBinPatch`/`applyBinPatchQ`/`applyZipBinPatch`/`applyZipBinPatchQ`. + * Supported `gosh` functions: `applyBinPatch`/`applyBinPatchQ`/`applyZipBinPatch`/`applyZipBinPatchQ`. * Supported conversion `uint32` to private function, e.g. `function(uint, uint) internal pure returns (uint) fun = uint32(123456)`. * Support command line option `--private-function-ids` for printing private function ids. * Support `pragma upgrade func/oldsol;` to upgrade old contracts. ### 0.64.0 (2022-08-18) -Fixed build [sold](https://github.com/tonlabs/TON-Solidity-Compiler/tree/master/sold) for Windows and macOS. +Fixed build [sold](https://github.com/tonlabs/TON-Solidity-Compiler/tree/master/sold) for Windows and macOS. Compiler features: * Supported [ABI v2.3](https://github.com/tonlabs/ton-labs-abi/blob/master/docs/ABI_2.3_spec.md). @@ -75,7 +98,7 @@ Bugfixes: ### 0.61.1 (2022-06-10) Added `sold` sources. -Fix problem of using `mapping(string => ValueType) map` in loop `for ((uint k, ValueType v) : map)`. +Fix problem of using `mapping(string => ValueType) map` in loop `for ((uint k, ValueType v) : map)`. Use `bytes` instead of `TvmCell` in `gosh` functions. ### 0.61.0 (2022-06-07) @@ -84,7 +107,7 @@ Compiler features: * Supported experimental functions `gosh.diff`, `gosh.applyPatch`, `gosh.applyPatchQ`, `gosh.zip`, `gosh.unzip`, `gosh.zipDiff`, `gosh.applyZipPatch` and `gosh.applyZipPatchQ`. * Supported experimental `tx.storageFee`. - + Gas optimizations: * Use opcode `MYCODE` for Solidity function `tvm.code()`. * Assorted stack optimizations. @@ -111,7 +134,7 @@ Breaking change: explicitly defined. Gas optimizations: - * Peephole optimizations: use `PUSHPOW2`, `PUSHPOW2DEC`, `PUSHNEGPOW2` opcodes instead of + * Peephole optimizations: use `PUSHPOW2`, `PUSHPOW2DEC`, `PUSHNEGPOW2` opcodes instead of `PUSHINT` in same cases. ### 0.59.0 (2022-04-12) @@ -156,7 +179,7 @@ Assorted peephole stack optimizations. ### 0.57.1 (2022-02-04) -Bugfixes: +Bugfixes: * Code optimizer: fix bug that caused swapping some opcodes. ### 0.57.0 (2022-02-01) @@ -220,7 +243,7 @@ Compiler features: * Supported constant arrays, e.g. `uint[] public constant fib = [uint(2), 3, 5, 8, 12, 20, 32];`. Breaking change: - * Changed `stoi()` return type to `optional(int)`. + * Changed `stoi()` return type to `optional(int)`. * Output AST JSON to the file instead of standard output. Gas optimizations: @@ -254,7 +277,7 @@ Breaking change: * Deleted `\.bitsAndRefs()`. Please, use `\.size()`. * Renamed `\.bitsAndRefs()` -> `\.size()`. * Deleted `tvm.deploy()`. Please, use `\.transfer({stateInit: ..., ...})`. - * Changed `TvmSlice`, `TvmCell` and `TvmBuilder` `.depth()` method return type from `uint64` to `uint16`. + * Changed `TvmSlice`, `TvmCell` and `TvmBuilder` `.depth()` method return type from `uint64` to `uint16`. Gas optimizations: * Assorted stack optimizations. @@ -545,7 +568,7 @@ Bug fixes. APIs for common TON-specific functionality: * Supported optional type - * Added methods for optional type: set, hasValue, get + * Added methods for optional type: set, hasValue, get Changed APIs to handle mappings: fetch, min, max, prev, next and ect. diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index f78099a4..b7d45346 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -21,7 +21,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.67.0") +set(PROJECT_VERSION "0.68.0") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/compiler/libsolidity/analysis/TypeChecker.cpp b/compiler/libsolidity/analysis/TypeChecker.cpp index 10fa63a6..c3c6bc52 100644 --- a/compiler/libsolidity/analysis/TypeChecker.cpp +++ b/compiler/libsolidity/analysis/TypeChecker.cpp @@ -761,7 +761,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (_function.externalMsg() && _function.internalMsg()) { m_errorReporter.typeError(228_error, _function.location(), R"("internalMsg" and "externalMsg" cannot be used together.)"); } - if (!_function.isPublic()) { + if (!_function.functionIsExternallyVisible()) { m_errorReporter.typeError(228_error, _function.location(), R"(Private/internal function can't be marked as internalMsg/externalMsg.)"); } if (_function.isReceive() || _function.isFallback() || _function.isOnBounce() || _function.isOnTickTock()) { @@ -2968,16 +2968,6 @@ TypeChecker::checkPubFunctionOrContractTypeAndGetDefinition(Expression const& ar " provided." ); } - if (constructorDef && !constructorDef->isPublic()) { - m_errorReporter.fatalTypeError( - 228_error, - arg.location(), - SecondarySourceLocation().append("Declaration is here:", constructorDef->location()), - "Contract with public constructor required, but \"" + - Declaration::visibilityToString(constructorDef->visibility()) + - "\" constructor provided." - ); - } return constructorDef; } @@ -3471,9 +3461,11 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) TypePointers returnTypes; auto checkArgConversion = [&]() { for (size_t i = 0; i < paramTypes.size(); ++i) { - if (!arguments.at(i)->annotation().type->isImplicitlyConvertibleTo(*paramTypes.at(i))) { - m_errorReporter.typeError(228_error, _functionCall.location(), - "Expected argument of type " + paramTypes.at(i)->canonicalName()); + const Type *givenType = arguments.at(i)->annotation().type; + const Type *expType = paramTypes.at(i); + if (!givenType->isImplicitlyConvertibleTo(*expType)) { + m_errorReporter.typeError(228_error, arguments.at(i)->location(), + "Expected " + expType->canonicalName() + " type, but given " + givenType->canonicalName()); } } }; @@ -3934,7 +3926,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) paramTypes.push_back(TypeProvider::boolean()); checkAtLeastOneArg(); if (arguments.size() >= 2) { - paramTypes.push_back(TypeProvider::uint256()); + paramTypes.push_back(TypeProvider::uint(16)); } if (arguments.size() >= 3) { paramTypes.push_back(arguments.at(2)->annotation().type->mobileType()); @@ -3947,7 +3939,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) } case FunctionType::Kind::Revert: { if (!arguments.empty()) { - paramTypes.push_back(TypeProvider::uint256()); + paramTypes.push_back(TypeProvider::uint(16)); } if (arguments.size() >= 2) { paramTypes.push_back(arguments.at(1)->annotation().type->mobileType()); diff --git a/compiler/libsolidity/analysis/ViewPureChecker.cpp b/compiler/libsolidity/analysis/ViewPureChecker.cpp index 80ca2d7b..a918e5fb 100644 --- a/compiler/libsolidity/analysis/ViewPureChecker.cpp +++ b/compiler/libsolidity/analysis/ViewPureChecker.cpp @@ -47,9 +47,15 @@ bool ViewPureChecker::visit(FunctionDefinition const& _funDef) solAssert(!m_currentFunction, ""); m_currentFunction = &_funDef; m_bestMutabilityAndLocation = {StateMutability::Pure, _funDef.location()}; - ContractDefinition const* contr = _funDef.annotation().contract; - if (contr->isLibrary() && _funDef.stateMutability() != StateMutability::NonPayable) { - m_errorReporter.warning(228_error, _funDef.location(), "Library functions must have default mutability. Delete keyword view or pure."); + if (ContractDefinition const* contr = _funDef.annotation().contract) { + if (contr->isLibrary() && _funDef.stateMutability() != StateMutability::NonPayable) { + m_errorReporter.warning(228_error, _funDef.location(), + "Library functions must have default mutability. Delete keyword view or pure."); + } + } + if (_funDef.isFree() && _funDef.stateMutability() != StateMutability::NonPayable) { + m_errorReporter.warning(228_error, _funDef.location(), + "Free functions must have default mutability. Delete keyword view or pure."); } return true; } @@ -65,13 +71,15 @@ void ViewPureChecker::endVisit(FunctionDefinition const& _funDef) } } + ContractDefinition const* contract = _funDef.annotation().contract; if ( m_bestMutabilityAndLocation.mutability < _funDef.stateMutability() && _funDef.isImplemented() && !_funDef.body().statements().empty() && !_funDef.isConstructor() && !_funDef.overrides() && - !_funDef.annotation().contract->isLibrary() && + !(contract && contract->isLibrary()) && + !_funDef.isFree() && !_funDef.isFallback() && !_funDef.isReceive() && !_funDef.virtualSemantics() @@ -252,7 +260,16 @@ void ViewPureChecker::endVisit(FunctionCall const& _functionCall) } } if (!isLibCall) { - mutability = dynamic_cast(*_functionCall.expression().annotation().type).stateMutability(); + bool isFree{}; + auto ident = dynamic_cast(&_functionCall.expression()); + if (ident) { + auto funcDef = dynamic_cast(ident->annotation().referencedDeclaration); + isFree = funcDef && funcDef->isFree(); + } + if (isFree) + mutability = StateMutability::Pure; + else + mutability = dynamic_cast(*_functionCall.expression().annotation().type).stateMutability(); } } } @@ -320,7 +337,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) {MagicType::Kind::ABI, "encodeWithSelector"}, {MagicType::Kind::ABI, "encodeWithSignature"}, {MagicType::Kind::Block, "blockhash"}, - {MagicType::Kind::Block, "logtimestamp"}, + {MagicType::Kind::Block, "logicaltime"}, {MagicType::Kind::Block, "timestamp"}, {MagicType::Kind::Gosh, "applyBinPatch"}, {MagicType::Kind::Gosh, "applyBinPatchQ"}, diff --git a/compiler/libsolidity/ast/ASTJsonExporter.cpp b/compiler/libsolidity/ast/ASTJsonExporter.cpp index bc98a0d7..ab06b215 100644 --- a/compiler/libsolidity/ast/ASTJsonExporter.cpp +++ b/compiler/libsolidity/ast/ASTJsonExporter.cpp @@ -710,7 +710,8 @@ bool ASTJsonExporter::visit(Return const& _node) { setJsonNode(_node, "Return", { make_pair("expression", toJsonOrNull(_node.expression())), - make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters)) + make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters)), + make_pair("options", toJson(_node.options())), }); return false; } diff --git a/compiler/libsolidity/ast/Types.cpp b/compiler/libsolidity/ast/Types.cpp index 96bd3440..3a6f54de 100644 --- a/compiler/libsolidity/ast/Types.cpp +++ b/compiler/libsolidity/ast/Types.cpp @@ -4384,7 +4384,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const { case Kind::Block: return MemberList::MemberMap({ - {"logtimestamp", TypeProvider::uint(64)}, + {"logicaltime", TypeProvider::uint(64)}, {"timestamp", TypeProvider::uint(32)}, {"difficulty", TypeProvider::uint256()}, {"number", TypeProvider::uint256()}, @@ -4537,12 +4537,12 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const )); members.emplace_back("rawConfigParam", TypeProvider::function( - TypePointers{TypeProvider::integer(32, IntegerType::Modifier::Signed)}, - TypePointers{TypeProvider::tvmcell(), TypeProvider::boolean()}, - strings{string()}, - strings{string(), string()}, - FunctionType::Kind::TVMRawConfigParam, - StateMutability::Pure + {TypeProvider::integer(32, IntegerType::Modifier::Signed)}, + {TypeProvider::optional(TypeProvider::tvmcell())}, + {{}}, + {{}}, + FunctionType::Kind::TVMRawConfigParam, + StateMutability::Pure )); members.emplace_back("buildExtMsg", TypeProvider::function( @@ -5137,7 +5137,40 @@ MemberList::MemberMap TvmSliceType::nativeMembers(ASTNode const *) const { StateMutability::Pure, nullptr, FunctionType::Options::withArbitraryParameters() ) - } + }, + { + "loadOnes", + TypeProvider::function( + {}, + {TypeProvider::uint(10)}, + {}, + {{}}, + FunctionType::Kind::TVMSliceSize, + StateMutability::Pure + ) + }, + { + "loadZeroes", + TypeProvider::function( + {}, + {TypeProvider::uint(10)}, + {}, + {{}}, + FunctionType::Kind::TVMSliceSize, + StateMutability::Pure + ) + }, + { + "loadSame", + TypeProvider::function( + {TypeProvider::uint(1)}, + {TypeProvider::uint(10)}, + {{}}, + {{}}, + FunctionType::Kind::TVMSliceSize, + StateMutability::Pure + ) + }, }; members.emplace_back("decode", TypeProvider::function( @@ -5483,7 +5516,19 @@ TypeResult TvmCellType::binaryOperatorResult(Token _operator, const Type *_other MemberList::MemberMap TvmBuilderType::nativeMembers(const ASTNode *) const { - MemberList::MemberMap members; + MemberList::MemberMap members = { + { + "storeSame", + TypeProvider::function( + {TypeProvider::uint(10), TypeProvider::uint(1)}, + {}, + {{}, {}}, + {}, + FunctionType::Kind::TVMBuilderMethods, + StateMutability::Pure + ) + }, + }; members.emplace_back("depth", TypeProvider::function( TypePointers{}, @@ -5595,7 +5640,7 @@ MemberList::MemberMap TvmBuilderType::nativeMembers(const ASTNode *) const for (const std::string func : {"storeOnes", "storeZeroes"}) { members.emplace_back(func.c_str(), TypeProvider::function( - {TypeProvider::uint256()}, + {TypeProvider::uint(10)}, {}, {{}}, {}, diff --git a/compiler/libsolidity/codegen/DictOperations.cpp b/compiler/libsolidity/codegen/DictOperations.cpp index f39d5ff4..e68a3ea4 100644 --- a/compiler/libsolidity/codegen/DictOperations.cpp +++ b/compiler/libsolidity/codegen/DictOperations.cpp @@ -268,7 +268,7 @@ void DelMinOrMax::delMinOrMax() { opcode = "DICT" + typeToDictChar(&keyType) + "REM" + (isDelMin? "MIN" : "MAX") + (isInRef? "REF" : ""); stackSize = pusher.stackSize(); - lValueInfo = ec->expandLValue(&memberAccess->expression(), true, true); // lValue... map + lValueInfo = ec->expandLValue(&memberAccess->expression(), true); // lValue... map pusher.pushInt(keyLength); // dict nbits pusher.startOpaque(); diff --git a/compiler/libsolidity/codegen/TVM.cpp b/compiler/libsolidity/codegen/TVM.cpp index fdf3d16b..f0f524a3 100644 --- a/compiler/libsolidity/codegen/TVM.cpp +++ b/compiler/libsolidity/codegen/TVM.cpp @@ -61,7 +61,7 @@ std::string getPathToFiles( void TVMCompilerProceedContract( ContractDefinition const& _contract, - std::vector libraries, + std::vector> _sourceUnits, std::vector const* pragmaDirectives, bool generateAbi, bool generateCode, @@ -77,10 +77,10 @@ void TVMCompilerProceedContract( if (doPrintFunctionIds) { TVMContractCompiler::printFunctionIds(_contract, pragmaHelper); } else if (doPrivateFunctionIds) { - TVMContractCompiler::printPrivateFunctionIds(_contract, libraries, pragmaHelper); + TVMContractCompiler::printPrivateFunctionIds(_contract, _sourceUnits, pragmaHelper); } else { if (generateCode) { - TVMContractCompiler::generateCode(pathToFiles + ".code", _contract, libraries, pragmaHelper); + TVMContractCompiler::generateCodeAndSaveToFile(pathToFiles + ".code", _contract, _sourceUnits, pragmaHelper); } if (generateAbi) { TVMContractCompiler::generateABI(pathToFiles + ".abi.json", &_contract, *pragmaDirectives); diff --git a/compiler/libsolidity/codegen/TVM.h b/compiler/libsolidity/codegen/TVM.h index c447ea6e..dc36f1a6 100644 --- a/compiler/libsolidity/codegen/TVM.h +++ b/compiler/libsolidity/codegen/TVM.h @@ -37,7 +37,7 @@ std::string getPathToFiles( void TVMCompilerProceedContract( solidity::frontend::ContractDefinition const& _contract, - std::vector libraries, + std::vector> _sourceUnits, std::vector const* pragmaDirectives, bool generateAbi, bool generateCode, diff --git a/compiler/libsolidity/codegen/TVMABI.cpp b/compiler/libsolidity/codegen/TVMABI.cpp index 262f8ccd..59951914 100644 --- a/compiler/libsolidity/codegen/TVMABI.cpp +++ b/compiler/libsolidity/codegen/TVMABI.cpp @@ -79,11 +79,11 @@ Json::Value TVMABI::generateFunctionIdsJson( Json::Value TVMABI::generatePrivateFunctionIdsJson( const ContractDefinition &contract, - std::vector libraries, + std::vector> _sourceUnits, const PragmaDirectiveHelper &pragmaHelper ) { Json::Value ids{Json::arrayValue}; - Pointer codeContract = TVMContractCompiler::generateContractCode(&contract, libraries, pragmaHelper); + Pointer codeContract = TVMContractCompiler::generateContractCode(&contract, _sourceUnits, pragmaHelper); for (Pointer const& fun : codeContract->functions()) { if (fun->type() == Function::FunctionType::PrivateFunction) { Json::Value func{Json::objectValue}; @@ -562,7 +562,7 @@ DecodePositionAbiV2::DecodePositionAbiV2(int _bitOffset, int _refOffset, const s } else { bits += size.maxBits; refs += size.maxRefs; - if (bits >= TvmConst::CellBitLength || refs >= 4) { + if (bits > TvmConst::CellBitLength || refs >= 4) { m_doLoadNextCell[i] = true; bits = size.maxBits; refs = size.maxRefs; diff --git a/compiler/libsolidity/codegen/TVMABI.hpp b/compiler/libsolidity/codegen/TVMABI.hpp index d0b4e58c..6de0cffa 100644 --- a/compiler/libsolidity/codegen/TVMABI.hpp +++ b/compiler/libsolidity/codegen/TVMABI.hpp @@ -34,7 +34,7 @@ class TVMABI { ); static Json::Value generatePrivateFunctionIdsJson( ContractDefinition const& contract, - std::vector libraries, + std::vector> _sourceUnits, PragmaDirectiveHelper const& pragmaHelper ); static void generateABI(ContractDefinition const* contract, diff --git a/compiler/libsolidity/codegen/TVMCommons.hpp b/compiler/libsolidity/codegen/TVMCommons.hpp index 442b6de2..8a9d82b8 100644 --- a/compiler/libsolidity/codegen/TVMCommons.hpp +++ b/compiler/libsolidity/codegen/TVMCommons.hpp @@ -351,7 +351,7 @@ enum class SetDictOperation { Set, Replace, Add }; struct LValueInfo { std::vector expressions; - bool doesntNeedToCollect = false; + int stackSizeDiff = 0; }; DictValueType toDictValueType(const Type::Category& category); diff --git a/compiler/libsolidity/codegen/TVMContractCompiler.cpp b/compiler/libsolidity/codegen/TVMContractCompiler.cpp index c97d4634..a60ba990 100644 --- a/compiler/libsolidity/codegen/TVMContractCompiler.cpp +++ b/compiler/libsolidity/codegen/TVMContractCompiler.cpp @@ -185,11 +185,11 @@ void TVMContractCompiler::printFunctionIds( } void TVMContractCompiler::printPrivateFunctionIds( - ContractDefinition const& contract, - std::vector libraries, - PragmaDirectiveHelper const& pragmaHelper + ContractDefinition const& contract, + std::vector> _sourceUnits, + PragmaDirectiveHelper const& pragmaHelper ) { - Json::Value functionIds = TVMABI::generatePrivateFunctionIdsJson(contract, libraries, pragmaHelper); + Json::Value functionIds = TVMABI::generatePrivateFunctionIdsJson(contract, _sourceUnits, pragmaHelper); cout << functionIds << endl; } @@ -211,13 +211,13 @@ void TVMContractCompiler::generateABI( } } -void TVMContractCompiler::generateCode( +void TVMContractCompiler::generateCodeAndSaveToFile( const std::string& fileName, ContractDefinition const& contract, - std::vector libraries, + std::vector> _sourceUnits, PragmaDirectiveHelper const &pragmaHelper ) { - Pointer codeContract = generateContractCode(&contract, libraries, pragmaHelper); + Pointer codeContract = generateContractCode(&contract, _sourceUnits, pragmaHelper); ofstream ofile; ofile.open(fileName); @@ -233,7 +233,7 @@ void TVMContractCompiler::generateCode( Pointer TVMContractCompiler::generateContractCode( ContractDefinition const *contract, - std::vector libraries, + std::vector> _sourceUnits, PragmaDirectiveHelper const &pragmaHelper ) { std::vector pragmas; @@ -363,29 +363,58 @@ TVMContractCompiler::generateContractCode( } } - for (ContractDefinition const * lib : libraries) { - for (FunctionDefinition const *function : lib->definedFunctions()) { - ctx.setCurrentFunction(function); - - if (!function->modifiers().empty()) { - cast_error(*function->modifiers().at(0).get(), - "Modifiers for library functions are not supported yet."); + for (std::shared_ptr source: _sourceUnits) { + for (ASTPointer const &node: source->nodes()) { + if (auto lib = dynamic_cast(node.get())) { + if (lib->isLibrary()) { + for (FunctionDefinition const *function : lib->definedFunctions()) { + ctx.setCurrentFunction(function); + + if (!function->modifiers().empty()) { + cast_error(*function->modifiers().at(0).get(), + "Modifiers for library functions are not supported yet."); + } + + if (!function->parameters().empty()) { + { + const std::string name = TVMCompilerContext::getLibFunctionName(function, true); + functions.emplace_back(TVMFunctionCompiler::generateLibraryFunction(ctx, function, name)); + } + { + const std::string name = TVMCompilerContext::getLibFunctionName(function, true) + "_macro"; + functions.emplace_back(TVMFunctionCompiler::generateLibraryFunctionMacro(ctx, function, name)); + } + } + const std::string name = TVMCompilerContext::getLibFunctionName(function, false); + functions.emplace_back(TVMFunctionCompiler::generatePrivateFunction(ctx, name, function)); + functions.emplace_back(TVMFunctionCompiler::generateMacro(ctx, function, name + "_macro")); + ctx.setCurrentFunction(nullptr); + } + } } + } + } - if (!function->parameters().empty()) { - { - const std::string name = TVMCompilerContext::getLibFunctionName(function, true); - functions.emplace_back(TVMFunctionCompiler::generateLibraryFunction(ctx, function, name)); - } - { - const std::string name = TVMCompilerContext::getLibFunctionName(function, true) + "_macro"; - functions.emplace_back(TVMFunctionCompiler::generateLibraryFunctionMacro(ctx, function, name)); + for (std::shared_ptr source: _sourceUnits) { + for (ASTPointer const &node: source->nodes()) { + if (auto function = dynamic_cast(node.get())) { + if (function->isFree()) { + ctx.setCurrentFunction(function); + + if (!function->modifiers().empty()) { + cast_error(*function->modifiers().at(0).get(), + "Modifiers for free functions are not supported yet."); + } + + std::string functionName = ctx.getFunctionInternalName(function); + functions.push_back(TVMFunctionCompiler::generatePrivateFunction(ctx, functionName, function)); + + const std::string macroName = functionName + "_macro"; + functions.push_back(TVMFunctionCompiler::generateMacro(ctx, function, macroName)); + + ctx.setCurrentFunction(nullptr); } } - const std::string name = TVMCompilerContext::getLibFunctionName(function, false); - functions.emplace_back(TVMFunctionCompiler::generatePrivateFunction(ctx, name, function)); - functions.emplace_back(TVMFunctionCompiler::generateMacro(ctx, function, name + "_macro")); - ctx.setCurrentFunction(nullptr); } } diff --git a/compiler/libsolidity/codegen/TVMContractCompiler.hpp b/compiler/libsolidity/codegen/TVMContractCompiler.hpp index f5ad9556..1bd96e04 100644 --- a/compiler/libsolidity/codegen/TVMContractCompiler.hpp +++ b/compiler/libsolidity/codegen/TVMContractCompiler.hpp @@ -46,7 +46,7 @@ class TVMContractCompiler: private boost::noncopyable { static void printFunctionIds(ContractDefinition const& contract, PragmaDirectiveHelper const& pragmaHelper); static void printPrivateFunctionIds( ContractDefinition const& contract, - std::vector libraries, + std::vector> _sourceUnits, PragmaDirectiveHelper const& pragmaHelper ); static void generateABI( @@ -54,15 +54,15 @@ class TVMContractCompiler: private boost::noncopyable { ContractDefinition const* contract, std::vector const& pragmaDirectives ); - static void generateCode( + static void generateCodeAndSaveToFile( const std::string& fileName, ContractDefinition const& contract, - std::vector libraries, + std::vector> _sourceUnits, PragmaDirectiveHelper const &pragmaHelper ); static Pointer generateContractCode( ContractDefinition const* contract, - std::vector libraries, + std::vector> _sourceUnits, PragmaDirectiveHelper const& pragmaHelper ); static void optimizeCode(Pointer& c); diff --git a/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp b/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp index 69a0b624..596af530 100644 --- a/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp +++ b/compiler/libsolidity/codegen/TVMExpressionCompiler.cpp @@ -246,8 +246,7 @@ void TVMExpressionCompiler::visit2(Identifier const &_identifier) { } else if (name == "this") { // calling this.function() creates an internal message that should be sent to the address of current contract m_pusher.push(+1, "MYADDR"); - } else if (to(_identifier.annotation().referencedDeclaration)) { - auto funDecl = to(_identifier.annotation().referencedDeclaration); + } else if (auto funDecl = to(_identifier.annotation().referencedDeclaration)) { m_pusher.pushPrivateFunctionId(*funDecl); } else { cast_error(_identifier, "Unsupported identifier: " + name); @@ -263,7 +262,7 @@ void TVMExpressionCompiler::compileUnaryOperation( Type const* resType = _node.annotation().type; LValueInfo lValueInfo; if (isCurrentResultNeeded()) { - lValueInfo = expandLValue(&_node.subExpression(), true, true); + lValueInfo = expandLValue(&_node.subExpression(), true); const int expandedLValueSize = m_pusher.stackSize() - saveStackSize - 1; solAssert(expandedLValueSize >= 0, ""); if (isPrefixOperation) { @@ -281,7 +280,7 @@ void TVMExpressionCompiler::compileUnaryOperation( } } } else { - lValueInfo = expandLValue(&_node.subExpression(), true, true); + lValueInfo = expandLValue(&_node.subExpression(), true); m_pusher.push(0, tvmUnaryOperation); } @@ -292,7 +291,7 @@ void TVMExpressionCompiler::compileUnaryOperation( } void TVMExpressionCompiler::compileUnaryDelete(UnaryOperation const &node) { - const LValueInfo lValueInfo = expandLValue(&node.subExpression(), false, true); + const LValueInfo lValueInfo = expandLValue(&node.subExpression(), false); Expression const* lastExpr = lValueInfo.expressions.back(); Type const* exprType = node.subExpression().annotation().type; if (to(lastExpr)) { @@ -815,7 +814,7 @@ void TVMExpressionCompiler::visitMagic(MemberAccess const &_node) { } else if (identifier->name() == "block") { if (_node.memberName() == "timestamp") { m_pusher << "NOW"; - } else if (_node.memberName() == "logtimestamp") { + } else if (_node.memberName() == "logicaltime") { m_pusher << "BLOCKLT"; } else { unsupportedMagic(); @@ -1086,9 +1085,10 @@ bool TVMExpressionCompiler::isOptionalGet(Expression const* expr) { LValueInfo TVMExpressionCompiler::expandLValue( Expression const *const _expr, - const bool withExpandLastValue, - bool isLValue + const bool withExpandLastValue ) { + solAssert(*_expr->annotation().isLValue, ""); + const int startStackSize = m_pusher.stackSize(); LValueInfo lValueInfo {}; Expression const* expr = _expr; @@ -1104,14 +1104,8 @@ TVMExpressionCompiler::expandLValue( memberAccess && getType(&memberAccess->expression())->category() == Type::Category::Struct ) { expr = &memberAccess->expression(); - } else if ( - auto funCall = to(expr); - funCall && !isLValue - ) { - compileNewExpr(_expr); - lValueInfo.doesntNeedToCollect = true; - return lValueInfo; } else if (isOptionalGet(expr)) { + auto funCall = to(expr); auto ma = to(&funCall->expression()); expr = &ma->expression(); } else { @@ -1120,8 +1114,9 @@ TVMExpressionCompiler::expandLValue( } std::reverse(lValueInfo.expressions.begin(), lValueInfo.expressions.end()); - for (int i = 0; i < static_cast(lValueInfo.expressions.size()); i++) { - bool isLast = (i + 1) == static_cast(lValueInfo.expressions.size()); + const int n = static_cast(lValueInfo.expressions.size()); + for (int i = 0; i < n; i++) { + bool isLast = i + 1 == n; if (auto variable = to(lValueInfo.expressions[i])) { auto& stack = m_pusher.getStack(); auto name = variable->name(); @@ -1187,6 +1182,7 @@ TVMExpressionCompiler::expandLValue( solUnimplemented(""); } } + lValueInfo.stackSizeDiff = m_pusher.stackSize() - startStackSize; return lValueInfo; } @@ -1199,23 +1195,17 @@ TVMExpressionCompiler::collectLValue( { // variable [arrayIndex | mapIndex | structMember | .get()]... - if (lValueInfo.doesntNeedToCollect) { - solAssert(haveValueOnStackTop, "Collect with not needed value is available only for on stack top values."); - m_pusher.drop(); - return; - } - const int n = static_cast(lValueInfo.expressions.size()); for (int i = n - 1; i >= 0; i--) { - const bool isLast = (i + 1) == static_cast(lValueInfo.expressions.size()); + const bool isLast = i + 1 == n; if (auto variable = to(lValueInfo.expressions[i])) { // pushLog("colVar"); auto& stack = m_pusher.getStack(); if (stack.isParam(variable->annotation().referencedDeclaration)) { solAssert((haveValueOnStackTop && n == 1) || n > 1, ""); - m_pusher.tryAssignParam(variable->annotation().referencedDeclaration); + m_pusher.assignStackVariable(variable->annotation().referencedDeclaration); } else { // value auto vd = to(variable->annotation().referencedDeclaration); @@ -1283,7 +1273,7 @@ bool TVMExpressionCompiler::tryAssignLValue(Assignment const &_assignment) { const int saveStackSize0 = m_pusher.stackSize(); bool valueIsBuilder = push_rhs(); const int saveStackSize = m_pusher.stackSize(); - const LValueInfo lValueInfo = expandLValue(&lhs, false, true); + const LValueInfo lValueInfo = expandLValue(&lhs, false); if (isCurrentResultNeeded()) { solAssert(saveStackSize - saveStackSize0 == 1, ""); m_pusher.pushS(m_pusher.stackSize() - saveStackSize); @@ -1296,7 +1286,7 @@ bool TVMExpressionCompiler::tryAssignLValue(Assignment const &_assignment) { compileNewExpr(&rhs); // r m_pusher.hardConvert(commonType, rhs.annotation().type); const int saveStackSize = m_pusher.stackSize(); - const LValueInfo lValueInfo = expandLValue(&lhs, true, true); // r expanded... l + const LValueInfo lValueInfo = expandLValue(&lhs, true); // r expanded... l m_pusher.hardConvert(commonType, lhs.annotation().type); const int expandedLValueSize = m_pusher.stackSize() - saveStackSize - 1; m_pusher.blockSwap(1, expandedLValueSize + 1); // expanded... l r @@ -1342,7 +1332,7 @@ bool TVMExpressionCompiler::tryAssignTuple(Assignment const &_assignment) { m_pusher.hardConvert(leftComp->annotation().type, rhs.annotation().type); } const int stackSizeForValue = m_pusher.stackSize(); - const LValueInfo lValueInfo = expandLValue(leftComp.get(), false, true); + const LValueInfo lValueInfo = expandLValue(leftComp.get(), false); const int stackSize = m_pusher.stackSize(); const int expandLValueSize = stackSize - stackSizeForValue; if (expandLValueSize > 0) { diff --git a/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp b/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp index 0e6b1184..29383b4e 100644 --- a/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp +++ b/compiler/libsolidity/codegen/TVMExpressionCompiler.hpp @@ -31,8 +31,7 @@ class TVMExpressionCompiler { LValueInfo expandLValue( Expression const* const _expr, - const bool withExpandLastValue, - bool isLValue + const bool withExpandLastValue ); void collectLValue(const LValueInfo &lValueInfo, bool haveValueOnStackTop, bool isValueBuilder); diff --git a/compiler/libsolidity/codegen/TVMFunctionCall.cpp b/compiler/libsolidity/codegen/TVMFunctionCall.cpp index ad2f39c5..2784a2ea 100644 --- a/compiler/libsolidity/codegen/TVMFunctionCall.cpp +++ b/compiler/libsolidity/codegen/TVMFunctionCall.cpp @@ -90,8 +90,9 @@ void FunctionCallCompiler::compile() { arrayMethods(*ma); } else if (category == Type::Category::TvmSlice) { sliceMethods(*ma); + } else if (category == Type::Category::TvmBuilder) { + builderMethods(*ma); } else if ( - checkForTvmBuilderMethods(*ma, category) || checkForTvmVectorMethods(*ma, category) || checkForOptionalMethods(*ma)) { @@ -218,7 +219,7 @@ void FunctionCallCompiler::mappingGetSet() { } else if (isIn(memberName, "replace", "add", "getSet", "getAdd", "getReplace")) { const int stackSize = m_pusher.stackSize(); auto ma = to(&m_functionCall.expression()); - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&ma->expression(), true, true); // lValue... map + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&ma->expression(), true); // lValue... map pushArgAndConvert(1); // lValue... map value const DataType& dataType = m_pusher.prepareValueForDictOperations(keyType, valueType); // lValue... map value' pushArgAndConvert(0); // mapLValue... map value key @@ -431,7 +432,7 @@ bool FunctionCallCompiler::libraryCall(MemberAccess const& ma) { // using MathLib for uint; // a.add(b); const int stakeSize0 = m_pusher.stackSize(); - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&ma.expression(), true, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&ma.expression(), true); const int stakeSize1 = m_pusher.stackSize(); const int lValueQty = stakeSize1 - stakeSize0; @@ -1304,195 +1305,206 @@ bool FunctionCallCompiler::checkForTvmDeployMethods(MemberAccess const &_node, T } void FunctionCallCompiler::sliceMethods(MemberAccess const &_node) { - if (_node.memberName() == "empty") { + ASTString const& memberName = _node.memberName(); + if (memberName == "empty") { acceptExpr(&_node.expression()); m_pusher.push(-1 + 1, "SEMPTY"); - } else if (_node.memberName() == "dataSize") { + } else if (memberName == "dataSize") { acceptExpr(&_node.expression()); pushArgAndConvert(0); m_pusher.push(-2 + 3, "SDATASIZE"); - } else if (_node.memberName() == "dataSizeQ") { + } else if (memberName == "dataSizeQ") { acceptExpr(&_node.expression()); pushArgAndConvert(0); cellBitRefQty(false); - } else if (_node.memberName() == "size") { + } else if (memberName == "size") { acceptExpr(&_node.expression()); m_pusher.push(-1+2, "SBITREFS"); - } else if (_node.memberName() == "bits") { + } else if (memberName == "bits") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "SBITS"); - } else if (_node.memberName() == "compare") { + } else if (memberName == "compare") { acceptExpr(&_node.expression()); pushArgAndConvert(0); m_pusher.push(-2+1, "SDLEXCMP"); - } else if (_node.memberName() == "hasNBits") { + } else if (memberName == "hasNBits") { acceptExpr(&_node.expression()); pushArgAndConvert(0); m_pusher.push(-2+1, "SCHKBITSQ"); - } else if (_node.memberName() == "hasNRefs") { + } else if (memberName == "hasNRefs") { acceptExpr(&_node.expression()); pushArgAndConvert(0); m_pusher.push(-2+1, "SCHKREFSQ"); - } else if (_node.memberName() == "hasNBitsAndRefs") { + } else if (memberName == "hasNBitsAndRefs") { acceptExpr(&_node.expression()); pushArgAndConvert(0); pushArgAndConvert(1); m_pusher.push(-3+1, "SCHKBITREFSQ"); - } else if (_node.memberName() == "refs") { + } else if (memberName == "refs") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "SREFS"); - } else if (_node.memberName() == "depth") { + } else if (memberName == "depth") { acceptExpr(&_node.expression()); m_pusher.push(-1 + 1, "SDEPTH"); - } else if (_node.memberName() == "decode") { - const int stackSize = m_pusher.stackSize(); - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, - *_node.expression().annotation().isLValue); - TypePointers targetTypes; - if (auto const* targetTupleType = dynamic_cast(m_retType)) - targetTypes = targetTupleType->components(); - else - targetTypes = TypePointers{m_retType}; - - ChainDataDecoder decode{&m_pusher}; - DecodePositionFromOneSlice pos; - decode.decodeParameters(targetTypes, pos, false); - - m_exprCompiler.collectLValue(lValueInfo, true, false); - solAssert(stackSize + static_cast(targetTypes.size()) == m_pusher.stackSize(), ""); - } else if (_node.memberName() == "decodeQ") { - - const int stackSize = m_pusher.stackSize(); - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, - *_node.expression().annotation().isLValue); - auto optType = to(m_retType); - TypePointers targetTypes; - if (auto const* targetTupleType = dynamic_cast(optType->valueType())) - targetTypes = targetTupleType->components(); - else - targetTypes = TypePointers{optType->valueType()}; - - ChainDataDecoder decode{&m_pusher}; - DecodePositionFromOneSlice pos; - decode.decodeParametersQ(targetTypes, pos); - - m_exprCompiler.collectLValue(lValueInfo, true, false); - solAssert(stackSize + 1 == m_pusher.stackSize(), toString(stackSize) + " vs" + toString(m_pusher.stackSize())); - } else if (_node.memberName() == "decodeFunctionParams") { - const int saveStackSize = m_pusher.stackSize(); - CallableDeclaration const* functionDefinition = getFunctionDeclarationOrConstructor(m_arguments.at(0).get()); - const LValueInfo lValueInfo = - m_exprCompiler.expandLValue(&_node.expression(), true, - *_node.expression().annotation().isLValue); - // lvalue.. slice - if (functionDefinition) { - auto fd = to(functionDefinition); - bool isResponsible = fd->isResponsible(); - if (isResponsible) { - m_pusher.push(-1 + 2, "LDU 32"); - } - // lvalue.. callback slice - ChainDataDecoder decoder{&m_pusher}; - - vector types = getParams(functionDefinition->parameters()).first; - decoder.decodePublicFunctionParameters(types, isResponsible, true); - - const int saveStackSize2 = m_pusher.stackSize(); - const int paramQty = functionDefinition->parameters().size() + (isResponsible ? 1 : 0); - m_pusher.blockSwap(saveStackSize2 - saveStackSize - paramQty, paramQty); - - m_pusher.pushSlice("x8_"); + } else if (memberName == "skip") { + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); + if (m_arguments.size() == 1) { + pushArgAndConvert(0); + m_pusher.push(-2+1, "SDSKIPFIRST"); + } else { + pushArgAndConvert(0); + pushArgAndConvert(1); + m_pusher.push(-3+1, "SSKIPFIRST"); } m_exprCompiler.collectLValue(lValueInfo, true, false); - } else if (boost::starts_with(_node.memberName(), "load")) { - const LValueInfo lValueInfo = - m_exprCompiler.expandLValue(&_node.expression(), true, *_node.expression().annotation().isLValue); - if (_node.memberName() == "loadRefAsSlice") { - m_pusher.push(-1 + 2, "LDREFRTOS"); - m_pusher.exchange(1); - } else if (_node.memberName() == "loadRef") { - m_pusher.push(-1 + 2, "LDREF"); - } else if (_node.memberName() == "loadUnsigned" || _node.memberName() == "loadSigned") { - std::string cmd = "LD"; - cmd += (_node.memberName() == "loadSigned" ? "I" : "U"); - const auto& val = ExprUtils::constValue(*m_arguments[0]); - if (val.has_value()) { - if (val < 1 || val > 256) { - cast_error(*m_arguments[0], "The value must be in the range 1 - 256."); + } else if (isIn(memberName, "decode", "decodeQ") || boost::starts_with(memberName, "load")) { + int stackDelta = 0; + const int stackSize = m_pusher.stackSize(); + bool isLValue = *_node.expression().annotation().isLValue; + LValueInfo lValueInfo; + if (isLValue) { + lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); + } else { + acceptExpr(&_node.expression()); + } + if (memberName == "decode") { + TypePointers targetTypes; + if (auto const *targetTupleType = dynamic_cast(m_retType)) + targetTypes = targetTupleType->components(); + else + targetTypes = TypePointers{m_retType}; + + ChainDataDecoder decode{&m_pusher}; + DecodePositionFromOneSlice pos; + decode.decodeParameters(targetTypes, pos, false); + stackDelta = targetTypes.size(); + } else if (memberName == "decodeQ") { + auto optType = to(m_retType); + TypePointers targetTypes; + if (auto const *targetTupleType = dynamic_cast(optType->valueType())) + targetTypes = targetTupleType->components(); + else + targetTypes = TypePointers{optType->valueType()}; + + ChainDataDecoder decode{&m_pusher}; + DecodePositionFromOneSlice pos; + decode.decodeParametersQ(targetTypes, pos); + stackDelta = 1; + } else if (boost::starts_with(memberName, "load")) { + stackDelta = 1; + if (memberName == "loadRefAsSlice") { + m_pusher.push(-1 + 2, "LDREFRTOS"); + m_pusher.exchange(1); + } else if (memberName == "loadRef") { + m_pusher.push(-1 + 2, "LDREF"); + } else if (memberName == "loadUnsigned" || memberName == "loadSigned") { + std::string cmd = "LD"; + cmd += (memberName == "loadSigned" ? "I" : "U"); + const auto& val = ExprUtils::constValue(*m_arguments[0]); + if (val.has_value()) { + if (val < 1 || val > 256) { + cast_error(*m_arguments[0], "The value must be in the range 1 - 256."); + } + m_pusher.push(-1 + 2, cmd + " " + val.value().str()); + } else { + pushArgAndConvert(0); + m_pusher.push(-2 + 2, cmd + "X"); } - m_pusher.push(-1 + 2, cmd + " " + val.value().str()); - } else { - pushArgAndConvert(0); - m_pusher.push(-2 + 2, cmd + "X"); - } - } else if (_node.memberName() == "loadTons") { - m_pusher.push(-1 + 2, "LDGRAMS"); - } else if (_node.memberName() == "loadSlice") { - if (m_arguments.size() == 1) { - const auto& value = ExprUtils::constValue(*m_arguments[0].get()); - if (value.has_value()) { - m_pusher.push(+1, "LDSLICE " + value.value().str()); + } else if (memberName == "loadTons") { + m_pusher.push(-1 + 2, "LDGRAMS"); + } else if (memberName == "loadSlice") { + if (m_arguments.size() == 1) { + const auto& value = ExprUtils::constValue(*m_arguments[0].get()); + if (value.has_value()) { + m_pusher.push(+1, "LDSLICE " + value.value().str()); + } else { + pushArgAndConvert(0); + m_pusher.push(-2+2, "LDSLICEX"); + } } else { pushArgAndConvert(0); - m_pusher.push(-2+2, "LDSLICEX"); + pushArgAndConvert(1); + m_pusher.push(-3+2, "SPLIT"); } + } else if (memberName == "loadOnes") { + m_pusher.push(-1 + 2, "LDONES"); + } else if (memberName == "loadZeroes") { + m_pusher.push(-1 + 2, "LDZEROES"); + } else if (memberName == "loadSame") { + pushArgs(); + m_pusher.push(-2 + 2, "LDSAME"); } else { - pushArgAndConvert(0); - pushArgAndConvert(1); - m_pusher.push(-3+2, "SPLIT"); + solUnimplemented(""); } } else { solUnimplemented(""); } - - m_exprCompiler.collectLValue(lValueInfo, true, false); - } else if (_node.memberName() == "skip") { - const LValueInfo lValueInfo = - m_exprCompiler.expandLValue(&_node.expression(), true, - *_node.expression().annotation().isLValue); - if (m_arguments.size() == 1) { - pushArgAndConvert(0); - m_pusher.push(-2+1, "SDSKIPFIRST"); + if (isLValue) { + // lvalue... decodedValues... slice + m_pusher.blockSwap(stackDelta, 1); + // lvalue... slice decodedValues... + m_pusher.blockSwap(lValueInfo.stackSizeDiff, stackDelta); + // decodedValues... lvalue... slice + m_exprCompiler.collectLValue(lValueInfo, true, false); } else { - pushArgAndConvert(0); - pushArgAndConvert(1); - m_pusher.push(-3+1, "SSKIPFIRST"); - } - m_exprCompiler.collectLValue(lValueInfo, true, false); - } else if (_node.memberName() == "decodeStateVars") { - const int saveStackSize = m_pusher.stackSize(); - - std::vector stateVarTypes; + // decodedValues... slice + m_pusher.drop(); + // decodedValues... + } + solAssert(stackSize + stackDelta == m_pusher.stackSize(), ""); + } else if (memberName == "decodeFunctionParams" || memberName == "decodeStateVars") { + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); + int paramQty = -1; + if (memberName == "decodeFunctionParams") { + CallableDeclaration const *functionDefinition = getFunctionDeclarationOrConstructor( + m_arguments.at(0).get()); + if (functionDefinition) { + + // lvalue.. slice + auto fd = to(functionDefinition); + bool isResponsible = fd->isResponsible(); + if (isResponsible) { + m_pusher.push(-1 + 2, "LDU 32"); + } + // lvalue.. callback slice + ChainDataDecoder decoder{&m_pusher}; + vector types = getParams(functionDefinition->parameters()).first; + decoder.decodePublicFunctionParameters(types, isResponsible, true); - auto retTuple = to(m_retType); - for (Type const* type : retTuple->components()) { - stateVarTypes.push_back(type); - } + paramQty = functionDefinition->parameters().size() + (isResponsible ? 1 : 0); + } + } else if (memberName == "decodeStateVars") { + std::vector stateVarTypes; + auto retTuple = to(m_retType); + for (Type const* type : retTuple->components()) { + stateVarTypes.push_back(type); + } + // lvalue.. slice + ChainDataDecoder decoder{&m_pusher}; + decoder.decodeData(0, 0, stateVarTypes); + // lvalue.. stateVars... - const LValueInfo lValueInfo = - m_exprCompiler.expandLValue(&_node.expression(), true, - *_node.expression().annotation().isLValue); - // lvalue.. slice - ChainDataDecoder decoder{&m_pusher}; - decoder.decodeData(0, 0, stateVarTypes); - const int saveStackSize2 = m_pusher.stackSize(); - const int paramQty = stateVarTypes.size(); - m_pusher.blockSwap(saveStackSize2 - saveStackSize - paramQty, paramQty); - m_pusher.pushSlice("x8_"); + paramQty = stateVarTypes.size(); + } else { + solUnimplemented(""); + } + if (paramQty != -1) { + m_pusher.blockSwap(lValueInfo.stackSizeDiff - 1, paramQty); + m_pusher.pushSlice("x8_"); + } m_exprCompiler.collectLValue(lValueInfo, true, false); } else { solUnimplemented(""); } } - bool FunctionCallCompiler::checkForTvmVectorMethods(MemberAccess const &_node, Type::Category category) { if (category != Type::Category::TvmVector) return false; if (_node.memberName() == "push") { - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); acceptExpr(m_arguments[0].get()); //start callref @@ -1549,7 +1561,7 @@ bool FunctionCallCompiler::checkForTvmVectorMethods(MemberAccess const &_node, T if (_node.memberName() == "pop") { const int stackSize = m_pusher.stackSize(); - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); const int stackChange = m_pusher.stackSize() - stackSize; //start callref @@ -1648,20 +1660,18 @@ bool FunctionCallCompiler::checkForTvmVectorMethods(MemberAccess const &_node, T return false; } -bool FunctionCallCompiler::checkForTvmBuilderMethods(MemberAccess const &_node, Type::Category category) { - if (category != Type::Category::TvmBuilder) - return false; +void FunctionCallCompiler::builderMethods(MemberAccess const &_node) { + ASTString const& memberName = _node.memberName(); + if (boost::starts_with(memberName, "store")) { + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); - if (boost::starts_with(_node.memberName(), "store")) { - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, true); - - if (_node.memberName() == "storeOnes") { + if (memberName == "storeOnes") { pushArgs(); m_pusher.push(-2 + 1, "STONES"); - } else if (_node.memberName() == "storeZeroes") { + } else if (memberName == "storeZeroes") { pushArgs(); m_pusher.push(-2 + 1, "STZEROES"); - } else if (_node.memberName() == "storeRef") { + } else if (memberName == "storeRef") { pushArgAndConvert(0); Type::Category cat = m_arguments.at(0)->annotation().type->category(); switch (cat) { @@ -1679,7 +1689,7 @@ bool FunctionCallCompiler::checkForTvmBuilderMethods(MemberAccess const &_node, default: solUnimplemented(""); } - } else if (_node.memberName() == "store") { + } else if (memberName == "store") { int args = 0; for (const auto &argument: m_arguments | boost::adaptors::reversed) { if (ExprUtils::constBool(*argument)) { @@ -1700,9 +1710,9 @@ bool FunctionCallCompiler::checkForTvmBuilderMethods(MemberAccess const &_node, m_pusher.store(argument->annotation().type->mobileType(), false); } } - } else if (_node.memberName() == "storeSigned" || _node.memberName() == "storeUnsigned") { + } else if (memberName == "storeSigned" || memberName == "storeUnsigned") { std::string cmd = "ST"; - cmd += (_node.memberName() == "storeSigned" ? "I" : "U"); + cmd += (memberName == "storeSigned" ? "I" : "U"); pushArgAndConvert(0); const auto& val = ExprUtils::constValue(*m_arguments[1]); if (val.has_value()) { @@ -1714,73 +1724,48 @@ bool FunctionCallCompiler::checkForTvmBuilderMethods(MemberAccess const &_node, pushArgAndConvert(1); m_pusher.push(-2, cmd + "XR"); } - } else if (_node.memberName() == "storeTons") { + } else if (memberName == "storeTons") { pushArgAndConvert(0); m_pusher.push(-1, "STGRAMS"); + } else if (memberName == "storeSame") { + pushArgs(); + m_pusher << "STSAME"; } else { solUnimplemented(""); } m_exprCompiler.collectLValue(lValueInfo, true, false); - return true; - } - - if (_node.memberName() == "bits") { + } else if (memberName == "bits") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "BBITS"); - return true; - } - - if (_node.memberName() == "refs") { + } else if (memberName == "refs") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "BREFS"); - return true; - } - - if (_node.memberName() == "size") { + } else if (memberName == "size") { acceptExpr(&_node.expression()); m_pusher.push(-1+2, "BBITREFS"); - return true; - } - - if (_node.memberName() == "remBits") { + } else if (memberName == "remBits") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "BREMBITS"); - return true; - } - - if (_node.memberName() == "remRefs") { + } else if (memberName == "remRefs") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "BREMREFS"); - return true; - } - - if (_node.memberName() == "remBitsAndRefs") { + } else if (memberName == "remBitsAndRefs") { acceptExpr(&_node.expression()); m_pusher.push(-1+2, "BREMBITREFS"); - return true; - } - - if (_node.memberName() == "toCell") { + } else if (memberName == "toCell") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "ENDC"); - return true; - } - - if (_node.memberName() == "toSlice") { + } else if (memberName == "toSlice") { acceptExpr(&_node.expression()); m_pusher.push(-1+1, "ENDC"); m_pusher.push(-1+1, "CTOS"); - return true; - } - - if (_node.memberName() == "depth") { + } else if (memberName == "depth") { acceptExpr(&_node.expression()); m_pusher.push(-1 + 1, "BDEPTH"); - return true; + } else { + solUnimplemented(""); } - - return false; } void FunctionCallCompiler::arrayMethods(MemberAccess const &_node) { @@ -1835,7 +1820,7 @@ void FunctionCallCompiler::arrayMethods(MemberAccess const &_node) { pushArgAndConvert(0); cellBitRefQty(); } else if (_node.memberName() == "push") { - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); auto arrayBaseType = to(getType(&_node.expression()))->baseType(); IntegerType const& key = getArrayKeyType(); DataType dataType; @@ -1849,7 +1834,7 @@ void FunctionCallCompiler::arrayMethods(MemberAccess const &_node) { arrayPush(m_pusher, arrayBaseType, dataType); m_exprCompiler.collectLValue(lValueInfo, true, false); } else if (_node.memberName() == "pop") { - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); // arr m_pusher.push(-1 + 2, "UNTUPLE 2"); // size dict m_pusher.pushS(1); // size dict size @@ -1864,7 +1849,7 @@ void FunctionCallCompiler::arrayMethods(MemberAccess const &_node) { m_pusher.push(-2 + 1, "TUPLE 2"); // arr m_exprCompiler.collectLValue(lValueInfo, true, false); } else if (_node.memberName() == "append") { - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), true); pushArgAndConvert(0); m_pusher.pushMacroCallInCallRef(2, 1, "concatenateStrings_macro"); m_exprCompiler.collectLValue(lValueInfo, true, false); @@ -1908,7 +1893,7 @@ bool FunctionCallCompiler::checkForOptionalMethods(MemberAccess const &_node) { } else { rightType = getType(m_arguments.at(0).get()); } - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), false, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), false); pushArgs(false, false); m_pusher.hardConvert(getType(&_node.expression()), rightType); m_exprCompiler.collectLValue(lValueInfo, true, false); @@ -1916,7 +1901,7 @@ bool FunctionCallCompiler::checkForOptionalMethods(MemberAccess const &_node) { } if (_node.memberName() == "reset") { - const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), false, true); + const LValueInfo lValueInfo = m_exprCompiler.expandLValue(&_node.expression(), false); m_pusher.pushDefaultValue(optional); m_exprCompiler.collectLValue(lValueInfo, true, false); return true; @@ -2126,16 +2111,8 @@ bool FunctionCallCompiler::checkForTvmConfigParamFunction(MemberAccess const &_n if (_node.memberName() == "rawConfigParam") { // tvm.rawConfigParam const int stackSize = m_pusher.stackSize(); pushArgAndConvert(0); - m_pusher.startOpaque(); - m_pusher.pushAsym("CONFIGPARAM"); - m_pusher.pushS(0); - m_pusher.startContinuation(); - m_pusher.pushEmptyCell(); - m_pusher.exchange(1); - m_pusher.endContinuation(); - m_pusher.ifNot(); - m_pusher.endOpaque(1, 2); - solAssert(stackSize + 2 == m_pusher.stackSize(), ""); + m_pusher << "CONFIGOPTPARAM"; + solAssert(stackSize + 1 == m_pusher.stackSize(), ""); return true; } if (_node.memberName() == "configParam") { // tvm.configParam @@ -2928,11 +2905,10 @@ bool FunctionCallCompiler::checkLocalFunctionOrLibCall(const Identifier *identif m_pusher.pushInlineFunction(body, take, ret); } else { Declaration const& funDecl = m_funcType->declaration(); - ContractDefinition const* contractDecl= funDecl.annotation().contract; - bool isLib = contractDecl->isLibrary(); + ContractDefinition const* contractDecl = funDecl.annotation().contract; std::string name; auto fd = to(&funDecl); - if (isLib) { + if (contractDecl && contractDecl->isLibrary()) { name = TVMCompilerContext::getLibFunctionName(fd, false); } else { name = m_pusher.ctx().getFunctionInternalName(functionDefinition, false); @@ -2947,21 +2923,6 @@ bool FunctionCallCompiler::checkSolidityUnits() { return false; } - auto checkAndParseExceptionCode = [](Expression const* e) -> std::optional { - const auto& val = ExprUtils::constValue(*e); - if (val.has_value()) { - if (val >= 65536 || val < 0) { - cast_error(*e, "Exception code must be in the range 2 - 65535."); - } - return val; - } - TypeInfo ti{e->annotation().type}; - if (ti.category != Type::Category::Integer || ti.isSigned) { - cast_error(*e, "Exception code must be an unsigned number."); - } - return {}; - }; - switch (m_funcType->kind()) { case FunctionType::Kind::GasToValue: { pushArgs(); @@ -3025,7 +2986,7 @@ bool FunctionCallCompiler::checkSolidityUnits() { } else if (m_arguments.size() == 2 || m_arguments.size() == 3) { if (m_arguments.size() == 3) pushArgAndConvert(2); - const auto &exceptionCode = checkAndParseExceptionCode(m_arguments[1].get()); + const auto &exceptionCode = ExprUtils::constValue(*m_arguments[1].get()); if (exceptionCode.has_value() && exceptionCode.value() <= 1) { cast_error(*m_arguments[1].get(), "Error code must be at least two"); } @@ -3059,7 +3020,7 @@ bool FunctionCallCompiler::checkSolidityUnits() { if (!isIn(static_cast(m_arguments.size()), 1, 2)) { cast_error(m_functionCall, R"("revert" takes up to two m_arguments.)"); } - const auto &exceptionCode = checkAndParseExceptionCode(m_arguments[0].get()); + const auto &exceptionCode = ExprUtils::constValue(*m_arguments[0].get()); bool withArg = m_arguments.size() == 2; if (withArg) { pushArgAndConvert(1); diff --git a/compiler/libsolidity/codegen/TVMFunctionCall.hpp b/compiler/libsolidity/codegen/TVMFunctionCall.hpp index 8e24f468..f6172927 100644 --- a/compiler/libsolidity/codegen/TVMFunctionCall.hpp +++ b/compiler/libsolidity/codegen/TVMFunctionCall.hpp @@ -55,7 +55,7 @@ class FunctionCallCompiler { void sliceMethods(MemberAccess const& _node); void arrayMethods(MemberAccess const& _node); bool checkForOptionalMethods(MemberAccess const& _node); - bool checkForTvmBuilderMethods(MemberAccess const& _node, Type::Category category); + void builderMethods(MemberAccess const& _node); bool checkForTvmVectorMethods(MemberAccess const& _node, Type::Category category); void cellMethods(MemberAccess const& _node); void variantMethods(MemberAccess const& _node); diff --git a/compiler/libsolidity/codegen/TVMPusher.cpp b/compiler/libsolidity/codegen/TVMPusher.cpp index 3f6a1314..453ac55d 100644 --- a/compiler/libsolidity/codegen/TVMPusher.cpp +++ b/compiler/libsolidity/codegen/TVMPusher.cpp @@ -2163,19 +2163,15 @@ Type const* StackPusher::parseValueType(IndexAccess const &indexAccess) { return indexAccess.annotation().type; } -bool StackPusher::tryAssignParam(Declaration const *name) { +void StackPusher::assignStackVariable(Declaration const *name) { auto& stack = getStack(); - if (stack.isParam(name)) { - int idx = stack.getOffset(name); - solAssert(idx >= 0, ""); - if (idx == 0) { - // nothing - } else { - popS(idx); - } - return true; + int idx = stack.getOffset(name); + solAssert(idx >= 0, ""); + if (idx == 0) { + // nothing + } else { + popS(idx); } - return false; } void StackPusher::prepareKeyForDictOperations(Type const *key, bool doIgnoreBytes) { @@ -2571,10 +2567,13 @@ string TVMCompilerContext::getFunctionInternalName(FunctionDefinition const* _fu std::string functionName; const std::string hexName = _function->externalIdentifierHex(); - if (_function->annotation().contract->isLibrary()) { + ContractDefinition const* contract = _function->annotation().contract; + if (contract && contract->isLibrary()) { functionName = getLibFunctionName(_function, calledByPoint); } else if (calledByPoint && isBaseFunction(_function)) { functionName = _function->annotation().contract->name() + "_" + _function->name() + "_" + hexName; + } else if (_function->isFree()) { + functionName = _function->name() + "_" + hexName + "_free_internal"; } else { functionName = _function->name() + "_" + hexName + "_internal"; } diff --git a/compiler/libsolidity/codegen/TVMPusher.hpp b/compiler/libsolidity/codegen/TVMPusher.hpp index 33b070ff..b795e4ae 100644 --- a/compiler/libsolidity/codegen/TVMPusher.hpp +++ b/compiler/libsolidity/codegen/TVMPusher.hpp @@ -305,7 +305,7 @@ class StackPusher { SetDictOperation opcode = SetDictOperation::Set ); - bool tryAssignParam(Declaration const* name); + void assignStackVariable(Declaration const* name); void getDict( const Type& keyType, diff --git a/compiler/libsolidity/codegen/TvmAst.cpp b/compiler/libsolidity/codegen/TvmAst.cpp index ff18f836..447c9c62 100644 --- a/compiler/libsolidity/codegen/TvmAst.cpp +++ b/compiler/libsolidity/codegen/TvmAst.cpp @@ -541,6 +541,7 @@ Pointer gen(const std::string& cmd) { {"BREMBITS", {1, 1, true}}, {"BREMREFS", {1, 1, true}}, {"CDEPTH", {1, 1}}, + {"CONFIGOPTPARAM", {1, 1, true}}, {"CTOS", {1, 1}}, {"DEC", {1, 1}}, {"DICTEMPTY", {1, 1, true}}, @@ -601,6 +602,7 @@ Pointer gen(const std::string& cmd) { {"LDGRAMS", {1, 2}}, {"LDI", {1, 2}}, {"LDMSGADDR", {1, 2}}, + {"LDONES", {1, 2, true}}, {"LDOPTREF", {1, 2}}, {"LDREF", {1, 2}}, {"LDREFRTOS", {1, 2}}, @@ -610,6 +612,7 @@ Pointer gen(const std::string& cmd) { {"LDVARINT32", {1, 2}}, {"LDVARUINT16", {1, 2}}, {"LDVARUINT32", {1, 2}}, + {"LDZEROES", {1, 2, true}}, {"REWRITESTDADDR", {1, 2}}, {"SBITREFS", {1, 2, true}}, {"TPOP", {1, 2}}, @@ -626,6 +629,8 @@ Pointer gen(const std::string& cmd) { {"DIFF_PATCHQ", {2, 1, true}}, {"DIFF_PATCH_BINARY", {2, 1}}, {"DIFF_PATCH_BINARYQ", {2, 1, true}}, + {"DIFF_PATCH_BINARY_ZIP", {2, 1}}, + {"DIFF_PATCH_BINARY_ZIPQ", {2, 1, true}}, {"DIFF_PATCH_ZIP", {2, 1}}, {"DIFF_PATCH_ZIPQ", {2, 1, true}}, {"DIFF_ZIP", {2, 1}}, @@ -638,8 +643,6 @@ Pointer gen(const std::string& cmd) { {"INDEXVAR", {2, 1}}, // only for vector {"LEQ", {2, 1, true}}, {"LESS", {2, 1, true}}, - {"DIFF_PATCH_BINARY_ZIP", {2, 1}}, - {"DIFF_PATCH_BINARY_ZIPQ", {2, 1, true}}, {"MAX", {2, 1, true}}, {"MIN", {2, 1, true}}, {"MOD", {2, 1}}, @@ -683,6 +686,7 @@ Pointer gen(const std::string& cmd) { {"DIVMOD", {2, 2}}, {"LDIX", {2, 2}}, + {"LDSAME", {2, 2, true}}, {"LDSLICEX", {2, 2}}, {"LDUX", {2, 2}}, {"MINMAX", {2, 2, true}}, @@ -703,6 +707,7 @@ Pointer gen(const std::string& cmd) { {"SETINDEXVARQ", {3, 1, true}}, {"SSKIPFIRST", {3, 1}}, {"STIXR", {3, 1}}, + {"STSAME", {3, 1}}, {"STUX", {3, 1}}, {"STUXR", {3, 1}}, diff --git a/compiler/libsolidity/interface/CompilerStack.cpp b/compiler/libsolidity/interface/CompilerStack.cpp index f09f6318..441c7d4b 100644 --- a/compiler/libsolidity/interface/CompilerStack.cpp +++ b/compiler/libsolidity/interface/CompilerStack.cpp @@ -633,17 +633,11 @@ std::pair CompilerStack::compile(bool json) if (m_generateAbi || m_generateCode || m_doPrintFunctionIds || m_doPrivateFunctionIds) { ContractDefinition const *targetContract{}; std::vector targetPragmaDirectives; - std::vector libraries = getAllLibraries(); bool findSrc = false; for (Source const *source: m_sourceOrder) { - // TODO DELETE. IS IT OK? - auto a = boost::filesystem::path(m_inputFile); - boost::filesystem::path aaa = a.filename(); - string curCand = *source->ast->annotation().path; - boost::filesystem::path bbb{curCand}; - - if (aaa != bbb.filename()) { + string curSrcPath = *source->ast->annotation().path; + if (curSrcPath != m_inputFile) { continue; } @@ -721,14 +715,6 @@ std::pair CompilerStack::compile(bool json) ); return {false, didCompileSomething}; } - if (targetContract == nullptr) { - m_errorReporter.typeError( - 228_error, - SourceLocation(), - "Source file doesn't contain any deployable contracts." - ); - return {false, didCompileSomething}; - } if (targetContract != nullptr) { try { @@ -742,7 +728,7 @@ std::pair CompilerStack::compile(bool json) } if (m_generateCode) { Pointer codeContract = - TVMContractCompiler::generateContractCode(targetContract, libraries, pragmaHelper); + TVMContractCompiler::generateContractCode(targetContract, getSourceUnits(), pragmaHelper); ostringstream out; Printer p{out}; codeContract->accept(p); @@ -752,7 +738,7 @@ std::pair CompilerStack::compile(bool json) } else { TVMCompilerProceedContract( *targetContract, - libraries, + getSourceUnits(), &targetPragmaDirectives, m_generateAbi, m_generateCode, @@ -760,7 +746,7 @@ std::pair CompilerStack::compile(bool json) m_folder, m_file_prefix, m_doPrintFunctionIds, - m_doPrivateFunctionIds + m_doPrivateFunctionIds ); } didCompileSomething = true; @@ -790,19 +776,6 @@ vector CompilerStack::contractNames() const return contractNames; } -string const CompilerStack::lastContractName(optional const& _sourceName) const -{ - if (m_stackState < AnalysisPerformed) - solThrow(CompilerError, "Parsing was not successful."); - // try to find some user-supplied contract - string contractName; - for (auto const& it: m_sources) - if (_sourceName.value_or(it.first) == it.first) - for (auto const* contract: ASTNode::filteredNodes(it.second.ast->nodes())) - contractName = contract->fullyQualifiedName(); - return contractName; -} - string const* CompilerStack::sourceMapping(string const& _contractName) const { if (m_stackState != CompilationSuccessful) @@ -949,8 +922,7 @@ Json::Value const& CompilerStack::privateFunctionIds(std::string const& _contrac try { std::vector pragmaDirectives = getPragmaDirectives(&source(sourceName)); PragmaDirectiveHelper pragmaHelper{pragmaDirectives}; - std::vector libraries = getAllLibraries(); - auto functionIds = TVMABI::generatePrivateFunctionIdsJson(*c.contract, libraries, pragmaHelper); + auto functionIds = TVMABI::generatePrivateFunctionIdsJson(*c.contract, getSourceUnits(), pragmaHelper); c.privateFunctionIds = make_unique(functionIds); } catch (...) { // TODO sorry @@ -1246,13 +1218,9 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const { auto it = m_sources.find(_sourceName); - if (it == m_sources.end()) { - it = std::find_if(m_sources.begin(), m_sources.end(), [&_sourceName] (auto it) { - return _sourceName == boost::filesystem::canonical(it.first).string(); - }); - if (it == m_sources.end()) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found.")); - } + if (it == m_sources.end()) + solThrow(CompilerError, "Given source file not found: " + _sourceName); + return it->second; } @@ -1486,16 +1454,10 @@ std::vector CompilerStack::getPragmaDirectives(Source c return pragmaDirectives; } -std::vector CompilerStack::getAllLibraries() const { - std::vector libraries; +std::vector> CompilerStack::getSourceUnits() const { + std::vector> sourceUnits; for (Source const *source: m_sourceOrder) { - for (ASTPointer const &node: source->ast->nodes()) { - if (auto cont = dynamic_cast(node.get())) { - if (cont->isLibrary()) { - libraries.emplace_back(cont); - } - } - } + sourceUnits.push_back(source->ast); } - return libraries; + return sourceUnits; } diff --git a/compiler/libsolidity/interface/CompilerStack.h b/compiler/libsolidity/interface/CompilerStack.h index 2953e52b..67571d6b 100644 --- a/compiler/libsolidity/interface/CompilerStack.h +++ b/compiler/libsolidity/interface/CompilerStack.h @@ -275,9 +275,6 @@ class CompilerStack: public langutil::CharStreamProvider /// @returns a list of the contract names in the sources. std::vector contractNames() const; - /// @returns the name of the last contract. If _sourceName is defined the last contract of that source will be returned. - std::string const lastContractName(std::optional const& _sourceName = std::nullopt) const; - /// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use std::string const filesystemFriendlyName(std::string const& _contractName) const; @@ -450,7 +447,7 @@ class CompilerStack: public langutil::CharStreamProvider ) const; std::vector getPragmaDirectives(Source const* source) const; - std::vector getAllLibraries() const; + std::vector> getSourceUnits() const; ReadCallback::Callback m_readFile; OptimiserSettings m_optimiserSettings; diff --git a/compiler/solc/CommandLineInterface.cpp b/compiler/solc/CommandLineInterface.cpp index 887be10d..c8f31c3a 100644 --- a/compiler/solc/CommandLineInterface.cpp +++ b/compiler/solc/CommandLineInterface.cpp @@ -486,6 +486,9 @@ void CommandLineInterface::compile() } else { + StringMap const& src = m_fileReader.sourceUnits(); + solAssert(src.size() == 1, ""); + m_compiler->setInputFile(src.begin()->first); m_compiler->setSources(m_fileReader.sourceUnits()); m_compiler->setParserErrorRecovery(m_options.input.errorRecovery); } @@ -504,11 +507,6 @@ void CommandLineInterface::compile() m_compiler->printPrivateFunctionIds(); m_compiler->setOutputFolder(m_options.output.dir.string()); - // TODO DELETE make 1 file only, check whether it is remapping - for (const boost::filesystem::path& p : m_options.input.paths) { - m_compiler->setInputFile(p.string()); - } - bool successful = true; bool didCompileSomething = false; std::tie(successful, didCompileSomething) = m_compiler->compile(); @@ -570,14 +568,11 @@ void CommandLineInterface::handleAst() } else { - sout() << "JSON AST (compact format):" << endl << endl; for (auto const& sourceCode: m_fileReader.sourceUnits()) { - sout() << endl << "======= " << sourceCode.first << " =======" << endl; ASTJsonExporter(m_compiler->state(), m_compiler->sourceIndices()).print(sout(), m_compiler->ast(sourceCode.first), m_options.formatting.json); + sout() << endl; } - sout() << endl; - sout() << "]" << endl; m_hasOutput = true; } } diff --git a/compiler/solc/CommandLineParser.cpp b/compiler/solc/CommandLineParser.cpp index 56af7357..0e35cf7c 100644 --- a/compiler/solc/CommandLineParser.cpp +++ b/compiler/solc/CommandLineParser.cpp @@ -548,7 +548,7 @@ General Information)").c_str(), "Use the given path as the root of the source tree instead of the root of the filesystem." ) ( - g_strIncludePath.c_str(), + (g_strIncludePath + ",i").c_str(), po::value>()->value_name("path"), "Make an additional source directory available to the default import callback. " "Use this option if you want to import contracts whose location is not fixed in relation " diff --git a/lib/stdlib_sol.tvm b/lib/stdlib_sol.tvm index b710f010..c4430a64 100644 --- a/lib/stdlib_sol.tvm +++ b/lib/stdlib_sol.tvm @@ -173,17 +173,15 @@ THROWIFNOT 67 PUSHINT 20 PUSHINT 21 CONDSEL -CONFIGPARAM -DUP -PUSHCONT { - PUSHREF { - } - SWAP -} -IFNOT +CONFIGOPTPARAM .loc stdlib.sol, 77 -THROWIFNOT 68 +DUP +ISNULL +THROWIF 68 .loc stdlib.sol, 78 +DUP +ISNULL +THROWIF 63 CTOS .loc stdlib.sol, 79 LDU 8 @@ -1527,8 +1525,8 @@ PUSHCONT { .loc stdlib.sol, 333 PUSH S3 LDU 8 - POP S5 - DROP + NIP + POP S4 .loc stdlib.sol, 0 } IF @@ -1539,8 +1537,8 @@ PUSHCONT { PUSH S3 LDU 8 LDU 8 - POP S6 - DROP2 + BLKDROP2 2, 1 + POP S4 .loc stdlib.sol, 0 } IF diff --git a/sold/Cargo.toml b/sold/Cargo.toml index 034fc2c1..ce7144ff 100644 --- a/sold/Cargo.toml +++ b/sold/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = '2021' name = 'sold' -version = '0.67.0' +version = '0.68.0' [[bin]] name = 'sold' @@ -11,23 +11,22 @@ path = 'src/main.rs' atty = '0.2' dunce = '1.0' failure = '0.1' -once_cell = '1.10' +once_cell = '1.17' serde_json = { features = [ 'unbounded_depth' ], version = '1.0' } -strip-ansi-escapes = '0.1.1' -clap = { features = [ 'derive' ], version = '4.1' } +strip-ansi-escapes = '0.1' +clap = { features = [ 'derive' ], version = '4.2' } serde = { features = [ 'derive' ], version = '1.0' } -ton_abi = { git = 'https://github.com/tonlabs/ton-labs-abi.git', tag = '2.3.60' } -ton_block = { git = 'https://github.com/tonlabs/ton-labs-block.git', tag = '1.9.22' } -ton_types = { git = 'https://github.com/tonlabs/ton-labs-types.git', tag = '1.12.6' } -tvm_linker = { git = 'https://github.com/tonlabs/TVM-linker.git', tag = '0.19.5' } +ton_abi = { git = 'https://github.com/tonlabs/ever-abi.git', tag = '2.3.80' } +ton_block = { git = 'https://github.com/tonlabs/ever-block.git', tag = '1.9.43' } +ton_types = { git = 'https://github.com/tonlabs/ever-types.git', tag = '2.0.2' } +tvm_linker = { git = 'https://github.com/tonlabs/TVM-linker.git', tag = '0.20.1' } [build-dependencies] -# bindgen = '0.64' cmake = '0.1' [dev-dependencies] -assert_cmd = '2.0.4' -predicates = '2.1.1' +assert_cmd = '2.0' +predicates = "3.0" [lib] name = 'sold_lib' diff --git a/sold/src/lib.rs b/sold/src/lib.rs index ee1a39e3..359e3e0c 100644 --- a/sold/src/lib.rs +++ b/sold/src/lib.rs @@ -8,7 +8,7 @@ use failure::{bail, format_err}; use serde::Deserialize; use ton_block::Serializable; -use ton_types::{BagOfCells, Result, SliceData, Status}; +use ton_types::{Result, SliceData, Status}; use ton_utils::parser::{ParseEngine, ParseEngineInput}; use ton_utils::program::Program; @@ -97,11 +97,16 @@ fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, } else { "" }; - let assembly = if args.abi_json || args.ast_compact_json { + let assembly = if args.abi_json || args.ast_compact_json || args.userdoc || args.devdoc { "" } else { ", \"assembly\"" }; + let doc = if args.userdoc || args.devdoc { + ", \"userdoc\", \"devdoc\"" + } else { + "" + }; let main_contract = args.contract.clone().unwrap_or_default(); let remappings = remappings_to_json_string(remappings); let input_json = format!(r#" @@ -112,7 +117,7 @@ fn compile(args: &Args, input: &str, remappings: Vec) -> Result<(String, "remappings": {remappings}, "outputSelection": {{ "{source_unit_name}": {{ - "*": [ "abi"{assembly}{show_function_ids}{show_private_function_ids} ], + "*": [ "abi"{assembly}{show_function_ids}{show_private_function_ids}{doc} ], "": [ "ast" ] }} }} @@ -158,6 +163,8 @@ macro_rules! parse_error { }; } +pub static ERROR_MSG_NO_OUTPUT: &str = "Compiler run successful, no output requested."; + fn parse_comp_result( res: &serde_json::Value, source_unit_name: &str, @@ -165,6 +172,7 @@ fn parse_comp_result( compile: bool, ) -> Result { let res = res.as_object().ok_or_else(|| parse_error!())?; + // println!("{}", serde_json::to_string_pretty(&res)?); if let Some(v) = res.get("errors") { let entries = v.as_array() @@ -230,11 +238,15 @@ fn parse_comp_result( } }); let qualification = if compile { "deployable " } else { "" }; - let entry = iter.next().unwrap(); - if iter.next().is_some() { - Err(format_err!("Source file contains at least two {}contracts. Consider adding the option --contract in compiler command line to select the desired contract", qualification)) + let entry = iter.next(); + if let Some(entry) = entry { + if iter.next().is_some() { + Err(format_err!("Source file contains at least two {}contracts. Consider adding the option --contract in compiler command line to select the desired contract", qualification)) + } else { + Ok(entry.1.clone()) + } } else { - Ok(entry.1.clone()) + Err(format_err!("{}", ERROR_MSG_NO_OUTPUT)) } } } @@ -285,7 +297,7 @@ pub fn build(args: Args) -> Status { &res.1, &res.0, args.contract, - !(args.abi_json || args.ast_compact_json) + !(args.abi_json || args.ast_compact_json || args.userdoc || args.devdoc ) )?; if args.function_ids { @@ -306,6 +318,18 @@ pub fn build(args: Args) -> Status { let output_prefix = args.output_prefix.unwrap_or(input_file_stem); let output_tvc = format!("{}.tvc", output_prefix); + if args.userdoc || args.devdoc { + if args.devdoc { + println!("Developer Documentation"); + println!("{}", serde_json::to_string_pretty(&out["devdoc"])?); + } + if args.userdoc { + println!("User Documentation"); + println!("{}", serde_json::to_string_pretty(&out["userdoc"])?); + } + return Ok(()) + } + if args.ast_compact_json { let all = res.1.as_object() .ok_or_else(|| parse_error!())? @@ -323,13 +347,8 @@ pub fn build(args: Args) -> Status { .ok_or_else(|| parse_error!())?; array.push(ast.clone()); } - - let ast = serde_json::Value::Array(array); - let ast_file_name = format!("{}.ast.json", output_prefix); - let mut ast_file = File::create(output_path.join(&ast_file_name))?; - - serde_json::to_writer(&mut ast_file, &ast)?; - writeln!(ast_file)?; + assert!(array.len() == 1); + println!("{}", serde_json::to_string(&array[0])?); return Ok(()) } @@ -358,7 +377,7 @@ pub fn build(args: Args) -> Status { } inputs.push(ParseEngineInput { buf: Box::new(assembly.as_bytes()), name: format!("{}/{}", output_dir, assembly_file_name) }); - let mut prog = Program::new(ParseEngine::new_generic(inputs, Some(format!("{}", abi)))?); + let mut prog = Program::new(ParseEngine::new_generic(inputs, Some(format!("{}", abi)))?)?; let output_filename = if output_dir == "." { @@ -391,8 +410,7 @@ pub fn build(args: Args) -> Status { state.set_data(new_data.into_cell()); let root_cell = state.write_to_new_cell()?.into_cell()?; - let mut buffer = vec![]; - BagOfCells::with_root(&root_cell).write_to(&mut buffer, false)?; + let buffer = ton_types::write_boc(&root_cell)?; let mut file = File::create(&output_filename)?; file.write_all(&buffer)?; @@ -458,6 +476,12 @@ pub struct Args { /// AST of all source files in a compact JSON format #[clap(long, value_parser)] pub ast_compact_json: bool, + /// Natspec user documentation of all contracts. + #[clap(long, value_parser)] + pub userdoc: bool, + /// Natspec developer documentation of all contracts. + #[clap(long, value_parser)] + pub devdoc: bool, // TODO ? /// Set newly generated keypair diff --git a/sold/src/main.rs b/sold/src/main.rs index e30be2a1..13c4e813 100644 --- a/sold/src/main.rs +++ b/sold/src/main.rs @@ -12,7 +12,7 @@ */ use clap::Parser; -use sold_lib::{Args, VERSION, build, solidity_version}; +use sold_lib::{Args, VERSION, ERROR_MSG_NO_OUTPUT, build, solidity_version}; mod libsolc; @@ -22,6 +22,8 @@ fn main() { let args = Args::parse(); if let Err(e) = build(args) { eprintln!("{}", e); - std::process::exit(1); + if e.to_string() != ERROR_MSG_NO_OUTPUT { + std::process::exit(1); + } } } diff --git a/sold/tests/tests.rs b/sold/tests/tests.rs index aaf36629..ecffa2f9 100644 --- a/sold/tests/tests.rs +++ b/sold/tests/tests.rs @@ -102,8 +102,9 @@ fn test_library() -> Status { .arg("--output-dir") .arg("tests") .assert() - .failure() - .stderr(predicate::str::contains("Source file doesn't contain any deployable contracts.")); + .success() + .stderr(predicate::str::contains("Compiler run successful, no output requested.")) + ; Ok(()) } @@ -217,3 +218,27 @@ fn test_remapping() -> Status { remove_all_outputs("ImportRemote")?; Ok(()) } + +#[test] +fn test_userdoc_devdoc() -> Status { + Command::cargo_bin(BIN_NAME)? + .arg("tests/Trivial.sol") + .arg("--userdoc") + .arg("--devdoc") + .assert() + .success() + .stdout(predicate::str::contains(r#"Developer Documentation +{ + "kind": "dev", + "methods": {}, + "version": 1 +} +User Documentation +{ + "kind": "user", + "methods": {}, + "version": 1 +} +"#)); + Ok(()) +}