| 1 | + | # VDSL Language Syntax |
| 2 | + | |
| 3 | + | VDSL's syntax is designed to be familiar to Go developers while being a bit |
| 4 | + | simpler and more streamlined. |
| 5 | + | |
| 6 | + | **You can test the VDSL code in CVE PoC IDE.** |
| 7 | + | |
| 8 | + | ## Values and Value Types |
| 9 | + | |
| 10 | + | In VDSL, everything is a value, and, all values are associated with a type. |
| 11 | + | |
| 12 | + | ```golang |
| 13 | + | 11 + 22 // int values |
| 14 | + | "aa" + `bb` // string values |
| 15 | + | -1.22 + 3e9 // float values |
| 16 | + | true || false // bool values |
| 17 | + | '七' > '7' // char values |
| 18 | + | [33, false, "xx"] // array value |
| 19 | + | {a: true, b: "oo"} // map value |
| 20 | + | func() { /*...*/ } // function value |
| 21 | + | ``` |
| 22 | + | |
| 23 | + | Here's a list of all available value types in VDSL. |
| 24 | + | |
| 25 | + | | VDSL Type | Description | Equivalent Type in Go | |
| 26 | + | | :---: | :---: | :---: | |
| 27 | + | | int | signed 64-bit integer value | `int64` | |
| 28 | + | | float | 64-bit floating point value | `float64` | |
| 29 | + | | bool | boolean value | `bool` | |
| 30 | + | | char | unicode character | `rune` | |
| 31 | + | | string | unicode string | `string` | |
| 32 | + | | bytes | byte array | `[]byte` | |
| 33 | + | | error | [error](#error-values) value | - | |
| 34 | + | | time | time value | `time.Time` | |
| 35 | + | | array | value array _(mutable)_ | `[]any` | |
| 36 | + | | const array | [const](#const-values) array | - | |
| 37 | + | | map | value map with string keys _(mutable)_ | `map[string]any` | |
| 38 | + | | const map | [const](#const-values) map | - | |
| 39 | + | | nil | [nil](#nil-values) value | - | |
| 40 | + | | function | [function](#function-values) value | - | |
| 41 | + | | _user-defined_ | value of [user-defined types](https://github.com/Safe3/dsl/blob/master/docs/objects.md) | - | |
| 42 | + | |
| 43 | + | ### Error Values |
| 44 | + | |
| 45 | + | In VDSL, an error can be represented using "error" typed values. An error |
| 46 | + | value is created using `error` expression, and, it must have an underlying |
| 47 | + | value. The underlying value of an error value can be access using `.value` |
| 48 | + | selector. |
| 49 | + | |
| 50 | + | ```golang |
| 51 | + | err1 := error("oops") // error with string value |
| 52 | + | err2 := error(1+2+3) // error with int value |
| 53 | + | if is_error(err1) { // 'is_error' builtin function |
| 54 | + | err_val := err1.value // get underlying value |
| 55 | + | } |
| 56 | + | ``` |
| 57 | + | |
| 58 | + | ### Const Values |
| 59 | + | |
| 60 | + | In VDSL, basically all values (except for array and map) are const. |
| 61 | + | |
| 62 | + | ```golang |
| 63 | + | s := "12345" |
| 64 | + | s[1] = 'b' // illegal: String is const |
| 65 | + | |
| 66 | + | a := [1, 2, 3] |
| 67 | + | a[1] = "two" // ok: a is now [1, "two", 3] |
| 68 | + | ``` |
| 69 | + | |
| 70 | + | An array or map value can be made const using `const` expression. |
| 71 | + | |
| 72 | + | ```golang |
| 73 | + | b := const([1, 2, 3]) |
| 74 | + | b[1] = "foo" // illegal: 'b' references to an const array. |
| 75 | + | ``` |
| 76 | + | |
| 77 | + | Note that re-assigning a new value to the variable has nothing to do with the |
| 78 | + | value immutability. |
| 79 | + | |
| 80 | + | ```golang |
| 81 | + | s := "abc" |
| 82 | + | s = "foo" // ok |
| 83 | + | a := const([1, 2, 3]) |
| 84 | + | a = false // ok |
| 85 | + | ``` |
| 86 | + | |
| 87 | + | Note that, if you copy (using `copy` builtin function) an const value, it |
| 88 | + | will return a "mutable" copy. Also, immutability is not applied to the |
| 89 | + | individual elements of the array or map value, unless they are explicitly made |
| 90 | + | const. |
| 91 | + | |
| 92 | + | ```golang |
| 93 | + | a := const({b: 4, c: [1, 2, 3]}) |
| 94 | + | a.b = 5 // illegal |
| 95 | + | a.c[1] = 5 // ok: because 'a.c' is not const |
| 96 | + | |
| 97 | + | a = const({b: 4, c: const([1, 2, 3])}) |
| 98 | + | a.c[1] = 5 // illegal |
| 99 | + | ``` |
| 100 | + | |
| 101 | + | ### Nil Values |
| 102 | + | |
| 103 | + | In VDSL, an "nil" value can be used to represent an unexpected or |
| 104 | + | non-existing value: |
| 105 | + | |
| 106 | + | - A function that does not return a value explicitly considered to return |
| 107 | + | `nil` value. |
| 108 | + | - Indexer or selector on composite value types may return `nil` if the |
| 109 | + | key or index does not exist. |
| 110 | + | - Type conversion builtin functions without a default value will return |
| 111 | + | `nil` if conversion fails. |
| 112 | + | |
| 113 | + | ```golang |
| 114 | + | a := func() { b := 4 }() // a == nil |
| 115 | + | b := [1, 2, 3][10] // b == nil |
| 116 | + | c := {a: "foo"}["b"] // c == nil |
| 117 | + | d := int("foo") // d == nil |
| 118 | + | ``` |
| 119 | + | |
| 120 | + | ### Array Values |
| 121 | + | |
| 122 | + | In VDSL, array is an ordered list of values of any types. Elements of an array |
| 123 | + | can be accessed using indexer `[]`. |
| 124 | + | |
| 125 | + | ```golang |
| 126 | + | [1, 2, 3][0] // == 1 |
| 127 | + | [1, 2, 3][2] // == 3 |
| 128 | + | [1, 2, 3][3] // == nil |
| 129 | + | |
| 130 | + | ["foo", "bar", [1, 2, 3]] // ok: array with an array element |
| 131 | + | ``` |
| 132 | + | |
| 133 | + | ### Map Values |
| 134 | + | |
| 135 | + | In VDSL, map is a set of key-value pairs where key is string and the value is |
| 136 | + | of any value types. Value of a map can be accessed using indexer `[]` or |
| 137 | + | selector '.' operators. |
| 138 | + | |
| 139 | + | ```golang |
| 140 | + | m := { a: 1, b: false, c: "foo" } |
| 141 | + | m["b"] // == false |
| 142 | + | m.c // == "foo" |
| 143 | + | m.x // == nil |
| 144 | + | |
| 145 | + | {a: [1,2,3], b: {c: "foo", d: "bar"}} // ok: map with an array element and a map element |
| 146 | + | ``` |
| 147 | + | |
| 148 | + | ### Function Values |
| 149 | + | |
| 150 | + | In VDSL, function is a callable value with a number of function arguments and |
| 151 | + | a return value. Just like any other values, functions can be passed into or |
| 152 | + | returned from another function. |
| 153 | + | |
| 154 | + | ```golang |
| 155 | + | my_func := func(arg1, arg2) { |
| 156 | + | return arg1 + arg2 |
| 157 | + | } |
| 158 | + | |
| 159 | + | adder := func(base) { |
| 160 | + | return func(x) { return base + x } // capturing 'base' |
| 161 | + | } |
| 162 | + | add5 := adder(5) |
| 163 | + | nine := add5(4) // == 9 |
| 164 | + | ``` |
| 165 | + | |
| 166 | + | Unlike Go, VDSL does not have declarations. So the following code is illegal: |
| 167 | + | |
| 168 | + | ```golang |
| 169 | + | func my_func(arg1, arg2) { // illegal |
| 170 | + | return arg1 + arg2 |
| 171 | + | } |
| 172 | + | ``` |
| 173 | + | |
| 174 | + | VDSL also supports variadic functions/closures: |
| 175 | + | |
| 176 | + | ```golang |
| 177 | + | variadic := func (a, b, ...c) { |
| 178 | + | return [a, b, c] |
| 179 | + | } |
| 180 | + | variadic(1, 2, 3, 4) // [1, 2, [3, 4]] |
| 181 | + | |
| 182 | + | variadicClosure := func(a) { |
| 183 | + | return func(b, ...c) { |
| 184 | + | return [a, b, c] |
| 185 | + | } |
| 186 | + | } |
| 187 | + | variadicClosure(1)(2, 3, 4) // [1, 2, [3, 4]] |
| 188 | + | ``` |
| 189 | + | |
| 190 | + | Only the last parameter can be variadic. The following code is also illegal: |
| 191 | + | |
| 192 | + | ```golang |
| 193 | + | // illegal, because a is variadic and is not the last parameter |
| 194 | + | illegal := func(a..., b) { /*... */ } |
| 195 | + | ``` |
| 196 | + | |
| 197 | + | When calling a function, the number of passing arguments must match that of |
| 198 | + | function definition. |
| 199 | + | |
| 200 | + | ```golang |
| 201 | + | f := func(a, b) {} |
| 202 | + | f(1, 2, 3) // Runtime Error: wrong number of arguments: want=2, got=3 |
| 203 | + | ``` |
| 204 | + | |
| 205 | + | Like Go, you can use ellipsis `...` to pass array-type value as its last parameter: |
| 206 | + | |
| 207 | + | ```golang |
| 208 | + | f1 := func(a, b, c) { return a + b + c } |
| 209 | + | f1([1, 2, 3]...) // => 6 |
| 210 | + | f1(1, [2, 3]...) // => 6 |
| 211 | + | f1(1, 2, [3]...) // => 6 |
| 212 | + | f1([1, 2]...) // Runtime Error: wrong number of arguments: want=3, got=2 |
| 213 | + | |
| 214 | + | f2 := func(a, ...b) {} |
| 215 | + | f2(1) // valid; a = 1, b = [] |
| 216 | + | f2(1, 2) // valid; a = 1, b = [2] |
| 217 | + | f2(1, 2, 3) // valid; a = 1, b = [2, 3] |
| 218 | + | f2([1, 2, 3]...) // valid; a = 1, b = [2, 3] |
| 219 | + | ``` |
| 220 | + | |
| 221 | + | ## Variables and Scopes |
| 222 | + | |
| 223 | + | A value can be assigned to a variable using assignment operator `:=` and `=`. |
| 224 | + | |
| 225 | + | - `:=` operator defines a new variable in the scope and assigns a value. |
| 226 | + | - `=` operator assigns a new value to an existing variable in the scope. |
| 227 | + | |
| 228 | + | Variables are defined either in global scope (defined outside function) or in |
| 229 | + | local scope (defined inside function). |
| 230 | + | |
| 231 | + | ```golang |
| 232 | + | a := "foo" // define 'a' in global scope |
| 233 | + | |
| 234 | + | func() { // function scope A |
| 235 | + | b := 52 // define 'b' in function scope A |
| 236 | + | |
| 237 | + | func() { // function scope B |
| 238 | + | c := 19.84 // define 'c' in function scope B |
| 239 | + | |
| 240 | + | a = "bee" // ok: assign new value to 'a' from global scope |
| 241 | + | b = 20 // ok: assign new value to 'b' from function scope A |
| 242 | + | |
| 243 | + | b := true // ok: define new 'b' in function scope B |
| 244 | + | // (shadowing 'b' from function scope A) |
| 245 | + | } |
| 246 | + | |
| 247 | + | a = "bar" // ok: assigne new value to 'a' from global scope |
| 248 | + | b = 10 // ok: assigne new value to 'b' |
| 249 | + | a := -100 // ok: define new 'a' in function scope A |
| 250 | + | // (shadowing 'a' from global scope) |
| 251 | + | |
| 252 | + | c = -9.1 // illegal: 'c' is not defined |
| 253 | + | b := [1, 2] // illegal: 'b' is already defined in the same scope |
| 254 | + | } |
| 255 | + | |
| 256 | + | b = 25 // illegal: 'b' is not defined |
| 257 | + | a := {d: 2} // illegal: 'a' is already defined in the same scope |
| 258 | + | ``` |
| 259 | + | |
| 260 | + | Unlike Go, a variable can be assigned a value of different types. |
| 261 | + | |
| 262 | + | ```golang |
| 263 | + | a := 123 // assigned 'int' |
| 264 | + | a = "123" // re-assigned 'string' |
| 265 | + | a = [1, 2, 3] // re-assigned 'array' |
| 266 | + | ``` |
| 267 | + | |
| 268 | + | ## Type Conversions |
| 269 | + | |
| 270 | + | Although the type is not directly specified in VDSL, one can use type |
| 271 | + | conversion |
| 272 | + | [builtin functions](https://github.com/Safe3/dsl/blob/master/docs/builtins.md) |
| 273 | + | to convert between value types. |
| 274 | + | |
| 275 | + | ```golang |
| 276 | + | s1 := string(1984) // "1984" |
| 277 | + | i2 := int("-999") // -999 |
| 278 | + | f3 := float(-51) // -51.0 |
| 279 | + | b4 := bool(1) // true |
| 280 | + | c5 := char("X") // 'X' |
| 281 | + | ``` |
| 282 | + | |
| 283 | + | See [Operators](https://github.com/Safe3/dsl/blob/master/docs/operators.md) |
| 284 | + | for more details on type coercions. |
| 285 | + | |
| 286 | + | ## Operators |
| 287 | + | |
| 288 | + | ### Unary Operators |
| 289 | + | |
| 290 | + | | Operator | Usage | Types | |
| 291 | + | | :---: | :---: | :---: | |
| 292 | + | | `+` | same as `0 + x` | int, float | |
| 293 | + | | `-` | same as `0 - x` | int, float | |
| 294 | + | | `!` | logical NOT | all types* | |
| 295 | + | | `^` | bitwise complement | int | |
| 296 | + | |
| 297 | + | _In VDSL, all values can be either |
| 298 | + | [truthy or falsy](https://github.com/Safe3/dsl/blob/d5-patch-1/docs/runtime-types.md#objectisfalsy)._ |
| 299 | + | |
| 300 | + | ### Binary Operators |
| 301 | + | |
| 302 | + | | Operator | Usage | Types | |
| 303 | + | | :---: | :---: | :---: | |
| 304 | + | | `==` | equal | all types | |
| 305 | + | | `!=` | not equal | all types | |
| 306 | + | | `&&` | logical AND | all types | |
| 307 | + | | `\|\|` | logical OR | all types | |
| 308 | + | | `+` | add/concat | int, float, string, char, time, array | |
| 309 | + | | `-` | subtract | int, float, char, time | |
| 310 | + | | `*` | multiply | int, float | |
| 311 | + | | `/` | divide | int, float | |
| 312 | + | | `&` | bitwise AND | int | |
| 313 | + | | `\|` | bitwise OR | int | |
| 314 | + | | `^` | bitwise XOR | int | |
| 315 | + | | `&^` | bitclear (AND NOT) | int | |
| 316 | + | | `<<` | shift left | int | |
| 317 | + | | `>>` | shift right | int | |
| 318 | + | | `<` | less than | int, float, char, time, string | |
| 319 | + | | `<=` | less than or equal to | int, float, char, time, string | |
| 320 | + | | `>` | greater than | int, float, char, time, string | |
| 321 | + | | `>=` | greater than or equal to | int, float, char, time, string | |
| 322 | + | |
| 323 | + | _See [Operators](https://github.com/Safe3/dsl/blob/master/docs/operators.md) |
| 324 | + | for more details._ |
| 325 | + | |
| 326 | + | ### Ternary Operators |
| 327 | + | |
| 328 | + | VDSL has a ternary conditional operator `(condition expression) ? (true expression) : (false expression)`. |
| 329 | + | |
| 330 | + | ```golang |
| 331 | + | a := true ? 1 : -1 // a == 1 |
| 332 | + | |
| 333 | + | min := func(a, b) { |
| 334 | + | return a < b ? a : b |
| 335 | + | } |
| 336 | + | b := min(5, 10) // b == 5 |
| 337 | + | ``` |
| 338 | + | |
| 339 | + | ### Assignment and Increment Operators |
| 340 | + | |
| 341 | + | | Operator | Usage | |
| 342 | + | | :---: | :---: | |
| 343 | + | | `+=` | `(lhs) = (lhs) + (rhs)` | |
| 344 | + | | `-=` | `(lhs) = (lhs) - (rhs)` | |
| 345 | + | | `*=` | `(lhs) = (lhs) * (rhs)` | |
| 346 | + | | `/=` | `(lhs) = (lhs) / (rhs)` | |
| 347 | + | | `%=` | `(lhs) = (lhs) % (rhs)` | |
| 348 | + | | `&=` | `(lhs) = (lhs) & (rhs)` | |
| 349 | + | | `\|=` | `(lhs) = (lhs) \| (rhs)` | |
| 350 | + | | `&^=` | `(lhs) = (lhs) &^ (rhs)` | |
| 351 | + | | `^=` | `(lhs) = (lhs) ^ (rhs)` | |
| 352 | + | | `<<=` | `(lhs) = (lhs) << (rhs)` | |
| 353 | + | | `>>=` | `(lhs) = (lhs) >> (rhs)` | |
| 354 | + | | `++` | `(lhs) = (lhs) + 1` | |
| 355 | + | | `--` | `(lhs) = (lhs) - 1` | |
| 356 | + | |
| 357 | + | ### Operator Precedences |
| 358 | + | |
| 359 | + | Unary operators have the highest precedence, and, ternary operator has the |
| 360 | + | lowest precedence. There are five precedence levels for binary operators. |
| 361 | + | Multiplication operators bind strongest, followed by addition operators, |
| 362 | + | comparison operators, `&&` (logical AND), and finally `||` (logical OR): |
| 363 | + | |
| 364 | + | | Precedence | Operator | |
| 365 | + | | :---: | :---: | |
| 366 | + | | 5 | `*` `/` `%` `<<` `>>` `&` `&^` | |
| 367 | + | | 4 | `+` `-` `\|` `^` | |
| 368 | + | | 3 | `==` `!=` `<` `<=` `>` `>=` | |
| 369 | + | | 2 | `&&` | |
| 370 | + | | 1 | `\|\|` | |
| 371 | + | |
| 372 | + | Like Go, `++` and `--` operators form statements, not expressions, they fall |
| 373 | + | outside the operator hierarchy. |
| 374 | + | |
| 375 | + | ### Selector and Indexer |
| 376 | + | |
| 377 | + | One can use selector (`.`) and indexer (`[]`) operators to read or write |
| 378 | + | elements of composite types (array, map, string, bytes). |
| 379 | + | |
| 380 | + | ```golang |
| 381 | + | ["one", "two", "three"][1] // == "two" |
| 382 | + | |
| 383 | + | m := { |
| 384 | + | a: 1, |
| 385 | + | b: [2, 3, 4], |
| 386 | + | c: func() { return 10 } |
| 387 | + | } |
| 388 | + | m.a // == 1 |
| 389 | + | m["b"][1] // == 3 |
| 390 | + | m.c() // == 10 |
| 391 | + | m.x = 5 // add 'x' to map 'm' |
| 392 | + | m["b"][5] // == nil |
| 393 | + | m["b"][5].d // == nil |
| 394 | + | m.b[5] = 0 // == nil |
| 395 | + | m.x.y.z // == nil |
| 396 | + | ``` |
| 397 | + | |
| 398 | + | Like Go, one can use slice operator `[:]` for sequence value types such as |
| 399 | + | array, string, bytes. |
| 400 | + | |
| 401 | + | ```golang |
| 402 | + | a := [1, 2, 3, 4, 5][1:3] // == [2, 3] |
| 403 | + | b := [1, 2, 3, 4, 5][3:] // == [4, 5] |
| 404 | + | c := [1, 2, 3, 4, 5][:3] // == [1, 2, 3] |
| 405 | + | d := "hello world"[2:10] // == "llo worl" |
| 406 | + | c := [1, 2, 3, 4, 5][-1:10] // == [1, 2, 3, 4, 5] |
| 407 | + | ``` |
| 408 | + | |
| 409 | + | **Note: Keywords cannot be used as selectors.** |
| 410 | + | |
| 411 | + | ```golang |
| 412 | + | a := {in: true} // Parse Error: expected map key, found 'in' |
| 413 | + | a.func = "" // Parse Error: expected selector, found 'func' |
| 414 | + | ``` |
| 415 | + | |
| 416 | + | Use double quotes and indexer to use keywords with maps. |
| 417 | + | |
| 418 | + | ```golang |
| 419 | + | a := {"in": true} |
| 420 | + | a["func"] = "" |
| 421 | + | ``` |
| 422 | + | |
| 423 | + | ## Statements |
| 424 | + | |
| 425 | + | ### If Statement |
| 426 | + | |
| 427 | + | "If" statement is very similar to Go. |
| 428 | + | |
| 429 | + | ```golang |
| 430 | + | if a < 0 { |
| 431 | + | // execute if 'a' is negative |
| 432 | + | } else if a == 0 { |
| 433 | + | // execute if 'a' is zero |
| 434 | + | } else { |
| 435 | + | // execute if 'a' is positive |
| 436 | + | } |
| 437 | + | ``` |
| 438 | + | |
| 439 | + | Like Go, the condition expression may be preceded by a simple statement, |
| 440 | + | which executes before the expression is evaluated. |
| 441 | + | |
| 442 | + | ```golang |
| 443 | + | if a := foo(); a < 0 { |
| 444 | + | // execute if 'a' is negative |
| 445 | + | } |
| 446 | + | ``` |
| 447 | + | |
| 448 | + | ### For Statement |
| 449 | + | |
| 450 | + | "For" statement is very similar to Go. |
| 451 | + | |
| 452 | + | ```golang |
| 453 | + | // for (init); (condition); (post) {} |
| 454 | + | for a:=0; a<10; a++ { |
| 455 | + | // ... |
| 456 | + | } |
| 457 | + | |
| 458 | + | // for (condition) {} |
| 459 | + | for a < 10 { |
| 460 | + | // ... |
| 461 | + | } |
| 462 | + | |
| 463 | + | // for {} |
| 464 | + | for { |
| 465 | + | // ... |
| 466 | + | } |
| 467 | + | ``` |
| 468 | + | |
| 469 | + | ### For-In Statement |
| 470 | + | |
| 471 | + | "For-In" statement is new in VDSL. It's similar to Go's `for range` statement. |
| 472 | + | "For-In" statement can iterate any iterable value types (array, map, bytes, |
| 473 | + | string, nil). |
| 474 | + | |
| 475 | + | ```golang |
| 476 | + | for v in [1, 2, 3] { // array: element |
| 477 | + | // 'v' is value |
| 478 | + | } |
| 479 | + | for i, v in [1, 2, 3] { // array: index and element |
| 480 | + | // 'i' is index |
| 481 | + | // 'v' is value |
| 482 | + | } |
| 483 | + | for k, v in {k1: 1, k2: 2} { // map: key and value |
| 484 | + | // 'k' is key |
| 485 | + | // 'v' is value |
| 486 | + | } |
| 487 | + | ``` |
| 488 | + | |
| 489 | + | ## Modules |
| 490 | + | |
| 491 | + | Module is the basic compilation unit in VDSL. A module can import another |
| 492 | + | module using `import` expression. |
| 493 | + | |
| 494 | + | Main module: |
| 495 | + | |
| 496 | + | ```golang |
| 497 | + | sum := import("./sum") // load module from a local file |
| 498 | + | fmt.print(sum(10)) // module function |
| 499 | + | ``` |
| 500 | + | |
| 501 | + | Another module in `sum.dsl` file: |
| 502 | + | |
| 503 | + | ```golang |
| 504 | + | base := 5 |
| 505 | + | |
| 506 | + | export func(x) { |
| 507 | + | return x + base |
| 508 | + | } |
| 509 | + | ``` |
| 510 | + | |
| 511 | + | By default, `import` solves the missing extension name of a module file as |
| 512 | + | "`.dsl`"[^note]. |
| 513 | + | Thus, `sum := import("./sum")` is equivalent to `sum := import("./sum.dsl")`. |
| 514 | + | |
| 515 | + | [^note]: |
| 516 | + | If using VDSL as a library in Go, the file extension name "`.dsl`" can |
| 517 | + | be customized. In that case, use the `SetImportFileExt` function of the |
| 518 | + | `Compiler` type. |
| 519 | + | See the [Go reference](https://pkg.go.dev/dsl) for details. |
| 520 | + | |
| 521 | + | In VDSL, modules are very similar to functions. |
| 522 | + | |
| 523 | + | - `import` expression loads the module code and execute it like a function. |
| 524 | + | - Module should return a value using `export` statement. |
| 525 | + | - Module can return `export` a value of any types: int, map, function, etc. |
| 526 | + | - `export` in a module is like `return` in a function: it stops execution and |
| 527 | + | return a value to the importing code. |
| 528 | + | - `export`-ed values are always const. |
| 529 | + | - If the module does not have any `export` statement, `import` expression |
| 530 | + | simply returns `nil`. _(Just like the function that has no `return`.)_ |
| 531 | + | - Note that `export` statement is completely ignored and not evaluated if |
| 532 | + | the code is executed as a main module. |
| 533 | + | |
| 534 | + | Also, you can use `import` expression to load the |
| 535 | + | [Standard Library](https://github.com/Safe3/dsl/blob/master/docs/stdlib.md) as |
| 536 | + | well. |
| 537 | + | |
| 538 | + | ```golang |
| 539 | + | math := import("math") |
| 540 | + | a := math.abs(-19.84) // == 19.84 |
| 541 | + | ``` |
| 542 | + | |
| 543 | + | ## Comments |
| 544 | + | |
| 545 | + | Like Go, VDSL supports line comments (`//...`) and block comments |
| 546 | + | (`/* ... */`). |
| 547 | + | |
| 548 | + | ```golang |
| 549 | + | /* |
| 550 | + | multi-line block comments |
| 551 | + | */ |
| 552 | + | |
| 553 | + | a := 5 // line comments |
| 554 | + | ``` |
| 555 | + | |
| 556 | + | ## Differences from Go |
| 557 | + | |
| 558 | + | Unlike Go, VDSL does not have the following: |
| 559 | + | |
| 560 | + | - Declarations |
| 561 | + | - Imaginary values |
| 562 | + | - Structs |
| 563 | + | - Pointers |
| 564 | + | - Channels |
| 565 | + | - Goroutines |
| 566 | + | - Tuple assignment |
| 567 | + | - Variable parameters |
| 568 | + | - Switch statement |
| 569 | + | - Goto statement |
| 570 | + | - Defer statement |
| 571 | + | - Panic |
| 572 | + | - Type assertion |
| 573 | + | |