{"id":13792680,"url":"https://github.com/merklejerk/solpp","last_synced_at":"2025-04-22T22:23:54.560Z","repository":{"id":33234057,"uuid":"155752946","full_name":"merklejerk/solpp","owner":"merklejerk","description":"A solidity preprocessor and flattener CLI and library","archived":false,"fork":false,"pushed_at":"2023-07-12T02:39:14.000Z","size":397,"stargazers_count":112,"open_issues_count":14,"forks_count":14,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-18T13:59:28.226Z","etag":null,"topics":["ethereum","flattener","preprocessor","smart-contracts","solidity"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/merklejerk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-11-01T17:41:02.000Z","updated_at":"2024-01-20T09:20:39.000Z","dependencies_parsed_at":"2024-01-28T17:09:25.980Z","dependency_job_id":"55ab0602-9cca-416e-b885-4d8132a9d8ed","html_url":"https://github.com/merklejerk/solpp","commit_stats":{"total_commits":54,"total_committers":7,"mean_commits":7.714285714285714,"dds":0.5555555555555556,"last_synced_commit":"402ea4af9a6f42d1fa9791ee58049db714c1376c"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merklejerk%2Fsolpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merklejerk%2Fsolpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merklejerk%2Fsolpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/merklejerk%2Fsolpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/merklejerk","download_url":"https://codeload.github.com/merklejerk/solpp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250332602,"owners_count":21413241,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ethereum","flattener","preprocessor","smart-contracts","solidity"],"created_at":"2024-08-03T22:01:15.011Z","updated_at":"2025-04-22T22:23:54.538Z","avatar_url":"https://github.com/merklejerk.png","language":"JavaScript","funding_links":[],"categories":["Roadmap"],"sub_categories":[],"readme":"---\n\n⚠️ This project is deprecated, no longer maintained, and is here for historical purposes only 😢. Solidity has come a long way since this tool was developed and you can usually accomplish many of the same things with vanilla solidity from here on, so it's largely unecessary now. ⚠️\n\n---\n\n![build status](https://travis-ci.org/merklejerk/solpp.svg?branch=master)\n[![npm package](https://badge.fury.io/js/solpp.svg)](https://www.npmjs.com/package/solpp)\n\n# **solpp**\n#### A [preprocessor](https://en.wikipedia.org/wiki/Preprocessor) and flattener for Ethereum's [Solidity](https://solidity.readthedocs.io) source files.\n\n`solpp` is designed *specifically* for Solidity, which means it\nactually understands some of Solidity's grammar and offers high-precision\nmath and builtin functions suitable for use with Solidity's primitives.\n\n## Features\n\n- Flattens your source files for easy contract verification on\n[etherscan.io](https://etherscan.io) by merging all naked imports.\n- Will even include URL imports, along with their dependencies.\n- Simple, practical language inspired by C preprocessor directives,\npython, and javascript.\n- Easily declare symbols and macro functions in your source file with\n`#def` directives.\n- `#if`/`#elif`/`#else` blocks for conditional code rendering.\n- `#for` blocks for repeating code.\n- Expand (substitute) with `$(...)` or evaluate with `$$(...)` symbols, macros,\nand expressions anywhere in your code.\n- All math is done in extremely high precision (up to120 digits) and can\nrepresent integers AND decimals.\n- Robust expression syntax with many useful builtin functions.\n\n##### Please see the [ChangeLog](./CHANGELOG.md) for breaking changes between versions.\n\n## Topics\n- [Example](#example)\n- [Installation](#installation)\n- [Command Line Usage](#command-line-usage)\n   - [CLI Options](#cli-options)\n   - [Instructions](#instructions)\n      - [External Symbols](#external-symbols)\n- [Library Usage](#library-usage)\n- [Language Reference](#language-reference)\n   - [Directive Syntax](#directive-syntax)\n   - [Symbols](#symbols)\n   - [Macros](#macros)\n   - [Expansion](#expansion)\n   - [Evaluation](#evaluation)\n      - [Inline Evaluation](#inline-evaluation)\n   - [If/Elif/Else Blocks](#if-elif-else-blocks)\n   - [For Loops](#for-loops)\n   - [Expressions](#expressions)\n      - [Operations](#operations)\n      - [Literals](#literals)\n   - [Builtins](#builtins)\n      - [Language Functions](#language-functions)\n      - [Numerical Functions](#numerical-functions)\n      - [String Functions](#string-functions)\n      - [List Functions](#list-functions)\n      - [Ethereum Functions](#ethereum-functions)\n      - [Constants](#constants)\n\n## Example\n\n```solidity\n// solpp will inline this file and any of its dependencies.\nimport './MyLibrary.sol';\n// If you have a file in node_modules, solpp can grab that too.\nimport 'openzeppelin-solidity/contracts/math/Math.sol';\n// solpp can also do the same with URLs!\nimport 'https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.0.0/contracts/token/ERC20/ERC20.sol';\n\n\ncontract MyContract {\n   // Define and use a symbol.\n   // #def EIGHT_QUARTERS 8 / 4\n   uint256 _var1 = $(EIGHT_QUARTERS); // -\u003e uint256 _var1 = 8 / 4;\n   // Evaluate a symbol as an expression. Note the double $.\n   uint256 _var2 = $$(EIGHT_QUARTERS); // -\u003e uint256 _var2 = 2;\n   // We can even remove the symbol if we don't need it anymore.\n   // #undef EIGHT_QUARTERS\n\n   // Define and use a macro.\n   // #def POW(a, b) a ** b\n   // Here we expand then evaluate the symbol.\n   uint256 _var3 = $(POW(2, 3)) + $$(POW(16, 0.5)); // -\u003e uint256 _var3 = 2 ** 3 + 4;\n   // Macros can call other macros and symbols during evaluation.\n   // #def SQUARE(x) POW(x, 2)\n   uint256 _var4 = $$(SQUARE(10)); // -\u003e uint256 _var4 = 100;\n   // You can also evaluate expressions inline.\n   // Here we compute LOG(10) expressed as parts per million\n   // using some builtin functions.\n   uint256 _log10 = $$(int(log(10) * 1e6)); // -\u003e uint256 _log10 = 2302585;\n   // All math supports decimals. here we output sqrt(2) as a\n   // decimal string with 16 digits of precision.\n   string _sqrt2 = $$(quote(sd(2**0.5, 16))); // -\u003e string _sqrt2 = \"1.414213562373095\";\n   // We can even do bitwise operations on integers and output hex.\n   bytes32 _bytes = $$(hex(int((2**0.5) * 1e18) \u003c\u003c 8)); // -\u003e bytes32 _bytes = 0x13a04bbdfdc9be8800;\n   // Maybe we want to combine some strings.\n   string _fullName = $$(quote(join(['Bob', 'Smith'], ' '))); // -\u003e string _fullName = \"Bob Smith\";\n   // Or do string interpolation.\n   // #def GREETING(first, last) quote(`Hello, $(first} $(last}!`)\n   string _fullName2 = $$(GREETING('Bob', 'Smith')) // -\u003e string _fullName2 = \"Hello, Bob Smith!\";\n   // Convert a private key to an address? Sure!\n   // #def PRIV_KEY 0x563b99585e0709e3a7ac78b8957aa0f53bc874a86f288884d7ccafe3b9e9b934\n   address _addr = $$(key2addr(PRIV_KEY)); // -\u003e _addr = 0x86c0bfFbA7b505c82f1533aFe6C69A604c3e2870;\n\n   function foo(uint256 x) pure returns (uint256) {\n      // #if EXT_SYMBOL\n      // If the symbol EXT_SYMBOL is defined externally or in a source file\n      // as \"truthy\" (non-false, non-zero), this code will be rendered.\n      return x * 100;\n      // #else\n      // Otherwise, this code will be rendered.\n      return x / 100;\n      // #endif\n   }\n\n   function bar(uint256 x) pure returns (uint256) {\n     // Repeat code with a a for loop.\n     return x /* #for V in range(1,4) */+ $$(V+1)/* #done */; // -\u003e return x + 1 + 2 + 3;\n   }\n}\n```\n\n## Installation\nIf your project scaffolding is node-based, you can install it as a\ndevelopment dependency inside your project directory.\nAs a development dependency, you should be able to call\n`solpp` in a `\"scripts\"` entry in your project's `package.json` file.\n\nTo run the tool manually, you can use `npx solpp` from within your project\ndirectory.\n\n```bash\n# Install as a project development dependency with npm.\nnpm install -D solpp\n# or if using yarn\nyarn add -D solpp\n```\n\nIf you want `solpp` to be accessible from anywhere in your filesystem, you'll\nneed to install it globally.\n\n```bash\n# Install globally with npm.\nnpm install -g solpp\n# or if using yarn\nyarn global add solpp\n```\n\n## Command Line Usage\n\n### CLI Options\n```\nUsage: solpp [options] \u003csource-file\u003e\n\nOptions:\n   -v --version                 output the version number\n   -o, --output \u003cfile\u003e          write output to a file (instead of stdout)\n   --no-flatten                 do not flatten (include) naked imports\n   --no-pp                      disable the preprocessor (just flatten)\n   -D, --define \u003cname\u003e[=value]  define a preprocessor symbol (can be repeated)\n   --defs \u003cfile\u003e                preprocessor definitions JS or JSON file\n   --tolerant                   ignore missing imports when flattening\n   -h, --help                   output usage information\n```\n\n### Instructions\n\nYou should invoke `solpp` for the contract file that you want to preprocess.\nIt will automatically include and preprocess all **naked** imports found within\nthe file and subsequent files. Naked imports are of the form\n`import \"path/to/file\";`. Any other import scheme will be ignored.\n\n**`solpp` is not a compiler**, so you will still need to compile the generated code\nyourself, via [solc](https://solidity.readthedocs.io/en/v0.4.25/using-the-compiler.html)\nor a build pipeline like [truffle](https://github.com/trufflesuite/truffle).\n\nIf you are using a build pipeline such as\n[truffle](https://github.com/trufflesuite/truffle), you should keep your\nraw source files in a separate directory and run `solpp` to output code\ninto the pipeline's source directory before compiling your project.\n\n#### External Symbols\n\nYou can define preprocessor symbols inside source files using the `#def`\ndirective or you can define them externally on the command line\n(with the `-D` flag) or in a JS/JSON file. The order of priority in which\nredundantly declared symbols override each other, from highest priority to\nlowest priority, is Source -\u003e Command Line -\u003e Definitions File.\n\nA JSON definitions file is just a plain object such as:\n```js\n{\n   \"MY_SYMBOL_1\": 100,\n   \"MY_SYMBOL_2\": true,\n   \"MY_SYMBOL_3\": \"48192.418291248\",\n   \"MY_SYMBOL_4\": \"blah blah\",\n   \"MY_SYMBOL_5\": ['symbols', 'can', 'hold', 'lists']\n}\n```\n\nIf using a JS file, it will be imported as a nodejs module, so you must assign\nyour object to `module.exports`. The advantage of using a JS file is you can\ndefine symbols as functions, which can be called from\n[evaluations](#evaluation) in your code.\n\n## Library Usage\n\nIf you `require('solpp')` into your nodejs project, you can use it\nprogrammatically. This allows `solpp` to be integrated into any pipeline.\n\nThe library exposes 3 functions, all of which return promises:\n\n```js\nconst solpp = require('solpp');\n\n// Preprocess code. Returns processed code.\nPROCESSED_CODE: String = await solpp.processCode(\n   // The raw code to process.\n   code: String,\n   // Options object. All fields are optional.\n   opts={\n      // Dictionary of preprocessor symbols and functions\n      defs: {...},\n      // Unique name for the source unit (like a full path).\n      name: String,\n      // The current working directory.\n      cwd: String,\n      // Function to resolve imported files.\n      resolver: Function(path, cwd, from),\n      // Whether or not to collapse 2 or more empty lines. Defaults to true.\n      collapseEmptyLines: Boolean,\n      // Whether to ignore unresolved imports. Defaults to false.\n      tolerant: Boolean,\n      // Don't flatten/inline imports. Defaults to false.\n      noFlatten: Boolean,\n      // Disable the preprocessor. Defaults to false.\n      noPreprocessor: Boolean\n});\n\n// Preprocess code in a file. Returns processed code.\nPROCESSED_CODE: String = await solpp.processFile(\n   // The path of the raw code file.\n   path: String,\n   // Same as in processCode().\n   opts={...});\n\n// The default resolver used when none is set.\n// Will either resolve filesystem files or remote files (URLs).\n// Returns an object.\n{\n   // The raw code in the file.\n   code: String\n   // A unique name for the file (usually just the full path or URL)\n   name: String,\n   // The parent directory (or URL path) of the file.\n   cwd: String,\n} = await solpp.resolver(\n      // The import path. May be a relative or absolute path, or even a URL.\n      path: String,\n      // The current working directory, or parent URL path if coming from a remote file.\n      cwd: String,\n      // The name of the importing file.\n      from: String\n   );\n```\n\n## Language Reference\n\n### Directive Syntax\n\nAll `solpp` directives are contained inside either line comments or block\ncomments. This design is to maintain compatibility with existing Solidity\neditor highlighters. You can use line and block comment directives\ninterchangeably. Line comment directives terminate at the end of the line,\nunless the line ends in a `\\` character, which allows you to continue the\ndirective on the next immediate line comment.\n\n**Example**\n```solidity\n// Single line comment directive.\n// #def LDEF All this text is the value of LDEF.\n\n// A line comment directive spread across two lines.\n// #def MULTILINE_LDEF If you start running out of room, you can continue \\\n// on the next line like so.\n\n// Block comment directives are great in tight #for loops or #if blocks.\n// This will render: uint256 fac5 = 1 * 2 * 3 * 4 * 5;\nuint256 fac5 = 1/* #for i in range(2, 6) */ * $$(i)/* #done */;\nbool maybe = /* #if SOME_SYMBOL */true/* #else */false;/* #endif */\n```\n\n### Symbols\nSymbols can be declared externally on the command line or in a definitions\nfile, or from right within a source file with the `#def` directive.\nSymbols can take on arbitrary values: code snippets, expressions, strings,\nnumbers (binary, hex, octal, decimals), booleans, and lists.\n\nOnce defined, symbols (and macros) can be [expanded](#expansion) (`$(...)`)\nor [evaluated](#evaluation) (`$$(...)`) in your code. Symbols do not\nhave to hold valid expressions, but only those that do can be evaluated.\n\nIf you no longer need a symbol, you can undefine it with the `#undef` directive.\n\n**Input**\n```solidity\n// Define a symbol\n// #def MY_EXPR 1 + 1\n// Expand it.\nuint256 x = $(MY_EXPR);\n// Now evaluate it.\nuint256 y = $$(MY_EXPR);\n\n// Remove this symbol.\n// #undef MY_EXPR\n```\n\n**Result**\n```solidity\n// Define a symbol\n// Expand it.\nuint256 x = 1 + 1;\n// Now evaluate it.\nuint256 y = 2;\n\n// Remove this symbol.\n```\n\n### Macros\nMacros are similar to symbols except that they take some arguments, like a\nfunction. They can be defined externally in a (javascript) definitions file or\nfrom within your code also with the `#def` directive.\n\n[Expanding](#expansion) a macro will perform a substitution of the arguments\nacross its contents. [Evaluating](#evaluation) a macro will evaluate its\ncontents as an expression, just like calling a function. You can even call\nother macros or reference other symbols inside macros during evaluation.\nLike symbols, macros do not have to hold valid expressions, but\nonly those that do can be evaluated.\n\nIf you no longer need a macro, you can undefine it with the `#undef` directive.\n\n**Input**\n```solidity\n// Define a macro\n// #def MY_MACRO(x) (x / 2) + 1\n// Expand it.\nuint256 x = $(MY_MACRO(10));\n// Evaluate it.\nuint256 y = $$(MY_MACRO(10));\n\n// Define a new macro that calls the other macro.\n// #def OTHER_MACRO(x) MY_MACRO(x * 10)\n// Evaluate it.\nuint256 z = $$(OTHER_MACRO(8));\n\n// Remove this macro.\n// #undef OTHER_MACRO\n```\n\n**Result**\n```solidity\n// Define a macro\n// Expand it.\nuint256 x = (10/2) + 1;\n// Evaluate it.\nuint256 y = 6;\n\n// Define a new macro that calls the other macro.\n// Evaluate it.\nuint256 z = 41;\n\n// Remove this macro.\n```\n\n### Expansion\n\nExpansion occurs whenever a `$(...)` block is encountered in regular code\n(i.e., not inside a comment or string literal). When expanding a symbol, the\ncontents of that symbol are simply put in the place of the expansion block.\n\nA similar result occurs when expanding a macro, except arguments will be\nsubstituted throughout the macro's contents.\n\n**Input**\n```solidity\n// Expanding a symbol.\n// #def SYM_1 foo / 2\nuint256 v = 1 + $(SYM_1);\n\n// Expanding a macro.\n// #def MACRO_1(x) x / 2\nuint256 v2 = 1 + $(MACRO_1(100));\n```\n\n**Result**\n```solidity\n// Expanding a symbol.\nuint256 v = 1 + foo / 2;\n\n// Expanding a macro.\nuint256 v = 1 + 100 / 2;\n```\n\n### Evaluation\n\nEvaluation occurs whenever a `$$(...)` block is encountered in regular code\n(i.e., not inside a comment or string literal). When evaluating a symbol, the\ncontents of that symbol are parsed and evaluated as an expression, with the\nultimate result put in the place of the evaluation block. Macros work the same\n way, except they can accept arguments which will also be evaluated.\n\nMacros and symbols call and refer to other macros, symbols, and\n[builtins](#builtins) during evaluation.\n\nIf a macro or symbol does not contain a valid expression during an evaluation\noperation, an error will be raised. If a symbol is encountered that is\nundefined, it will take on the value of `0`.\n\n**Input**\n```solidity\n// Evaluating a symbol.\n// #def SYM_1 5 * 2\nuint256 v = 1 + $$(SYM_1);\n\n// Evaluating a macro.\n// #def MACRO_1(x) x * 2\nuint256 v2 = 1 + $$(MACRO_1(2));\n\n// Macro calling another macro and referencing a symbol.\n// #def SYM_2 2 ** 3\n// #def MACRO_2(x) MACRO_1(x) + SYM_2\nuint256 v3 = $$(MACRO_2(4));\n```\n**Result**\n```solidity\n// Evaluating a symbol.\nuint256 v = 1 + 10;\n\n// Evaluating a macro.\nuint256 v2 = 1 + 4;\n\n// Macro calling another macro and referencing a symbol.\nuint256 v3 = 16;\n```\n\n#### Inline Evaluation\n\nYou don't have to use symbols or macros in your evaluation blocks. You can put\nany valid expression inside of them as well.\n\n**Input**\n```solidity\n// Compute the sqrt of 2 as parts per million.\n// Here we use the builtin function 'int' to make the result an integer.\nuint256 sqrt2 = $$(int(2**0.5 * 1e6));\n```\n\n**Result**\n```solidity\n// Compute the sqrt of 2 as parts per million.\n// Here we use the builtin function 'int' to make the result an integer.\nuint256 sqrt2 = 1414213;\n```\n\n\n### If/Elif/Else Blocks\n\nOne of the most common uses of a preprocessor is conditional code\ngeneration. This is easily accomplished through the\n`#if`, `#elif`, `#else`, and `#endif` directives. Code between an\n`#if/else/elif` and `#endif` directive will only be rendered if the directive's\ncondition **evaluates** to \"truthy\" (either true, non-zero, or a\nnon-empty string). Conditions are normal preprocessor\n[expressions](#expressions), which can be as simple as a single value or a\ncomplex sequence of operations.\n\nBlocks may also be nested, with inner blocks depending on outer blocks.\n\n**Input**\n```solidity\n// #if true\n// This block will always render.\nuint256 x = 100;\n// #endif\n\n// #if 0\n// This block will never render\nuint256 x = 200;\n// #endif\n\n// #if EXT_SYM_1\n// This block will only render if EXT_SYM_1 is defined as truthy.\nuint256 foo = 1;\n// #elif EXT_SYM_2 == 'foobar'\n// This Block will only render if EXT_SYM_1 is falsey (or undefined)\n// AND EXT_SYM_1 is set to the string 'foobar'\nuint256 foo = 2;\n// #else\n// This block will only render if the preceding two conditions fail.\nuint256 foo = 3;\n// #endif\n```\n\n**Result** (with `EXT_SYM_2='foobar'`)\n```solidity\n// This block will always render.\nuint256 x = 100;\n\n// This Block will only render if EXT_SYM_1 is falsey (or undefined)\n// AND EXT_SYM_1 is set to the string 'foobar'\nuint256 foo = 2;\n```\n\n### For Loops\n\nAnother great use case for preprocessors is unrolling loops or generating\nconstant values for an array. The `#for` directive can help you do all those\nthings and more.\n\n`#for` directives iterate over a list, either one you have explicity defined with\nthe list operator (`[...]`) or from a list producing function function such as\n`range()`. `#for` directives have the syntax `#for ITEM, IDX in LIST`, which\niterates over values and indices, or simply `#for ITEM in LIST`, if you only\nwant to iterate over the values in a list.\n\n**Input**\n```solidity\n// Calculate the summation of 0...4\nuint256 sum = 0;\n// #for ITEM in range(1, 5)\nsum += $$(ITEM);\n// #done\n```\n\n**Result**\n```solidity\n// Calculate the summation of 0...4\nuint256 sum = 0;\nsum += 1;\nsum += 2;\nsum += 3;\nsum += 4;\n```\n\nWhile `#for` offers a lot of explicit control, when working with lists,\n(which the `range()` builtin returns), you might find a more concise solution\nby exploiting [list builtin functions](#list-functions), such as `map()`,\n`reduce()`, and `join()`.\n\n### Expressions\n\nPreprocessor expressions are similar to javascript expressions, with many of the\nusual operations and precedence. All mathematical operations are done using\nhigh-precision (up to 120 significant digits) math, which can hold many more\ndigits than the largest Solidity type (uint256).\n\nIt's worth noting that bitwise operations, however,\nwill only operate on 256-bit integers, and will always result in a 256-bit\nunsigned integer. Attempting to perform a bitwise operation on a number with a\ndecimal component will result in an error.\n\n#### Operations\n\n| Operation | Description |\n|-----------|-------------|\n| `a + b` | Add `a` to `b` |\n| `a - b` | Subract `b` from `a` |\n| `a * b` | Multiple `a` with `b` |\n| `a / b` | Divide `a` by `b` |\n| `a % b` | Modulo of `a` with `b` |\n| `a ** b` | Raise `a` to `b` |\n| `~a` | 256-bit bitwise INVERT `a` |\n| `a \u0026 b` | 256-bit `a` bitwise AND `b` |\n| \u003ccode\u003ea \u0026#124; b\u003c/code\u003e | 256-bit `a` bitwise OR `b` |\n| `a ^ b` | 256-bit `a` bitwise XOR `b` |\n| `a \u003c\u003c b` | 256-bit bitwise shift `a` left by `b` bits |\n| `a \u003e\u003e b` | 256-bit bitwise shift `a` right by `b` bits |\n| `!a` | logical NOT `a` |\n| \u003ccode\u003ea \u0026#124;\u0026#124; b\u003c/code\u003e | logical `a` OR `b` |\n| `a \u0026\u0026 b` | logical `a` AND `b` |\n| `(...)` | Expression grouping (explicit precedence) |\n| `a ? b : c` | Ternary operator: return `b` if `a` is true, otherwise return `c` |\n| `foo(x, y, z)` | Call function/macro `foo` with arguments `x`, `y`, and `z` |\n| `id` | Evaluate the symbol `id` |\n| `[a, b, c]` | Create a list with values `a`, `b`, and `c`, which can be expressions |\n| `(a, b) =\u003e ...` | Define an anonymous (lambda) macro, useful for the `map()` and `reduce()` [builtins](#list-functions) |\n\n##### Literals\n\nThere are 3 types of literals: booleans, strings, and numbers.\nInternally, numbers are stored as decimal strings, so they do not lose\nprecision.\n\n| Example | Description |\n|---------|-------------|\n| `true` | `true` boolean |\n| `false` | `false` boolean |\n| `\"foo\"` | Double quoted string |\n| `'foo'` | Single quoted string |\n| \u003ccode\u003e\u0026#96;foo $(bar}\u0026#96;\u003c/code\u003e | Interpolated string (with `bar` *expanded* in place) |\n| \u003ccode\u003e\u0026#96;foo $$(bar}\u0026#96;\u003c/code\u003e | Interpolated string (with `bar` *evaluated* in place) |\n| `32` | Positive integer number |\n| `-32` | Negative integer number |\n| `32.55` | Decimal number |\n| `1.5e5` | Exponent notation number |\n| `0xa047` | hexadecimal notation number |\n| `0b0101011` | binary notation number |\n| `077414` | octal notation number |\n\n\n### Builtins\n\nMany general-purpose and domain-specific builtin functions come already defined\nand can be called during [evaluation](#evaluation).\n\n#### Language Functions\n\n| Function | Description |\n|----------|-------------|\n| `defined(x)` | Test whether the symbol `x` is defined |\n| `peek(x)` | Return the *literal* value of symbol `x` (does not evaluate the contents of `x`)  |\n| `bool(x)` | Coerce `x` into a boolean |\n| `islist(x)` | Check if `x` is a list |\n\n#### Numerical Functions\n\n| Function | Description |\n|----------|-------------|\n| `min(a, b)` | Take the minimum of `a` and `b` |\n| `max(a, b)` | Take the maximum of `a` and `b` |\n| `clamp(x, lo, hi)` | Clamp `x` to be within `lo` and `hi`, inclusive |\n| `abs(x)` | Take the absolute value of `x` |\n| `sqrt(x)` | Get the square root of x, same as doing `x**0.5` |\n| `log(x)` | Take the natural logarithm of `x` |\n| `log(x, b)` | Take the logarithm of `x` with base `b` |\n| `exp(y)` | Raise the mathematical constant `e` to `y` |\n| `sign(x)` | Get the sign of `x` (either `-1`, `0`, or `1`) |\n| `sd(x)` | Get the number of significant digits in the number x |\n| `sd(x, n)` | Return a number which is `x` with `n` significant digits |\n| `dp(x)` | Get the number of decimal places in the number x |\n| `dp(x, n)` | Return a number which is `x` with `n` decimal places |\n| `round(x)` | Round `x` to a signed integer |\n| `int(x)` | Truncate `x` to a signed integer |\n| `uint(x)` | Truncate `x` to an positive integer |\n| `int8(x)` | Truncate `x` to a signed 8-bit integer |\n| `uint8(x)` | Truncate `x` to an positive 8-bit integer |\n| `int16(x)` | Truncate `x` to a signed 16-bit integer |\n| `uint16(x)` | Truncate `x` to an positive 16-bit integer |\n| `int32(x)` | Truncate `x` to a signed 32-bit integer |\n| `uint32(x)` | Truncate `x` to an positive 32-bit integer |\n| `int64(x)` | Truncate `x` to a signed 64-bit integer |\n| `uint64(x)` | Truncate `x` to an positive 64-bit integer |\n| `int128(x)` | Truncate `x` to a signed 128-bit integer |\n| `uint128(x)` | Truncate `x` to an positive 128-bit integer |\n| `int256(x)` | Truncate `x` to a signed 256-bit integer |\n| `uint256(x)` | Truncate `x` to an positive 256-bit integer |\n| `hex(x)` | Encode `x` as a hexadecimal |\n| `hex(x, n)` | Encode `x` as a hexadecimal, padding or truncating to `n` bytes. If `n` is negative, `n` will be right padded/truncated. |\n| `decimal(x)` | Encode `x` as a decimal |\n\n#### String Functions\n\n| Function | Description |\n|----------|-------------|\n| `len(x)` | Get the length of string `x` |\n| `concat(...)` | Concatenates all arguments into a single string. |\n| `quote(x)` | Turn `x` into a quoted string. |\n| `unquote(x)` | Remove quotes from a quoted string `x`. |\n| `strhex(x)` | Return the utf-8 hex of a string `x`. |\n| `uppercase(x)` | Uppercase the string `x`. |\n| `lowercase(x)` | Lowercase the string `x`. |\n| `camelcase(x)` | Camelcase the string `x`. |\n| `capitalize(x)` | capitalize the string `x`. |\n| `repeat(s, n)` | Repeat the string `s` `n` times. |\n\n#### List Functions\n\n| Function | Description |\n|----------|-------------|\n| `islist(x)` | Check if `x` is a list |\n| `len(x)` | Get the length of list `x` |\n| `range(end)` | Create a list of numbers from `0` to `end` (exclusive) with step size `1` |\n| `range(start, end, step=1)` | Create a list of numbers from `start` to `end` (exclusive) with step size `step` |\n| `filled(len, value=0)` | Create a `len` length list filled with `value` |\n| `concat(...)` | Combines a series of lists into one. |\n| `sum(x)` | Returns the sum of all values in `x`. |\n| `join(a, sep='')` | Join list `a` into a string with separator `sep` |\n| `map(a, fn)` | Create a list where each item in `a` is run through the function/macro `fn`. If `fn` can take two arguments, the index of the item will be passed as the 2nd argument. |\n| `reduce(a, fn, initial=0)` | Run items in the list `a` through the function/macro `fn`, which takes 2-3 arguments (`total, value, [index]`) and returns the new total. |\n\n#### Ethereum Functions\n\n| Function | Description |\n|----------|-------------|\n| `keccak256(...)` | Compute the keccak256 hash of all arguments. |\n| `key2addr(k)` | Get the address associated with private key `k` |\n\n#### Constants\n\n| Name | Description |\n|----------|-------------|\n| `E` | The mathematical constant *e* |\n| `PI` | The mathematical constant *π* |\n| `__line` | The line number of the expression |\n| `__indent` | The indentation of the expression (string of whitespaces leading up to the expression |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmerklejerk%2Fsolpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmerklejerk%2Fsolpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmerklejerk%2Fsolpp/lists"}