// Construction syntax

syntax array_initialization from "<" Arg(<type>, type) ">[" [{Arg(<expr>, elems) "," [s]} Arg(<expr>, elems)] "]" {
    let res = arr<$type>();

    @elems.i {
        res.push($elems.i);
    }
    
    return move(res);
}

syntax list_comprehension from "[" [s] Arg(<expr>, map) s "for" s Arg(<ident>, it) [s] ":" [s] Arg(<type>, type) s "in" s Arg(<expr>, container) [s] "]" {
    let res = arr<$type>();
    let func = ($it: $type) -> $type $map;

    for _it_ in $container {
        res.push(func(*_it_));
    \}
    
    return move(res);
}

// Algorithms

fn<T> arr_with_capacity(size: Int) -> Array<'T> {
    let res = arr<'T>();
    res.reserve(move(size));
    
    return move(res);
}

fn<T> fill(array: @Array<'T>, value: 'T) -> @Array<'T> {
    while array.capacity() > array.len() {
        array.push(*value);
    }

    return array;
}

fn<T> fill_with(array: @Array<'T>, f: Int => 'T) -> @Array<'T> {
    let idx = array.len();

    while array.capacity() > array.len() {
        array.push(f(*idx));
        idx.inc();
    }

    return array;
}

fn<T, G> transform(array: @Array<'T>, f: 'T => 'G) -> Array<'G> {
    let res = arr_with_capacity<'G>(array.len());

    for i in array {
        res.push(f(*i));
    }

    return move(res);
}

fn<T> transform_inplace(array: @Array<'T>, f: 'T => 'T) -> @Array<'T> {
    for i in array {
        i := f(*i);
    }

    return array;
}

fn<T> reverse(array: @Array<'T>) -> @Array<'T> {
    let length = array.len();
    let half = length / 2;
    let i = 0;
    
    while i < half {
        swap(array[*i], array[length - i - 1]);
        i.inc();
    }

    return array;
}

fn<T> reduce(array: @Array<'T>, base: 'T, op: ('T, 'T) => 'T) -> 'T {
    for i in array {
        base := op(*base, *i);
    }

    return move(base);
}

// Printable interface

fn<T> print(array: Array<'T [Printable]>) {
    let idx = 0;

    print("[");

    for i in array {
        print(*i);

        idx.inc();

        if idx < array.len() {
            print(", ");
        }
    }

    print("]");
}

implement<T> Printable for Array<'T [Printable]>;