Dasy Docs

Table of Contents

1. Current Status

Dasy is currently in pre-alpha. The language’s core is still being designed and implemented.

2. Syntax

Dasy has a clojure-inspired lisp syntax with some influences from python. Some constructs are dasy-specific. Most vyper code can be translated by wrapping in parentheses properly. For example, you can assume that for arr.append(10) in Vyper, the equivalent Dasy is (.append arr 10)

2.1. Tuples

Tuples are represented by a quoted list such as '(1 2 3)

The vyper equivalent is (1, 2, 3)

2.2. Arrays

Arrays are represented by a bracketed list, such as [1 2 3]

The vyper equivalent is [1, 2, 3]

2.3. Types

Dasy has all of Vyper’s types. Base types such as uint256 are represented with a dasy ’keyword’, which uses a colon and an identifier. Complex types are represented with a function-call syntax. Arrays are created with array, or dyn-array for dynamic arrays.

Vyper Dasy
uint256 :uint256
bool :bool
bytes32 :bytes32
String[10] (string 10)
uint256[10] (array :uint256 10)
HashMap[uint256, bool] (hash-map :uint256 :bool)
DynArray[uint256, 5] (dyn-array :uint256 5)

2.4. Operators

Dasy has mostly identical operators and builtins as Vyper. There are a few small differences.

2.4.1. Built-in chaining

Binary operations are chained by default in Dasy. This allows you to specify more than two arguments at at time.

Because of this, in Dasy, + functions like a sum operator.

Vyper Dasy
2 + 3 + 4 + 5 (+ 2 3 4 5)
x < y and y < z and z < a (< x y z a)

3. Core Forms

3.1. defn

(defn fn-name args [return-type] visibility & body)

This special form declares and defines a function within a smart contract.

The args list may be an empty list, but must be present. Returning multiple values requires declaring the return type as a tuple.

The return-type object is optional. If present, it may be a single keyword representing the return type, or it may be a tuple of keywords for returning multiple values.

The visibility object may also be a keyword or list of keywords. Valid values are:

  • :external
  • :internal
  • :payable
  • :view
  • :pure
  • (nonreentrant "lock-name")
(defn noArgs [] :external (pass))

(defn setNum [:uint256 x] :external (pass))

(defn addNums [:uint256 x y] :uint256 [:external :pure]
  (+ x y))

(defn addAndSub [:uint256 x y] '(:uint256 :uint256) [:external :pure]
  '((+ x y) (- x y)))

3.2. defvar

(defvar variable-name type [value])

This special form declares and optionally assigns a value to a variable.

Outside of a defn form, variables are stored in storage and accessible via self.variable-name.

Inside a defn form, variables are stored in memory and accessible directly.

The value form is optional.

(defvar owner (public :address))
(defvar enabled :bool)

(defn foo [] :external
  (defvar owner_memory :address self/owner)) ;; declare copy in memory

3.3. setv

(setv name value)

This special form assigns a value to a name. It is roughly equivalent to the equal sign = in Vyper.

;; Create a string variable that can store maximum 100 characters
(defvar greet (public (string 100)))

(defn __init__ [] :external
    (setv self/greet "Hello World")) ;; in vyper: self.greet = "Hello World"

3.4. definterface

(definterface name & fns)

This special form declares an interface.

(definterface TestInterface
  (defn owner [] :address :view)
  (defn setOwner [:address owner] :nonpayable)
  (defn sendEth [] :payable)
  (defn setOwnerAndSendEth [:address owner] :payable))

3.5. defstruct

(defstruct name & variables)

This special form declares a struct. Variables should be declared in pairs of name and type

(defstruct Person
  name (string 100)
  age :uint256)

3.6. defevent

(defevent name & fields)

This special form declares an event. Fields should be declared in pairs of name and type

(defevent Transfer
  sender (indexed :address)
  receiver (indexed :address)
  amount :uint256)

3.7. defconst

(defconst name value)

This special form defines a constant. The value must be provided when defined. This value can never change.

(defconst MIN_AMT 100)
(defconst GREETING "Hello")

3.8. defmacro

(defmacro name args & body)

This special form defines a macro. Macros are functions that run at compile time. Their inputs are code, and their outputs are code. They transform your code as it is built.

Macros can be used to implement convenient shorthand syntaxes. They can also be used to pull in information from the outside world into your contract at build time.

In the most simple terms, macros allow you to extend the Dasy compiler yourself in whichever way you see fit.

;; (set-at myArr 0 100) -> (setv (subscript myArr 0) 100)
(defmacro set-at [array index new-val] `(setv (subscript ~array ~index) ~new-val))

;; (doto obj (.append 10) (.append 20)) -> (do (.append obj 10) (.append obj 20))
(defmacro doto [ obj #*cmds]
  (lfor c cmds
        `(~(get c 0) ~obj ~@(cut c 1 None))))

4. Control Structures

4.1. If

(if test body else-body) If executes a test, and depending on the result, either executes the body or the else-body.

#+beginsrc clojure (if (x < 100)

4.1.1. (return 1) (return 0))

#+endsrc

4.2. Loops

4.2.1. For Loops

for loops can operate on arrays directly, or on a range

(for [i nums]
  (+= sum i))

(for [i [1 2 3 4 5]]
  (+= sum i))

(for [i (range 10)]
  (+= sum i))

In a for loop’s body, continue and break behave the same as they do in Vyper.

(for [i (range 10)]
  (if (== i 5)
    (continue))
  (+= sum i))

5. Errors

5.1. assert

assert behaves as it does in Vyper. It expects a test and an optional error message.

(assert (< x 100) "x must be less than 100")

5.2. raise

raise behaves as it does in Vyper. It expects a message.

(if (>= x 100)
  (raise "x must be less than 100"))

6. Built-in Macros

6.1. /

(setv self/foo bar)

Access object attributes. obj/name is shorthand for (. obj name)

6.2. set-at

(set-at obj index val)

Sets a value at an index within an object. This object can be an array, dynamic array, or hashmap.

This expands to (setv (subscript array index) new-val)

The vyper equivalent looks like obj[index] = val

(defvar arr (array :uint256 10)
        myMap (hash-map :addr :bool))
(set-at arr 0 100) ;; arr[0] = 100
(set-at myMap 0x1234.... True) ;; myMap[0x1234....] = True

6.3. set-in

(set-in obj attr val)

Sets the value of an attribute of an object. This object is usually a struct.

This expands to (setv (. obj attr) val)

(defstruct Person
  name (string 10)
  age :uint256)

(defvar p Person)
(set-in p age 40)
(set-in p name "Vitalik")

6.4. doto

(doto obj & body)

Call multiple functions on the same object. Allows for shorter code.

(doto obj (.foo 10) (.bar 100)) expands to (do (.foo obj 10) (.bar obj 100))

;; above example rewritten with doto
(defstruct Person
  name (string 10)
  age :uint256)

(doto p
  (defvar Person)
  (set-in age 40)
  (set-in name "Vitalik"))

Author: z80

Created: 2022-09-07 Wed 21:19