-
Notifications
You must be signed in to change notification settings - Fork 761
Expand file tree
/
Copy pathmod.rs
More file actions
3739 lines (3382 loc) · 172 KB
/
Copy pathmod.rs
File metadata and controls
3739 lines (3382 loc) · 172 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
// Copyright (C) 2020 Stacks Open Internet Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use super::types::signatures::{FunctionArgSignature, FunctionReturnsSignature};
use crate::vm::analysis::type_checker::v2_1::natives::SimpleNativeFunction;
use crate::vm::analysis::type_checker::v2_1::TypedNativeFunction;
use crate::vm::functions::define::DefineFunctions;
use crate::vm::functions::NativeFunctions;
use crate::vm::types::{FixedFunction, FunctionType};
use crate::vm::variables::NativeVariables;
use crate::vm::ClarityVersion;
#[cfg(feature = "rusqlite")]
pub mod contracts;
#[derive(Serialize)]
struct ReferenceAPIs {
functions: Vec<FunctionAPI>,
keywords: Vec<KeywordAPI>,
}
#[derive(Serialize, Clone)]
pub struct KeywordAPI {
pub name: &'static str,
pub snippet: &'static str,
pub output_type: &'static str,
pub description: &'static str,
pub example: &'static str,
/// The version where this keyword was first introduced.
pub min_version: ClarityVersion,
/// The version where this keyword was disabled.
pub max_version: Option<ClarityVersion>,
}
#[derive(Serialize, Clone)]
struct SimpleKeywordAPI {
name: &'static str,
snippet: &'static str,
output_type: &'static str,
description: &'static str,
example: &'static str,
}
#[derive(Serialize)]
pub struct FunctionAPI {
pub name: String,
pub snippet: String,
pub input_type: String,
pub output_type: String,
pub signature: String,
pub description: String,
pub example: String,
/// The version where this keyword was first introduced.
pub min_version: ClarityVersion,
/// The version where this keyword was disabled.
pub max_version: Option<ClarityVersion>,
}
pub struct SimpleFunctionAPI {
name: Option<&'static str>,
snippet: &'static str,
signature: &'static str,
description: &'static str,
example: &'static str,
}
struct SpecialAPI {
output_type: &'static str,
snippet: &'static str,
input_type: &'static str,
signature: &'static str,
description: &'static str,
example: &'static str,
}
pub struct DefineAPI {
output_type: &'static str,
snippet: &'static str,
input_type: &'static str,
signature: &'static str,
description: &'static str,
example: &'static str,
}
const BLOCK_HEIGHT: SimpleKeywordAPI = SimpleKeywordAPI {
name: "block-height",
snippet: "block-height",
output_type: "uint",
description: "Returns the current block height of the Stacks blockchain in Clarity 1 and 2.
Upon activation of epoch 3.0, `block-height` will return the same value as `tenure-height`.
In Clarity 3, `block-height` is removed and has been replaced with `stacks-block-height`.",
example:
"(> block-height u1000) ;; returns true if the current block-height has passed 1000 blocks.",
};
const BURN_BLOCK_HEIGHT: SimpleKeywordAPI = SimpleKeywordAPI {
name: "burn-block-height",
snippet: "burn-block-height",
output_type: "uint",
description: "Returns the current block height of the underlying burn blockchain.",
example: "(> burn-block-height u832000) ;; returns true if the current height of the underlying burn blockchain has passed 832,000 blocks.",
};
const CONTRACT_CALLER_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "contract-caller",
snippet: "contract-caller",
output_type: "principal",
description: "Returns the caller of the current contract context. If this contract is the first one called by a signed transaction,
the caller will be equal to the signing principal. If `contract-call?` was used to invoke a function from a new contract, `contract-caller`
changes to the _calling_ contract's principal. If `as-contract` is used to change the `tx-sender` context, `contract-caller` _also_ changes
to the same contract principal.",
example: "(print contract-caller) ;; Will print out a Stacks address of the transaction sender",
};
const CURRENT_CONTRACT_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "current-contract",
snippet: "current-contract",
output_type: "principal",
description: "Returns the principal of the current contract.",
example:
"(print current-contract) ;; Will print out the Stacks address of the current contract",
};
const STACKS_BLOCK_HEIGHT_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "stacks-block-height",
snippet: "stacks-block-height",
output_type: "uint",
description: "Returns the current block height of the Stacks blockchain.",
example: "(<= stacks-block-height u500000) ;; returns true if the current block-height has not passed 500,000 blocks.",
};
const TENURE_HEIGHT_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "tenure-height",
snippet: "tenure-height",
output_type: "uint",
description: "Returns the number of tenures that have passed.
At the start of epoch 3.0, `tenure-height` will return the same value as `block-height`, then it will continue to increase as each tenures passes.",
example:
"(< tenure-height u140000) ;; returns true if the current tenure-height has passed 140,000 blocks.",
};
const BLOCK_TIME_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "stacks-block-time",
snippet: "stacks-block-time",
output_type: "uint",
description: "Returns the Unix timestamp (in seconds) of the current Stacks block. Introduced
in Clarity 4. Provides access to the timestamp of the current block, which is
not available with `get-stacks-block-info?`.",
example: "(>= stacks-block-time u1755820800) ;; returns true if current block timestamp is at or after 2025-07-22.",
};
const TX_SENDER_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "tx-sender",
snippet: "tx-sender",
output_type: "principal",
description: "Returns the original sender of the current transaction, or if `as-contract` was called to modify the sending context, it returns that
contract principal.",
example: "(print tx-sender) ;; Will print out a Stacks address of the transaction sender",
};
const TX_SPONSOR_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "tx-sponsor?",
snippet: "tx-sponsor?",
output_type: "optional principal",
description: "Returns the sponsor of the current transaction if there is a sponsor, otherwise returns None.",
example: "(print tx-sponsor?) ;; Will print out an optional value containing the Stacks address of the transaction sponsor",
};
const TOTAL_LIQUID_USTX_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "stx-liquid-supply",
snippet: "stx-liquid-supply",
output_type: "uint",
description: "Returns the total number of micro-STX (uSTX) that are liquid in the system as of this block.",
example: "(print stx-liquid-supply) ;; Will print out the total number of liquid uSTX",
};
const REGTEST_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "is-in-regtest",
snippet: "is-in-regtest",
output_type: "bool",
description: "Returns whether or not the code is running in a regression test",
example:
"(print is-in-regtest) ;; Will print 'true' if the code is running in a regression test",
};
const MAINNET_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "is-in-mainnet",
snippet: "is-in-mainnet",
output_type: "bool",
description: "Returns a boolean indicating whether or not the code is running on the mainnet",
example: "(print is-in-mainnet) ;; Will print 'true' if the code is running on the mainnet",
};
const CHAINID_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "chain-id",
snippet: "chain-id",
output_type: "uint",
description: "Returns the 32-bit chain ID of the blockchain running this transaction",
example: "(print chain-id) ;; Will print 'u1' if the code is running on mainnet, and 'u2147483648' on testnet, and other values on different chains.",
};
const NONE_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "none",
snippet: "none",
output_type: "(optional ?)",
description: "Represents the _none_ option indicating no value for a given optional (analogous to a null value).",
example: "
(define-public (only-if-positive (a int))
(if (> a 0)
(some a)
none))
(only-if-positive 4) ;; Returns (some 4)
(only-if-positive (- 3)) ;; Returns none
",
};
const TRUE_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "true",
snippet: "true",
output_type: "bool",
description: "Boolean true constant.",
example: "
(and true false) ;; Evaluates to false
(or false true) ;; Evaluates to true
",
};
const FALSE_KEYWORD: SimpleKeywordAPI = SimpleKeywordAPI {
name: "false",
snippet: "false",
output_type: "bool",
description: "Boolean false constant.",
example: "
(and true false) ;; Evaluates to false
(or false true) ;; Evaluates to true
",
};
const TO_UINT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "to-uint ${1:int}",
signature: "(to-uint i)",
description: "Tries to convert the `int` argument to a `uint`. Will cause a runtime error and abort if the supplied argument is negative.",
example: "(to-uint 238) ;; Returns u238",
};
const TO_INT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "to-int ${1:uint}",
signature: "(to-int u)",
description: "Tries to convert the `uint` argument to an `int`. Will cause a runtime error and abort if the supplied argument is >= `pow(2, 127)`",
example: "(to-int u238) ;; Returns 238",
};
const BUFF_TO_INT_LE_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "buff-to-int-le ${1:buff}",
signature: "(buff-to-int-le (buff 16))",
description: "Converts a byte buffer to a signed integer use a little-endian encoding.
The byte buffer can be up to 16 bytes in length. If there are fewer than 16 bytes, as
this function uses a little-endian encoding, the input behaves as if it is
zero-padded on the _right_.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(buff-to-int-le 0x01) ;; Returns 1
(buff-to-int-le 0x01000000000000000000000000000000) ;; Returns 1
(buff-to-int-le 0xffffffffffffffffffffffffffffffff) ;; Returns -1
(buff-to-int-le 0x) ;; Returns 0
"#,
};
const BUFF_TO_UINT_LE_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "buff-to-uint-le ${1:buff}",
signature: "(buff-to-uint-le (buff 16))",
description: "Converts a byte buffer to an unsigned integer use a little-endian encoding.
The byte buffer can be up to 16 bytes in length. If there are fewer than 16 bytes, as
this function uses a little-endian encoding, the input behaves as if it is
zero-padded on the _right_.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(buff-to-uint-le 0x01) ;; Returns u1
(buff-to-uint-le 0x01000000000000000000000000000000) ;; Returns u1
(buff-to-uint-le 0xffffffffffffffffffffffffffffffff) ;; Returns u340282366920938463463374607431768211455
(buff-to-uint-le 0x) ;; Returns u0
"#,
};
const BUFF_TO_INT_BE_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "buff-to-int-be ${1:buff}",
signature: "(buff-to-int-be (buff 16))",
description: "Converts a byte buffer to a signed integer use a big-endian encoding.
The byte buffer can be up to 16 bytes in length. If there are fewer than 16 bytes, as
this function uses a big-endian encoding, the input behaves as if it is
zero-padded on the _left_.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(buff-to-int-be 0x01) ;; Returns 1
(buff-to-int-be 0x00000000000000000000000000000001) ;; Returns 1
(buff-to-int-be 0xffffffffffffffffffffffffffffffff) ;; Returns -1
(buff-to-int-be 0x) ;; Returns 0
"#,
};
const BUFF_TO_UINT_BE_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "buff-to-uint-be ${1:buff}",
signature: "(buff-to-uint-be (buff 16))",
description: "Converts a byte buffer to an unsigned integer use a big-endian encoding.
The byte buffer can be up to 16 bytes in length. If there are fewer than 16 bytes, as
this function uses a big-endian encoding, the input behaves as if it is
zero-padded on the _left_.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(buff-to-uint-be 0x01) ;; Returns u1
(buff-to-uint-be 0x00000000000000000000000000000001) ;; Returns u1
(buff-to-uint-be 0xffffffffffffffffffffffffffffffff) ;; Returns u340282366920938463463374607431768211455
(buff-to-uint-be 0x) ;; Returns u0
"#,
};
const IS_STANDARD_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "is-standard ${1:principal}",
signature: "(is-standard standard-or-contract-principal)",
description: "Tests whether `standard-or-contract-principal` _matches_ the current network
type, and therefore represents a principal that can spend tokens on the current
network type. That is, the network is either of type `mainnet`, or `testnet`.
Only `SPxxxx` and `SMxxxx` _c32check form_ addresses can spend tokens on
a mainnet, whereas only `STxxxx` and `SNxxxx` _c32check forms_ addresses can spend
tokens on a testnet. All addresses can _receive_ tokens, but only principal
_c32check form_ addresses that match the network type can _spend_ tokens on the
network. This method will return `true` if and only if the principal matches
the network type, and false otherwise.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(is-standard 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6) ;; returns true on testnet and false on mainnet
(is-standard 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6.foo) ;; returns true on testnet and false on mainnet
(is-standard 'SP3X6QWWETNBZWGBK6DRGTR1KX50S74D3433WDGJY) ;; returns true on mainnet and false on testnet
(is-standard 'SP3X6QWWETNBZWGBK6DRGTR1KX50S74D3433WDGJY.foo) ;; returns true on mainnet and false on testnet
(is-standard 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR) ;; returns false on both mainnet and testnet
"#,
};
const PRINCPIPAL_DESTRUCT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "principal-destruct? ${1:principal-address}",
signature: "(principal-destruct? principal-address)",
description: "A principal value represents either a set of keys, or a smart contract.
The former, called a _standard principal_,
is encoded as a `(buff 1)` *version byte*, indicating the type of account
and the type of network that this principal can spend tokens on,
and a `(buff 20)` *public key hash*, characterizing the principal's unique identity.
The latter, a _contract principal_, is encoded as a standard principal concatenated with
a `(string-ascii 40)` *contract name* that identifies the code body.
`principal-destruct?` will decompose a principal into its component parts: either`{version-byte, hash-bytes}`
for standard principals, or `{version-byte, hash-bytes, name}` for contract principals.
This method returns a `Response` that wraps this data as a tuple.
If the version byte of `principal-address` matches the network (see `is-standard`), then this method
returns the pair as its `ok` value.
If the version byte of `principal-address` does not match the network, then this method
returns the pair as its `err` value.
In both cases, the value itself is a tuple containing three fields: a `version` value as a `(buff 1)`,
a `hash-bytes` value as a `(buff 20)`, and a `name` value as an `(optional (string-ascii 40))`. The `name`
field will only be `(some ..)` if the principal is a contract principal.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(principal-destruct? 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6) ;; Returns (ok (tuple (hash-bytes 0x164247d6f2b425ac5771423ae6c80c754f7172b0) (name none) (version 0x1a)))
(principal-destruct? 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6.foo) ;; Returns (ok (tuple (hash-bytes 0x164247d6f2b425ac5771423ae6c80c754f7172b0) (name (some "foo")) (version 0x1a)))
(principal-destruct? 'SP3X6QWWETNBZWGBK6DRGTR1KX50S74D3433WDGJY) ;; Returns (err (tuple (hash-bytes 0xfa6bf38ed557fe417333710d6033e9419391a320) (name none) (version 0x16)))
(principal-destruct? 'SP3X6QWWETNBZWGBK6DRGTR1KX50S74D3433WDGJY.foo) ;; Returns (err (tuple (hash-bytes 0xfa6bf38ed557fe417333710d6033e9419391a320) (name (some "foo")) (version 0x16)))
"#,
};
const STRING_TO_INT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "string-to-int? ${1:string}",
signature: "(string-to-int? (string-ascii|string-utf8))",
description: "Converts a string, either `string-ascii` or `string-utf8`, to an optional-wrapped signed integer.
If the input string does not represent a valid integer, then the function returns `none`. Otherwise it returns
an integer wrapped in `some`.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(string-to-int? "1") ;; Returns (some 1)
(string-to-int? u"-1") ;; Returns (some -1)
(string-to-int? "a") ;; Returns none
"#,
};
const STRING_TO_UINT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "string-to-uint? ${1:string}",
signature: "(string-to-uint? (string-ascii|string-utf8))",
description:
"Converts a string, either `string-ascii` or `string-utf8`, to an optional-wrapped unsigned integer.
If the input string does not represent a valid integer, then the function returns `none`. Otherwise it returns
an unsigned integer wrapped in `some`.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(string-to-uint? "1") ;; Returns (some u1)
(string-to-uint? u"1") ;; Returns (some u1)
(string-to-uint? "a") ;; Returns none
"#,
};
const INT_TO_ASCII_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "int-to-ascii ${1:num}",
signature: "(int-to-ascii (int|uint))",
description: "Converts an integer, either `int` or `uint`, to a `string-ascii` string-value representation.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(int-to-ascii 1) ;; Returns "1"
(int-to-ascii u1) ;; Returns "1"
(int-to-ascii -1) ;; Returns "-1"
"#,
};
const INT_TO_UTF8_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "int-to-utf8 ${1:num}",
signature: "(int-to-utf8 (int|uint))",
description: "Converts an integer, either `int` or `uint`, to a `string-utf8` string-value representation.
Note: This function is only available starting with Stacks 2.1.",
example: r#"
(int-to-utf8 1) ;; Returns u"1"
(int-to-utf8 u1) ;; Returns u"1"
(int-to-utf8 -1) ;; Returns u"-1"
"#,
};
const ADD_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("+ (add)"),
snippet: "+ ${1:expr-1} ${2:expr-2}",
signature: "(+ i1 i2...)",
description: "Adds a variable number of integer inputs and returns the result. In the event of an _overflow_, throws a runtime error.",
example: "(+ 1 2 3) ;; Returns 6",
};
const SUB_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("- (subtract)"),
snippet: "- ${1:expr-1} ${2:expr-2}",
signature: "(- i1 i2...)",
description: "Subtracts a variable number of integer inputs and returns the result. In the event of an _underflow_, throws a runtime error.",
example: "(- 2 1 1) ;; Returns 0
(- 0 3) ;; Returns -3
",
};
const DIV_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("/ (divide)"),
snippet: "/ ${1:expr-1} ${2:expr-2}",
signature: "(/ i1 i2...)",
description: "Integer divides a variable number of integer inputs and returns the result. In the event of division by zero, throws a runtime error.",
example: "(/ 2 3) ;; Returns 0
(/ 5 2) ;; Returns 2
(/ 4 2 2) ;; Returns 1
",
};
const MUL_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("* (multiply)"),
snippet: "* ${1:expr-1} ${2:expr-2}",
signature: "(* i1 i2...)",
description: "Multiplies a variable number of integer inputs and returns the result. In the event of an _overflow_, throws a runtime error.",
example: "(* 2 3) ;; Returns 6
(* 5 2) ;; Returns 10
(* 2 2 2) ;; Returns 8
",
};
const MOD_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "mod ${1:expr-1} ${2:expr-2}",
signature: "(mod i1 i2)",
description: "Returns the integer remainder from integer dividing `i1` by `i2`. In the event of a division by zero, throws a runtime error.",
example: "(mod 2 3) ;; Returns 2
(mod 5 2) ;; Returns 1
(mod 7 1) ;; Returns 0
",
};
const POW_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "pow ${1:expr-1} ${2:expr-2}",
signature: "(pow i1 i2)",
description: "Returns the result of raising `i1` to the power of `i2`. In the event of an _overflow_, throws a runtime error.
Note: Corner cases are handled with the following rules:
* if both `i1` and `i2` are `0`, return `1`
* if `i1` is `1`, return `1`
* if `i1` is `0`, return `0`
* if `i2` is negative or greater than `u32::MAX`, throw a runtime error",
example: "(pow 2 3) ;; Returns 8
(pow 2 2) ;; Returns 4
(pow 7 1) ;; Returns 7
"
};
const SQRTI_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "sqrti ${1:expr-1}",
signature: "(sqrti n)",
description: "Returns the largest integer that is less than or equal to the square root of `n`.
Fails on a negative numbers.
",
example: "(sqrti u11) ;; Returns u3
(sqrti 1000000) ;; Returns 1000
(sqrti u1) ;; Returns u1
(sqrti 0) ;; Returns 0
",
};
const LOG2_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "log2 ${1:expr-1}",
signature: "(log2 n)",
description:
"Returns the power to which the number 2 must be raised to obtain the value `n`, rounded
down to the nearest integer. Fails on a negative numbers.
",
example: "(log2 u8) ;; Returns u3
(log2 8) ;; Returns 3
(log2 u1) ;; Returns u0
(log2 1000) ;; Returns 9
",
};
const XOR_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "xor ${1:expr-1} ${2:expr-2}",
signature: "(xor i1 i2)",
description: "Returns the result of bitwise exclusive or'ing `i1` with `i2`.",
example: "(xor 1 2) ;; Returns 3
(xor 120 280) ;; Returns 352
",
};
const BITWISE_XOR_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "bit-xor ${1:expr-1} ${2:expr-2}",
signature: "(bit-xor i1 i2...)",
description:
"Returns the result of bitwise exclusive or'ing a variable number of integer inputs.",
example: "(bit-xor 1 2) ;; Returns 3
(bit-xor 120 280) ;; Returns 352
(bit-xor -128 64) ;; Returns -64
(bit-xor u24 u4) ;; Returns u28
(bit-xor 1 2 4 -1) ;; Returns -8
",
};
const BITWISE_AND_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "bit-and ${1:expr-1} ${2:expr-2}",
signature: "(bit-and i1 i2...)",
description: "Returns the result of bitwise and'ing a variable number of integer inputs.",
example: "(bit-and 24 16) ;; Returns 16
(bit-and 28 24 -1) ;; Returns 24
(bit-and u24 u16) ;; Returns u16
(bit-and -128 -64) ;; Returns -128
(bit-and 28 24 -1) ;; Returns 24
",
};
const BITWISE_OR_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "bit-or ${1:expr-1} ${2:expr-2}",
signature: "(bit-or i1 i2...)",
description:
"Returns the result of bitwise inclusive or'ing a variable number of integer inputs.",
example: "(bit-or 4 8) ;; Returns 12
(bit-or 1 2 4) ;; Returns 7
(bit-or 64 -32 -16) ;; Returns -16
(bit-or u2 u4 u32) ;; Returns u38
",
};
const BITWISE_NOT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "bit-not ${1:expr-1}",
signature: "(bit-not i1)",
description: "Returns the one's compliement (sometimes also called the bitwise compliment or not operator) of `i1`, effectively reversing the bits in `i1`.
In other words, every bit that is `1` in `ì1` will be `0` in the result. Conversely, every bit that is `0` in `i1` will be `1` in the result.
",
example: "(bit-not 3) ;; Returns -4
(bit-not u128) ;; Returns u340282366920938463463374607431768211327
(bit-not 128) ;; Returns -129
(bit-not -128) ;; Returns 127
"
};
const BITWISE_LEFT_SHIFT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "bit-shift-left ${1:expr-1} ${2:expr-2}",
signature: "(bit-shift-left i1 shamt)",
description: "Shifts all the bits in `i1` to the left by the number of places specified in `shamt` modulo 128 (the bit width of Clarity integers).
Note that there is a deliberate choice made to ignore arithmetic overflow for this operation. In use cases where overflow should be detected, developers
should use `*`, `/`, and `pow` instead of the shift operators.
",
example: "(bit-shift-left 2 u1) ;; Returns 4
(bit-shift-left 16 u2) ;; Returns 64
(bit-shift-left -64 u1) ;; Returns -128
(bit-shift-left u4 u2) ;; Returns u16
(bit-shift-left 123 u9999999999) ;; Returns -170141183460469231731687303715884105728
(bit-shift-left u123 u9999999999) ;; Returns u170141183460469231731687303715884105728
(bit-shift-left -1 u7) ;; Returns -128
(bit-shift-left -1 u128) ;; Returns -1
"
};
const BITWISE_RIGHT_SHIFT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "bit-shift-right ${1:expr-1} ${2:expr-2}",
signature: "(bit-shift-right i1 shamt)",
description: "Shifts all the bits in `i1` to the right by the number of places specified in `shamt` modulo 128 (the bit width of Clarity integers).
When `i1` is a `uint` (unsigned), new bits are filled with zeros. When `i1` is an `int` (signed), the sign is preserved, meaning that new bits are filled with the value of the previous sign-bit.
Note that there is a deliberate choice made to ignore arithmetic overflow for this operation. In use cases where overflow should be detected, developers should use `*`, `/`, and `pow` instead of the shift operators.
",
example: "(bit-shift-right 2 u1) ;; Returns 1
(bit-shift-right 128 u2) ;; Returns 32
(bit-shift-right -64 u1) ;; Returns -32
(bit-shift-right u128 u2) ;; Returns u32
(bit-shift-right 123 u9999999999) ;; Returns 0
(bit-shift-right u123 u9999999999) ;; Returns u0
(bit-shift-right -128 u7) ;; Returns -1
(bit-shift-right -256 u1) ;; Returns -128
(bit-shift-right 5 u2) ;; Returns 1
(bit-shift-right -5 u2) ;; Returns -2
"
};
const AND_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "and ${1:expr-1} ${2:expr-2}",
signature: "(and b1 b2 ...)",
description: "Returns `true` if all boolean inputs are `true`. Importantly, the supplied arguments are
evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns `false`, the function
short-circuits, and no subsequent arguments are evaluated.
",
example: "(and true false) ;; Returns false
(and (is-eq (+ 1 2) 1) (is-eq 4 4)) ;; Returns false
(and (is-eq (+ 1 2) 3) (is-eq 4 4)) ;; Returns true
"
};
const OR_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "or ${1:expr-1} ${2:expr-2}",
signature: "(or b1 b2 ...)",
description: "Returns `true` if any boolean inputs are `true`. Importantly, the supplied arguments are
evaluated in-order and lazily. Lazy evaluation means that if one of the arguments returns `true`, the function
short-circuits, and no subsequent arguments are evaluated.",
example: "(or true false) ;; Returns true
(or (is-eq (+ 1 2) 1) (is-eq 4 4)) ;; Returns true
(or (is-eq (+ 1 2) 1) (is-eq 3 4)) ;; Returns false
(or (is-eq (+ 1 2) 3) (is-eq 4 4)) ;; Returns true
"
};
const NOT_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: None,
snippet: "not ${1:expr-1}",
signature: "(not b1)",
description: "Returns the inverse of the boolean input.",
example: "(not true) ;; Returns false
(not (is-eq 1 2)) ;; Returns true
",
};
const GEQ_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some(">= (greater than or equal)"),
snippet: ">= ${1:expr-1} ${2:expr-2}",
signature: "(>= i1 i2)",
description: "Compares two integers, returning `true` if `i1` is greater than or equal to `i2` and `false` otherwise.
i1 and i2 must be of the same type. Starting with Stacks 1.0, the `>=`-comparable types are `int` and `uint`. Starting with Stacks 2.1,
the `>=`-comparable types are expanded to include `string-ascii`, `string-utf8` and `buff`.
",
example: r#"(>= 1 1) ;; Returns true
(>= 5 2) ;; Returns true
(>= "baa" "aaa") ;; Returns true
(>= "aaa" "aa") ;; Returns true
(>= 0x02 0x01) ;; Returns true
(>= 5 u2) ;; Throws type error
"#
};
const LEQ_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("<= (less than or equal)"),
snippet: "<= ${1:expr-1} ${2:expr-2}",
signature: "(<= i1 i2)",
description: "Compares two integers, returning true if `i1` is less than or equal to `i2` and `false` otherwise.
i1 and i2 must be of the same type. Starting with Stacks 1.0, the `<=`-comparable types are `int` and `uint`. Starting with Stacks 2.1,
the `<=`-comparable types are expanded to include `string-ascii`, `string-utf8` and `buff`.",
example: r#"(<= 1 1) ;; Returns true
(<= 5 2) ;; Returns false
(<= "aaa" "baa") ;; Returns true
(<= "aa" "aaa") ;; Returns true
(<= 0x01 0x02) ;; Returns true
(<= 5 u2) ;; Throws type error
"#
};
const GREATER_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("> (greater than)"),
snippet: "> ${1:expr-1} ${2:expr-2}",
signature: "(> i1 i2)",
description:
"Compares two integers, returning `true` if `i1` is greater than `i2` and false otherwise.
i1 and i2 must be of the same type. Starting with Stacks 1.0, the `>`-comparable types are `int` and `uint`. Starting with Stacks 2.1,
the `>`-comparable types are expanded to include `string-ascii`, `string-utf8` and `buff`.",
example: r#"(> 1 2) ;; Returns false
(> 5 2) ;; Returns true
(> "baa" "aaa") ;; Returns true
(> "aaa" "aa") ;; Returns true
(> 0x02 0x01) ;; Returns true
(> 5 u2) ;; Throws type error
"#,
};
const LESS_API: SimpleFunctionAPI = SimpleFunctionAPI {
name: Some("< (less than)"),
snippet: "< ${1:expr-1} ${2:expr-2}",
signature: "(< i1 i2)",
description:
"Compares two integers, returning `true` if `i1` is less than `i2` and `false` otherwise.
i1 and i2 must be of the same type. Starting with Stacks 1.0, the `<`-comparable types are `int` and `uint`. Starting with Stacks 2.1,
the `<`-comparable types are expanded to include `string-ascii`, `string-utf8` and `buff`.",
example: r#"(< 1 2) ;; Returns true
(< 5 2) ;; Returns false
(< "aaa" "baa") ;; Returns true
(< "aa" "aaa") ;; Returns true
(< 0x01 0x02) ;; Returns true
(< 5 u2) ;; Throws type error
"#,
};
pub fn get_input_type_string(function_type: &FunctionType) -> String {
match function_type {
FunctionType::Variadic(ref in_type, _) => format!("{in_type}, ..."),
FunctionType::Fixed(FixedFunction { ref args, .. }) => {
let in_types: Vec<String> = args.iter().map(|x| format!("{}", x.signature)).collect();
in_types.join(", ")
}
FunctionType::UnionArgs(ref in_types, _) => {
let in_types: Vec<String> = in_types.iter().map(|x| format!("{x}")).collect();
in_types.join(" | ")
}
FunctionType::ArithmeticVariadic => "int, ... | uint, ...".to_string(),
FunctionType::ArithmeticUnary => "int | uint".to_string(),
FunctionType::ArithmeticBinary | FunctionType::ArithmeticComparison => {
"int, int | uint, uint | string-ascii, string-ascii | string-utf8, string-utf8 | buff, buff".to_string()
},
FunctionType::Binary(ref left_sig, ref right_sig, _) => {
let mut in_types: Vec<String> = Vec::new();
match left_sig {
FunctionArgSignature::Single(left) => {
match right_sig {
FunctionArgSignature::Single(right) => {
in_types.push(format!("{left}, {right}"));
},
FunctionArgSignature::Union(right_types) => {
for right in right_types.iter() {
in_types.push(format!("{left}, {right}"));
}
}
}
},
FunctionArgSignature::Union(left_types) => {
for left in left_types.iter() {
match right_sig {
FunctionArgSignature::Single(right) => {
in_types.push(format!("{left}, {right}"));
},
FunctionArgSignature::Union(right_types) => {
for right in right_types.iter() {
in_types.push(format!("{left}, {right}"));
}
}
}
}
}
}
in_types.join(" | ")
}
}
}
#[allow(clippy::panic)]
pub fn get_output_type_string(function_type: &FunctionType) -> String {
match function_type {
FunctionType::Variadic(_, ref out_type) => format!("{out_type}"),
FunctionType::Fixed(FixedFunction { ref returns, .. }) => format!("{returns}"),
FunctionType::UnionArgs(_, ref out_type) => format!("{out_type}"),
FunctionType::ArithmeticVariadic
| FunctionType::ArithmeticUnary
| FunctionType::ArithmeticBinary => "int | uint".to_string(),
FunctionType::ArithmeticComparison => "bool".to_string(),
FunctionType::Binary(left, right, ref out_sig) => match out_sig {
FunctionReturnsSignature::Fixed(out_type) => format!("{out_type}"),
FunctionReturnsSignature::TypeOfArgAtPosition(pos) => {
let arg_sig = match pos {
0 => left,
1 => right,
_ => panic!(
"Index out of range: TypeOfArgAtPosition for FunctionType::Binary can only handle two arguments, zero-indexed (0 or 1)."
),
};
match arg_sig {
FunctionArgSignature::Single(arg_type) => arg_type.to_string(),
FunctionArgSignature::Union(arg_types) => arg_types
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(" | "),
}
}
},
}
}
pub fn get_signature(function_name: &str, function_type: &FunctionType) -> Option<String> {
if let FunctionType::Fixed(FixedFunction { ref args, .. }) = function_type {
let in_names: Vec<String> = args.iter().map(|x| x.name.to_string()).collect();
let arg_examples = in_names.join(" ");
Some(format!(
"({function_name}{}{arg_examples})",
if arg_examples.is_empty() { "" } else { " " }
))
} else {
None
}
}
#[allow(clippy::expect_used)]
#[allow(clippy::panic)]
fn make_for_simple_native(
api: &SimpleFunctionAPI,
function: &NativeFunctions,
name: String,
) -> FunctionAPI {
let (input_type, output_type) = {
if let TypedNativeFunction::Simple(SimpleNativeFunction(function_type)) =
TypedNativeFunction::type_native_function(function)
.expect("Failed to type a native function")
{
let input_type = get_input_type_string(&function_type);
let output_type = get_output_type_string(&function_type);
(input_type, output_type)
} else {
panic!("Attempted to auto-generate docs for non-simple native function: {name:?}")
}
};
FunctionAPI {
name: api.name.map_or(name, |x| x.to_string()),
snippet: api.snippet.to_string(),
input_type,
output_type,
signature: api.signature.to_string(),
description: api.description.to_string(),
example: api.example.to_string(),
min_version: function.get_min_version(),
max_version: function.get_max_version(),
}
}
const EQUALS_API: SpecialAPI = SpecialAPI {
input_type: "A, A, ...",
snippet: "is-eq ${1:expr-1} ${2:expr-2}",
output_type: "bool",
signature: "(is-eq v1 v2...)",
description: "Compares the inputted values, returning `true` if they are all equal. Note that
_unlike_ the `(and ...)` function, `(is-eq ...)` will _not_ short-circuit. All values supplied to
is-eq _must_ be the same type.",
example: "(is-eq 1 1) ;; Returns true
(is-eq true false) ;; Returns false
(is-eq \"abc\" 234 234) ;; Throws type error
(is-eq \"abc\" \"abc\") ;; Returns true
(is-eq 0x0102 0x0102) ;; Returns true
",
};
const IF_API: SpecialAPI = SpecialAPI {
input_type: "bool, A, A",
snippet: "if ${1:condition} ${2:expr-if-true} ${3:expr-if-false}",
output_type: "A",
signature: "(if bool1 expr1 expr2)",
description: "The `if` function admits a boolean argument and two expressions
which must return the same type. In the case that the boolean input is `true`, the
`if` function evaluates and returns `expr1`. If the boolean input is `false`, the
`if` function evaluates and returns `expr2`.",
example: "(if true 1 2) ;; Returns 1
(if (> 1 2) 1 2) ;; Returns 2",
};
const LET_API: SpecialAPI = SpecialAPI {
input_type: "((name1 AnyType) (name2 AnyType) ...), AnyType, ... A",
snippet: "let ((${1:name-1} ${2:val-1})) ${3:expr-1}",
output_type: "A",
signature: "(let ((name1 expr1) (name2 expr2) ...) expr-body1 expr-body2 ... expr-body-last)",
description: "The `let` function accepts a list of `variable name` and `expression` pairs,
evaluating each expression and _binding_ it to the corresponding variable name.
`let` bindings are sequential: when a `let` binding is evaluated, it may refer to prior binding.
The _context_ created by this set of bindings is used for evaluating its body expressions.
The let expression returns the value of the last such body expression.
Note: intermediary statements returning a response type must be checked",
example: "(let ((a 2) (b (+ 5 6 7))) (print a) (print b) (+ a b)) ;; Returns 20
(let ((a 5) (c (+ a 1)) (d (+ c 1)) (b (+ a c d))) (print a) (print b) (+ a b)) ;; Returns 23",
};
const FETCH_VAR_API: SpecialAPI = SpecialAPI {
input_type: "VarName",
snippet: "var-get ${1:var}",
output_type: "A",
signature: "(var-get var-name)",
description: "The `var-get` function looks up and returns an entry from a contract's data map.
The value is looked up using `var-name`.",
example: "(define-data-var cursor int 6)
(var-get cursor) ;; Returns 6",
};
const SET_VAR_API: SpecialAPI = SpecialAPI {
input_type: "VarName, AnyType",
snippet: "var-set ${1:var} ${2:value}",
output_type: "bool",
signature: "(var-set var-name expr1)",
description: "The `var-set` function sets the value associated with the input variable to the
inputted value. The function always returns `true`.",
example: "
(define-data-var cursor int 6)
(var-get cursor) ;; Returns 6
(var-set cursor (+ (var-get cursor) 1)) ;; Returns true
(var-get cursor) ;; Returns 7",
};
const MAP_API: SpecialAPI = SpecialAPI {
input_type: "Function(A, B, ..., N) -> X, sequence_A, sequence_B, ..., sequence_N",
snippet: "map ${1:func} ${2:sequence}",
output_type: "(list X)",
signature: "(map func sequence_A sequence_B ... sequence_N)",
description: "The `map` function applies the function `func` to each corresponding element of the input sequences,
and outputs a _list_ of the same type containing the outputs from those function applications.
Applicable sequence types are `(list A)`, `buff`, `string-ascii` and `string-utf8`,
for which the corresponding element types are, respectively, `A`, `(buff 1)`, `(string-ascii 1)` and `(string-utf8 1)`.
The `func` argument must be a literal function name.
Note: no matter what kind of sequences the inputs are, the output is always a list.",
example: r#"
(map not (list true false true false)) ;; Returns (false true false true)
(map + (list 1 2 3) (list 1 2 3) (list 1 2 3)) ;; Returns (3 6 9)
(define-private (a-or-b (char (string-utf8 1))) (if (is-eq char u"a") u"a" u"b"))
(map a-or-b u"aca") ;; Returns (u"a" u"b" u"a")
(define-private (zero-or-one (char (buff 1))) (if (is-eq char 0x00) 0x00 0x01))
(map zero-or-one 0x000102) ;; Returns (0x00 0x01 0x01)
"#,
};
const FILTER_API: SpecialAPI = SpecialAPI {
input_type: "Function(A) -> bool, sequence_A",
snippet: "filter ${1:func} ${2:sequence}",
output_type: "sequence_A",
signature: "(filter func sequence)",
description: "The `filter` function applies the input function `func` to each element of the
input sequence, and returns the same sequence with any elements removed for which `func` returned `false`.
Applicable sequence types are `(list A)`, `buff`, `string-ascii` and `string-utf8`,
for which the corresponding element types are, respectively, `A`, `(buff 1)`, `(string-ascii 1)` and `(string-utf8 1)`.
The `func` argument must be a literal function name.