/* String example */

pub struct string {
	len usize;
	buf *u8;
}

pub init(mut s *string)
{
	s.len = 0;
	s.buf = null;
}

pub deinit(mut s *string)
{
	dealloc(s.buf);
}

pub init(mut s *string, u *u8)
{
	len usize = 0;
	r any = u;
	while r++ {len++;}

	s.len = len;
	s.buf = alloc(s.len);
	memcpy(s.buf, u);
}

pub copy(mut r *string, s *string) *string
{
	dealloc(r.buf);
	r.len = s.len;
	r.buf = alloc(r.len);
	memcpy(r.buf, s.buf);
}

pub move(mut r *string, mut s *string) *string
{
	dealloc(r.buf);
	r.len = s.len;
	r.buf = s.buf;
	s.buf = null;
	s.len = 0;
}

pub length(s *string) usize
{
	return s.len;
}

pub index(s *string, i usize) u8
{
	assert(i < len, "index %zu out of bounds\n", i);
	return s.buf[i];
}

pub add(r *string, a *string, b *string)
{
	len any = length(a) + length(b);
	buf any = alloc(l);

	if r.buf == a.buf {
		dealloc(a.buf);
	} else if r.buf == b.buf {
		dealloc(b.buf);
	}

	r.buf = buf;
	r.len = len;
}

/* example of hygienic and recursive macros.
   In macros, the last statement of the block is taken as the "return" value,
   so the following two definitions would be enough to get the smallest
   value of any number of parameters, without affecting any variables in
   the parent context. If recursive blocks, the last of the blocks is taken.

   In this case, the same thing could be done with functions of course.

   Internally, if one of these macros is passed as a function argument, all
   statements except the last (which has to be a certain type,
   have to check exactly which rules I want to apply to it) will be moved
   into the nearest "regular" context, i.e. not a function call in a function
   call or something like that. The last variable's context is kept as the block
   in which it was defined, but accessed "anonymously". In C, something like

   // some counter to make sure we don't overlap some other variable
   int min_res_12345;
   {
	const int _a = a;
	const int _b = b;

	const int _res = _a < _b ? _a : _b;
	min_res_12345 = _res;
   }
   call(min_res_12345);

   */
define min(a, b) {{
	_a const = a;
	_b const = b;

	_res const = if _a < _b {
		_a
	} else {
		_b
	};

	_res;
}}

define min(a, b ...args) {{
	_a const = a;
	_b const = min(b, ...args);
	
	_res const = if _a < _b {
		_a
	} else {
		_b
	};

	_res;
}}

pub define new(x ...args)
{
	x = alloc(sizeof(x));
	init(@ ...args);
}

pub define ctx(x ...args)
{
	init(&x ...args);
	defer(deinit(@));
}

main(argc i32, argv [argc] * u8)
{
	something = argv[10]; // run type bounds checking for ranged array?
	// will not be automatically freed
	new(a *string);
	new(b *string, "hello");
	c string; // undefined state
	// will be automatically 'freed'
	ctx(c string);
	ctx(v vec<string>);
	append(v, a);
	append(v, c);
}
