The much-needed Lisp language for the Ethereum EVM.
$ make
$ ./mist < source.mist
Want to waste some resources? Say no more:
(defun fib (i)
(if (< i 2)
i
(+ (fib (- i 2))
(fib (- i 1)))))
(return (fib 0xBAD))Public contracts most likely would include a dispatcher:
(defvar *balances* (mapping address uint256))
(defvar *allowances* (mapping address (mapping address uint256)))
(defvar *totalSupply* uint256)
(defun totalSupply () *totalSupply*)
(defun balanceOf (address) (gethash *balances* address))
(defun allowance (owner spender) (gethash *allowances* owner spender))
(defun transfer (to value) ...)
(defun transferFrom (from to value) ...)
(defun approve (spender value)
(puthash *allowances* value (caller) spender)
(emit3 "Approval(address,address,uint256)" owner spender value)
t)
(dispatch
("totalSupply()" totalSupply)
("balanceOf(address)" balanceOf)
("allowance(address,address)" allowance)
("transfer(address,uint256)" transfer)
("transferFrom(address,address,uint256)" transferFrom)
("approve(address,uint256)" approve))For an example implementation of an ERC-20 token, please see charm.mist.
- the number
0 - the symbol
nil - any empty list, quoted or not
- any number other than
0 - the symbol
t - any non-empty list, quoted or not
(stop)(-)e.g.(- 20 5)(/)e.g.(/ 10 2)(%)e.g.(% 10 3)(+%)e.g.(+% a b c), shorthand for(% (+ a b) c)(*%)e.g.(*% a b c), shorthand for(% (* a b) c)(**)e.g.(** x y), x to the power of y(expt), an alias for(**)(<)e.g.(< a b)results intifa<b,nilotherwise(>)(=)e.g.(= a b)results intifa==b,nilotherwise(not)e.g.(not t)results inniland(not nil)results int(zerop), an alias for(not)(~), e.g.(~ a)returns the bitwise complement ofa(lognot), an alias for(~)(byte), e.g.(byte index word), see opcodeBYTE(<<), e.g.(<< a b)returns integerawith its bits shifted bybbit positions,(<< 1 4)results in16(>>)(current-address), see opcodeADDRESS(balance), see opcodeBALANCE(origin), see opcodeORIGIN(caller), a.k.a.msg.sender(call-value), value sent with the transaction(calldata-load), low-level access to input transaction data(calldata-size), low-level access to the size of the input data(code-size), low-level access to the size of the currently running code(gas-price), a.k.a. effective gas price(coinbase), current block's beneficiary address(timestamp), current block's timestamp(block-number), current block's number(prev-randao), latest RANDAO mix of the post beacon state of the previous block(gas-limit), current block's gas limit(chain-id)(self-balance), balance of currently executing account(base-fee), current block's base fee(available-gas), amount of available gas (after paying for this instruction)
(+), e.g.(+ 1 2 3 4 5)(*)(&)and its alias(logand)(|)and its alias(logior)(&)and its alias(logxor)
(case), standard Lisp(case), seeexamples/case*.mistfor examples(defconst), give a name to a constant expression(defun), e.g.(defun NAME ARGLIST BODY...), define NAME as function(defvar), e.g.(defvar totalSupply uint256), create a storage variable(emit3), e.g.(emit3 "Transfer(address,address,uint256)" from to value), emit a Log with 3 topics(ether), e.g.(ether "1")results in1e18(gethash TABLE KEYS...), access values in a mapping, e.g.(gethash balances owner)or(gethash allowances owner spender)(if COND A B)results inAifCONDholds andBotherwise(progn BODY...)executes all BODY expressions in a sequence and yields the result of the last one(puthash TABLE VALUE KEYS...), analogous to(gethash), e.g.(puthash balances value owner)or(puthash allowances value owner spender)(return VALUE-OR-STRING)(revert VALUE-OR-STRING)(selector STRING)(setq SYMBOL VALUE)assignsVALUEto the storage variable namedSYMBOL
(<=)(>=)(apply FUNCTION ARGUMENTS...)(dispatch), seeexamples/token.mist(let VARLIST BODY...)(unless COND BODY...)ifCONDyieldsnil, doBODY, else return nil(when COND BODY...)ifCONDyieldst, doBODY, else return nil
These are the only functions do not result in an expression:
(stop)(return x)(revert x)
- Code length can't exceed 2^16 bytes (64 kilobytes).
- Implement real macros.
- Proper error reporting, no
panic()s. Segmentshould be an interface instead of a stateful mess.- Solidity offers a rich assortment of opcode optimizations; perhaps reuse?
- Clean up the public/private mess.
- Proper documentation, more examples, and more tests.
- Deal with linters.