Skip to content

updating documentation to gen2 - main documentation #1642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
May 3, 2025
Merged
79 changes: 44 additions & 35 deletions doc/source/reference/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,42 +53,45 @@ How it looks?

Mandatory fibonacci samples::

def fibR(n) {
if (n < 2) {
return n
} else {
return fibR(n - 1) + fibR(n - 2)
}
}

def fibI(n) {
var last = 0
var cur = 1
for ( i in 0..n-1 ) {
let tmp = cur
cur += last
last = tmp
}
return cur
}

The same samples with significant white space (python style), for those who prefer this type of syntax::

options gen2=false

def fibR(n)
if (n < 2)
if n < 2
return n
else
return fibR(n - 1) + fibR(n - 2)

def fibI(n)
var last = 0
var cur = 1
for i in range(0, n - 1)
for i in 0 .. n-1
let tmp = cur
cur += last
last = tmp
return cur

The same samples with curly brackets, for those who prefer this type of syntax::

def fibR(n) {
if (n < 2) {
return n;
} else {
return fibR(n - 1) + fibR(n - 2);
}
}
def fibI(n) {
var last = 0;
var cur = 1;
for i in range(0, n-1); {
let tmp = cur;
cur += last;
last = tmp;
}
return cur;
}

Please note, that semicolons(';') are mandatory within curly brackets. You can actually mix both ways in your codes, but for clarity in the documentation, we will only use the pythonic way.
At this point gen2 style syntax (with curly bracers) is the default, but you can switch to gen1 style (with indentation) by setting the `gen2` option to `false`.

++++++++++++++++++++++++++++++++++++
Generic programming and type system
Expand All @@ -100,9 +103,11 @@ Generic programming in Daslang allows very powerful compile-time type reflection
Unlike C++ with it's SFINAE, you can use common conditionals (if) in order to change the instance of the function depending on type info of its arguments.
Consider the following example::

def setSomeField(var obj; val)
static_if typeinfo(has_field<someField> obj)
def setSomeField(var obj; val) {
static_if ( typeinfo has_field<someField>(obj) ) {
obj.someField = val
}
}

This function sets `someField` in the provided argument *if* it is a struct with a `someField` member.

Expand All @@ -118,16 +123,20 @@ In fact, the Daslang compiler runs the Daslang interpreter for each module and h
The following example modifies function calls at compilation time to add a precomputed hash of a constant string argument::

[tag_function_macro(tag="get_hint_tag")]
class GetHintFnMacro : AstFunctionAnnotation
[unsafe] def override transform ( var call : smart_ptr<ExprCall>;
var errors : das_string ) : ExpressionPtr
if call.arguments[1] is ExprConstString
let arg2 = reinterpret<ExprConstString?>(call.arguments[1])
var mkc <- new [[ExprConstUInt() at=arg2.at, value=hash("{arg2.value}")]]
push(call.arguments, ExpressionPtr(mkc))
return <- ExpressionPtr(call)
return [[ExpressionPtr]]

class GetHintFnMacro : AstFunctionAnnotation {
def override transform(var call : smart_ptr<ExprCallFunc>; var errors : das_string) : ExpressionPtr {
if (call.arguments[1] is ExprConstString) {
unsafe {
var new_call := call // <- clone_expression(call)
let arg2 = reinterpret<ExprConstString?>(call.arguments[1])
let hint = hash("{arg2.value}")
emplace_new(new_call.arguments, new ExprConstUInt64(at = arg2.at, value = hint))
return new_call
}
}
return <- default<ExpressionPtr>
}
}

++++++++++++++++++++++++++++++++++++
Features
Expand Down
68 changes: 44 additions & 24 deletions doc/source/reference/language/arrays.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ Array
single: Arrays

An array is a sequence of values indexed by an integer number from 0 to the size of the
array minus 1. An array's elements can be obtained by their index.
::
array minus 1. An array's elements can be obtained by their index::

var a = [[int[4] 1; 2; 3; 4]] // fixed size of array is 4, and content is [1, 2, 3, 4]
var a = fixed_array<int>(1, 2, 3, 4) // fixed size of array is 4, and content is [1, 2, 3, 4]
assert(a[0] == 1)

var b: array<int>
Expand All @@ -22,26 +21,25 @@ array minus 1. An array's elements can be obtained by their index.
Alternative syntax is::

var a = fixed_array(1,2,3,4)
var a = fixed_array<int>(1,2,3,4)

There are static arrays (of fixed size, allocated on the stack), and dynamic arrays (size is dynamic, allocated on the heap)::

var a = [[int[4] 1; 2; 3; 4]] // fixed size of array is 4, and content is [1, 2, 3, 4]
var b: array<string> // empty dynamic array
push(b, "some") // now it is 1 element of "some"
b |> push("some") // same as above line, but using pipe operator
var a = fixed_array(1, 2, 3, 4) // fixed size of array is 4, and content is [1, 2, 3, 4]
var b: array<string> // empty dynamic array
push(b, "some") // now it is 1 element of "some"
b |> push("some") // same as above line, but using pipe operator

Dynamic sub-arrays can be created out of any array type via range indexing::

var a = [[int[4] 1; 2; 3; 4]]
let b <- a[1..3] // b is [{int 2;3}]
var a = fixed_array(1,2,3,4)
let b <- a[1..3] // b is [2,3]

In reality `a[b]`, where b is a range, is equivalent to `subarray(a, b)`.

Resizing, insertion, and deletion of dynamic arrays and array elements is done through a set of
standard functions (see :ref:`built-in functions <stdlib__builtin>`).

The relevant builtin functions are: ``push``, ``push_clone``, ``emplace``, ``reserve``, ``resize``, ``erase``, ``length``, ``clear``, and ``capacity``.
The relevant builtin functions are: ``push``, ``push_clone``, ``emplace``, ``reserve``, ``resize``, ``erase``, ``length``, ``clear``, ``empty`` and ``capacity``.

Arrays (as well as tables, structures, and handled types) are passed to functions by reference only.

Expand All @@ -56,34 +54,47 @@ Arrays cannot be copied; only cloned or moved. ::

Arrays can be constructed inline::

let arr = [[auto 1.; 2.; 3.; 4.5]]
let arr = fixed_array(1.,2.,3.,4.5)

This expands to::

let arr : float[4] = [[float[4] 1.; 2.; 3.; 4.5]]
let arr : float[4] = fixed_array<float>(1.,2.,3.,4.5)

Dynamic arrays can also be constructed inline::

let arr <- [{auto "one"; "two"; "three"}]
let arr <- ["one"; "two"; "three"]

This is syntactic equivalent to::

let arr : array<string> <- to_array_move([[string[3] "one"; "two"; "three"]])
let arr : array<string> <- array<string>("one","two","three")

Alternative syntax is::

let arr <- array(1., 2., 3., 4.5)
let arr <- array<float>(1., 2., 3., 4.5)

If only one element is specified, local data construction is of that element::
Arrays of structures can be constructed inline::

let i1 = [[int 1]] // same is the line bellow
let i2 = 1
struct Foo {
x : int = 1
y : int = 2
}

To create an array of an unspecified type, use [] syntax::
var a <- array struct<Foo>((x=11,y=22),(x=33),(y=44)) // dynamic array of Foo with 'construct' syntax (creates 3 different copies of Foo)

let ai1 <- [[int[] 1]] // actually [[int[1] 1]]
let ai2 <- [[auto[] 1] // same as above
Arrays of variants can be constructed inline::

variant Bar {
i : int
f : float
s : string
}

var a <- array variant<Bar>(Bar(i=1), Bar(f=2.), Bar(s="3")) // dynamic array of Bar (creates 3 different copies of Bar)

Arrays of tuples can be constructed inline::

var a <- array tuple<i:int,s:string>((i=1,s="one"),(i=2,s="two"),(i=3,s="three")) // dynamic array of tuples (creates 3 different copies of tuple)

When array elements can't be copied, use ``push_clone`` to insert a clone of a value, or ``emplace`` to move it in.

Expand All @@ -92,10 +103,19 @@ When array elements can't be copied, use ``push_clone`` to insert a clone of a v
``reserve`` is there for performance reasons. Generally, array capacity doubles, if exceeded.
``reserve`` allows you to specify the exact known capacity and significantly reduce the overhead of multiple ``push`` operations.

It's possible to iterate over an array via a regular ``for`` loop::
``empty`` tells you if the dynamic array is empty.

``clear`` clears the array, but does not free the memory. It is equivalent to ``resize(0)``.

``length`` returns the number of elements in the array.

``capacity`` returns the number of elements that can be stored in the array without reallocating.

It's possible to iterate over an array via a regular ``for`` loop. ::

for x in [[int[] 1;2;3;4]]
print("x = {x}\n")
for ( x in [1,2,3,4] ) {
print("x = {x}\n")
}

Additionally, a collection of unsafe iterators is provided::

Expand Down
8 changes: 4 additions & 4 deletions doc/source/reference/language/bitfields.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ Bitfield

Bitfields are a nameless types which represent a collection of up to 32-bit flags in a single integer::

var t : bitfield < one; two; three >
var t : bitfield < one,two,three >

There is a shorthand type alias syntax to define a bitfield::

bitfield bits123
bitfield bits123 {
one
two
three
}

typedef
bits123 = bitfield<one; two; three> // exactly the same as the declaration above
typedef bits123 = bitfield<one; two; three> // exactly the same as the declaration above

Any two bitfields are the same type and represent 32-bit integer::

Expand Down
48 changes: 33 additions & 15 deletions doc/source/reference/language/blocks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The block type can be declared with a function-like syntax::
block_type ::= block { optional_block_type }
optional_block_type ::= < { optional_block_arguments } { : return_type } >
optional_block_arguments := ( block_argument_list )
block_argument_list := argument_name : type | block_argument_list ; argument_name : type
block_argument_list := argument_name : type | block_argument_list , argument_name : type

block < (arg1:int;arg2:float&):bool >

Expand All @@ -23,26 +23,35 @@ Global or local block variables are prohibited; returning the block type is also
def goo ( b : block )
...

def foo ( b : block < (arg1:int; arg2:float&) : bool >
def foo ( b : block < (arg1:int, arg2:float&) : bool >
...

Blocks can be called via ``invoke``::

def radd(var ext:int&;b:block<(var arg:int&):int>):int
def radd(var ext:int&;b:block<(var arg:int&):int>):int {
return invoke(b,ext)
}

Typeless blocks are typically declared via pipe syntax::
There is also a shorthand, where block can be called as if it was a function::

goo() <| // block without arguments
def radd(var ext:int&;b:block<(var arg:int&):int>):int {
return b(ext) // same as invoke(b,ext)
}

Typeless blocks are typically declared via construction-like syntax::

goo() { // block without arguments
print("inside goo")
}

.. _blocks_declarations:

Similarly typed blocks are typically declared via pipe syntax::

var v1 = 1 // block with arguments
res = radd(v1) <| $(var a:int&):int
res = radd(v1) <| $(var a:int&):int {
return a++
}

Blocks can also be declared via inline syntax::

Expand All @@ -59,34 +68,43 @@ block types will be automatically inferred::

Nested blocks are allowed::

def passthroughFoo(a:Foo; blk:block<(b:Foo):void>)
def passthroughFoo(a:Foo; blk:block<(b:Foo):void>) {
invoke(blk,a)
}

passthrough(1) <| $ ( a )
passthrough(1) <| $ ( a ) {
assert(a==1)
passthrough(2) <| $ ( b )
passthrough(2) <| $ ( b ) {
assert(a==1 && b==2)
passthrough(3) <| $ ( c )
passthrough(3) <| $ ( c ) {
assert(a==1 && b==2 && c==3)
}
}
}

Loop control expressions are not allowed to cross block boundaries::

while true
take_any() <|
while ( true ) {
take_any() {
break // 30801, captured block can't break outside the block
}
}

Blocks can have annotations::

def queryOne(dt:float=1.0f)
testProfile::queryEs() <| $ [es] (var pos:float3&;vel:float3 const) // [es] is annotation
def queryOne(dt:float=1.0f) {
testProfile::queryEs() <| $ [es] (var pos:float3&;vel:float3 const) { // [es] is annotation
pos += vel * dt
}
}

Block annotations can be implemented via appropriate macros (see :ref:`Macro <macros>`).

Local block variables are allowed::

var blk = $ <| ( a, b : int )
var blk = $ ( a, b : int ) {
return a + b
}
verify ( 3 == invoke(blk,1,2) )
verify ( 7 == invoke(blk,3,4) )

Expand Down
Loading