shithub: lpa

ref: a062a0574fa9bbff7f3cb62251b41d42a441440f
dir: /array.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>

#include "dat.h"
#include "fns.h"

/* This file is the only file that knows how arrays are stored.
 * In theory, that allows us to experiment with other representations later.
 */

struct Array
{
	int type;
	int rank;
	usize size;
	usize *shape;
	union {
		void *data;
		vlong *intdata;
		Rune *chardata;
		Array **arraydata;
	};
};

void 
initarrays(void)
{
	dataspecs[DataArray].size = sizeof(Array);
}

Array *
allocarray(int type, int rank, usize size)
{
	Array *a = alloc(DataArray);
	a->type = type;
	a->rank = rank;
	a->size = size;

	switch(type){
	case TypeNumber:
		size *= sizeof(vlong);
		break;
	case TypeChar:
		size *= sizeof(Rune);
		break;
	case TypeArray:
		size *= sizeof(Array *);
		break;
	}

	a->shape = allocextra(a, (sizeof(usize) * rank) + size);
	a->data = (void*)(a->shape+rank);

	return a;
}

void
setint(Array *a, usize offset, vlong v)
{
	a->intdata[offset] = v;
}

void
setarray(Array *a, usize offset, Array *v)
{
	a->arraydata[offset] = v;
}

void
setshape(Array *a, int dim, usize size)
{
	a->shape[dim] = size;
}

static int printarraysub(char *, Array *, int);
static int
printitem(char *p, Array *a, uvlong i, int depth)
{
	switch(a->type){
	case TypeNumber:
		return sprint(p, "%lld", a->intdata[i]);
	case TypeChar:
		return sprint(p, "%C", a->chardata[i]);
	case TypeArray:
		return printarraysub(p, a->arraydata[i], depth);
	default:
		return sprint(p, "???");
	}	
}

static int
indent(char *buf, int depth)
{
	char *p = buf;
	for(int i = 0; i < depth; i++)
		p += sprint(p, " ");
	return p-buf;
}

static int
printarraysub(char *buf, Array *a, int depth)
{
	char *p = buf;

	if(a->rank == 0){
		p += printitem(p, a, 0, depth);
		goto end;
	}else if(a->rank == 1 && a->type == TypeNumber){
		if(a->size == 0)
			p += sprint(p, "⍬");
		for(uvlong i = 0; i < a->size; i++){
			if(i != 0)
				p += sprint(p, " ");
			p += printitem(p, a, i, depth);
		}
		goto end;
	}else if(a->rank == 1 && a->type == TypeChar){
		p += sprint(p, "'");
		for(uvlong i = 0; i < a->size; i++)
			p += printitem(p, a, i, depth); /* TODO: quoting */
		p += sprint(p, "'");
		goto end;
	}else if(a->rank == 1 && a->type == TypeArray){
		if(a->size == 0){
			p += sprint(p, "( ⋄ )");
			goto end;
		}
		p += sprint(p, "(");
		for(uvlong i = 0; i < a->size; i++){
			if(i != 0){
				p += sprint(p, "\n");
				p += indent(p, depth+1);
			}	
			p += printitem(p, a, i, depth+1);
		}
		p += sprint(p, ")");
		goto end;
	}

	p += sprint(p, "Some array I can't print yet");
end:
	return p-buf;
}

char *
printarray(Array *a)
{
	char buf[2048]; /* TODO: fixed size :) */
	printarraysub(buf, a, 0);
	return buf;
}

static int
addspace(char *p)
{
	if(*(p-1) == ' ')
		return 0;
	else
		return sprint(p, " ");
}

static int
printexpr(char *start, Ast *e, int left)
{
	if(e == nil)
		return sprint(start, "{?nil?}");

	char *p = start;
	int paren = 0;
	if(left){
		switch(e->tag){
		case AstAssign:
		case AstMonadic:
		case AstDyadic:
		case AstStrand:
			p += sprint(p, "(");
			paren = 1;
			break;
		}
	}

	switch(e->tag){
	case AstName:
		if(!left)
			p += addspace(p);
		p += sprint(p, "%s", e->name);
		if(left)
			p += addspace(p);
		break;
	case AstAssign:
		p += printexpr(p, e->left, 0);
		p += sprint(p, "←");
		p += printexpr(p, e->right, 0);
		break;
	case AstMonadic:
		p += printexpr(p, e->func, 1);
		p += printexpr(p, e->right, 0);
		break;
	case AstDyadic:
		p += printexpr(p, e->left, 1);
		p += printexpr(p, e->func, 1);
		p += printexpr(p, e->right, 0);
		break;
	case AstConst:
		p += printarraysub(p, e->val, 0);
		break;
	case AstPrim:
		p += sprint(p, "%s", primsymb(e->prim));
		break;
	case AstStrand:
		for(uvlong i = 0; i < e->childcount; i++){
			if(i != 0)
				p += addspace(p);
			p += printexpr(p, e->children[i], 1);
		}
		break;
	case AstLater:
		p += sprint(p, "{later..}");
		break;
	default:
		p += sprint(p, "{expr %d}", e->tag);
		break;
	}

	if(paren)
		p += sprint(p, ")");

	return p - start;
}

char *
printfunc(Function *f) /* Doesn't really belong here.. */
{
	char buf[2048]; /* TODO: fixed size :) */
	char *p = buf;

	if(f->ast == nil){
		sprint(p, "%s", primsymb(f->prim));
		return buf;
	}
	
	p += sprint(p, "∇");
	if(f->ast->funcresult)
		p += sprint(p, "%s←", f->ast->funcresult->name);
	if(f->ast->funcleftarg)
		p += sprint(p, "%s ", f->ast->funcleftarg->name);
	p += sprint(p, "%s", f->ast->funcname->name);
	if(f->ast->funcrightarg)
		p += sprint(p, " %s", f->ast->funcrightarg->name);
	for(uvlong i = 0; i < f->ast->funclocals->childcount; i++)
		p += sprint(p, ";%s", f->ast->funclocals->children[i]->name);
	for(uvlong i = 0; i < f->ast->childcount; i++){
		p += sprint(p, "\n ");
		p += printexpr(p, f->ast->children[i], 0);
	}
	sprint(p, "\n∇");
	return buf;
}

Array *
simplifyarray(Array *a)
{
	/* Given an array of type TypeArray, where all the elements are
	 * simple scalars of the same type, return an array of that type
	 */

	Array *b = nil;
	int type;

	if(a->type != TypeArray || a->size == 0)
		goto end;

	type = a->arraydata[0]->type;
	b = allocarray(type, a->rank, a->size);
	for(uvlong dim = 0; dim < a->rank; dim++)
		b->shape[dim] = a->shape[dim];

	for(uvlong i = 0; i < a->size; i++){
		if(a->arraydata[i]->type != type || a->arraydata[i]->rank != 0){
			b = a;
			goto end; /* Must be the same type and scalar */
		}
		switch(type){
		case TypeNumber:
			b->intdata[i] = a->arraydata[i]->intdata[0];
			break;
		case TypeChar:
			b->chardata[i] = a->arraydata[i]->chardata[0];
			break;
		}
	}
end:
	return b;
}