-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
72 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,95 @@ | ||
## Foundry | ||
# Huff, in Racket | ||
|
||
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** | ||
Puff is an experimental Huff compiler implemented in Racket. It currently supports a small subset of full Huff functionality. | ||
|
||
Foundry consists of: | ||
# Current Status | ||
|
||
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). | ||
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. | ||
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. | ||
- **Chisel**: Fast, utilitarian, and verbose solidity REPL. | ||
Very early WIP! | ||
|
||
## Documentation | ||
## Implemented | ||
|
||
https://book.getfoundry.sh/ | ||
Not much yet, but we can compile a basic contract that has a single MAIN macro, imports other files, and references constants. | ||
|
||
## Usage | ||
- All opcodes | ||
- `#define function` and `__FUNC_SIG` | ||
- `#define error` and `__ERROR` | ||
- `#define constant` and `[CONSTANT]` syntax for const references | ||
|
||
### Build | ||
## Not Implemented | ||
- Calling macros/functions from Main | ||
- Custom constructors | ||
- Built-ins like __FUNC_SIG, etc. | ||
- Lots of other stuff! | ||
|
||
```shell | ||
$ forge build | ||
``` | ||
# Usage | ||
|
||
### Test | ||
## Requirements | ||
|
||
```shell | ||
$ forge test | ||
``` | ||
- Racket | ||
- Rust | ||
|
||
### Format | ||
### Racket Libs | ||
|
||
```shell | ||
$ forge fmt | ||
``` | ||
- `threading-lib` | ||
- `brag` | ||
|
||
### Gas Snapshots | ||
Install with: | ||
|
||
```shell | ||
$ forge snapshot | ||
``` | ||
`make install_racket_libs` | ||
|
||
### Anvil | ||
## Build keccak library | ||
|
||
```shell | ||
$ anvil | ||
``` | ||
Puff depends on the keccak implementation from [Alloy](https://github.com/alloy-rs/core). | ||
|
||
### Deploy | ||
We need a tiny bit of Rust code to build a library we can call from Racket over FFI. This is all handled by the makefile. | ||
|
||
```shell | ||
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key> | ||
``` | ||
Clone the repository, then from its root, run: | ||
|
||
### Cast | ||
`make deps` | ||
|
||
```shell | ||
$ cast <subcommand> | ||
``` | ||
## Run | ||
|
||
Compile one of the example contracts: | ||
|
||
`racket main.rkt -b examples/add_two.huff` | ||
|
||
## [Optional] Compile executable | ||
|
||
You can do this already with `raco exe main.rkt -o puffc` and then `raco distribute out puffc`. This gives you a directory (called `out`) containing an executable and the required lib. | ||
|
||
I then ran `ln -s /home/z80/dev/puff/out/bin/puffc /home/z80/.local/bin/puffc` to create a symlink in a directory that's in my path, so I can call puffc from anywhere. | ||
|
||
### Help | ||
I'll be automating this in some way but if you're interested, that's how you do it | ||
|
||
```shell | ||
$ forge --help | ||
$ anvil --help | ||
$ cast --help | ||
# Technical Documentation | ||
|
||
## Compiler Phases | ||
|
||
The `compile-src` function illustrates the compilation pipeline | ||
|
||
``` racket | ||
(define (compile-src src) | ||
(~> src | ||
lex ;; src -> tokens | ||
parse ;; tokens -> syntax obj | ||
syntax->datum ;; syntax obj -> AST | ||
analyze-node ;; AST -> compiler data | ||
compile-program-data ;; compiler data -> bytes | ||
bytes->hex)) ;; bytes -> hex string | ||
``` | ||
|
||
### Lexing | ||
|
||
This happens in `puff/lexer.rkt`. In it we define some patterns we want to capture in the source code as specific tokens. This lets us have a much simpler and more explicit grammar. | ||
|
||
### Parsing | ||
|
||
We use the `brag` language to define our grammar in `huffparser.rkt`. With this grammar definintion, we get a `parse` function anywhere just by importing `huffparser.rkt`. | ||
|
||
### Analysis | ||
|
||
We define various phases of analysis in `analysis.rkt`. In this file we do all the work required to go from an AST to a `compiler-data` struct, which is a struct meant to contain all the data required to actually compile a contract. The `compiler-data` object essentiallyu acts as an enhanced AST, all the same data is contained but with the ability to easily and quickly perform lookups on labels, constants, errors, events, etc. | ||
|
||
### Compilation | ||
|
||
This happens in `puff.rkt`, `codegen.rkt`, and all the phases under `puff/phases`. We coordinate the various steps in `puff.rkt` but most of the actual compilation logic is implemented in various handlers in `codegen.rkt ` and the `phases`. |