Login
7 branches 0 tags
Ben (Win10) Readme a496ece 4 years ago 279 Commits
nujel / lib / s-expression / writer.c
/* Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
 * This project uses the MIT license, a copy should be included under /LICENSE
 */
#include "writer.h"

#include "../misc/pf.h"

#include "../allocation/array.h"
#include "../allocation/native-function.h"
#include "../allocation/symbol.h"
#include "../collection/list.h"
#include "../collection/string.h"
#include "../collection/tree.h"
#include "../type/closure.h"
#include "../type/native-function.h"
#include "../type/symbol.h"
#include "../type/val.h"

#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char *lSWriteTreeRec(lTree *v, char *buf, char *bufEnd, bool display){
	if((v == NULL) || (v->key == NULL)){return buf;}
	char *cur = buf;
	cur = lSWriteTreeRec(v->left,cur,bufEnd,display);
	int t = snprintf(cur,bufEnd-cur,"%s ",v->key->c);
	if(t > 0){cur += t;}
	cur = lSWriteVal(v->value,cur,bufEnd,display);
	t = snprintf(cur,bufEnd-cur," ");
	if(t > 0){cur += t;}
	cur = lSWriteTreeRec(v->right,cur,bufEnd,display);

	return cur;
}

char *lSWriteTree(lTree *v, char *buf, char *bufEnd, bool display){
	char *cur = buf;
	int t = snprintf(cur,bufEnd-cur,"@[");
	if(t > 0){cur += t;}
	char *new = lSWriteTreeRec(v,cur,bufEnd, display);
	if(new != cur){
		cur = new;
		cur[-1] = ']';
	}else if(cur < bufEnd){
		*cur++ = ']';
	}
	return cur;
}

// char *lSIndent(char *buf, char *bufEnd, int indentLevel)
char *lSWriteTreeDef(lTree *v, char *buf, char *bufEnd){
	if(v == NULL){return buf;}
	buf = lSWriteTreeDef(v->left, buf, bufEnd);

	int t = snprintf(buf,bufEnd-buf,"[def %s ",v->key->c);
	if(t > 0){buf += t;}
	buf = lSWriteVal(v->value, buf, bufEnd, false);
	t = snprintf(buf,bufEnd-buf,"]\n");
	if(t > 0){buf += t;}

	return lSWriteTreeDef(v->right, buf, bufEnd);
}

char *lSWriteVal(lVal *v, char *buf, char *bufEnd, bool display){
	if(v == NULL){
		return spf(buf,bufEnd,"#nil");
	}
	char *cur = buf;

	switch(v->type){
	default:
		return buf;
	case ltNoAlloc:
		return spf(cur, bufEnd,"#zzz");
	case ltBool:
		return spf(cur, bufEnd,"%s", v->vBool ? "#t" : "#f");
	case ltObject: {
		cur = spf(cur, bufEnd, "[ω ");
		cur = lSWriteTreeDef(v->vClosure->data, cur, bufEnd);
		return spf(cur, bufEnd, "]");}
	case ltMacro:
	case ltLambda:
		if(v->vClosure && v->vClosure->name){
			return spf(cur, bufEnd, "%s", v->vClosure->name->c);
		}else{
			return spf(cur, bufEnd, "#%s_%u", v->type == ltLambda ? "λ" : "μ", lClosureID(v->vClosure));
		}
	case ltPair: {
		lVal *carSym    = lCar(v);
		if((carSym != NULL) && (carSym->type == ltSymbol) && (lCdr(v) != NULL)){
			const lSymbol *sym = carSym->vSymbol;
			if((sym == symQuote) && (lCddr(v) == NULL) && (lCadr(v) != NULL)){
				cur = spf(cur, bufEnd, "\'");
				return lSWriteVal(lCadr(v),cur,bufEnd, false);
			}
		}
		cur = spf(cur, bufEnd, "[");
		for(lVal *n = v;n != NULL; n = lCdr(n)){
			if(n->type == ltPair){
				lVal *cv = lCar(n);
				if((n == v) && (cv == NULL) && (lCdr(n) == NULL)){continue;}
				cur = lSWriteVal(cv,cur,bufEnd, false);
				if(lCdr(n) != NULL){
					*cur++ = ' ';
				}
			}else{
				cur = spf(cur, bufEnd, ". ");
				cur = lSWriteVal(n,cur,bufEnd, false);
				break;
			}
		}
		return spf(cur, bufEnd, "]");}
	case ltTree:
		return lSWriteTree(v->vTree,cur,bufEnd, false);
	case ltArray: {
		cur = spf(cur, bufEnd, "#[");
		if(v->vArray->data != NULL){
			const int arrLen = v->vArray->length;
			for(int i=0;i<arrLen;i++){
				cur = lSWriteVal(v->vArray->data[i],cur,bufEnd, false);
				if(i < (arrLen-1)){*cur++ = ' ';}
			}
		}
		return spf(cur, bufEnd, "]");}
	case ltInt:
		return spf(cur , bufEnd, "%i" ,v->vInt);
	case ltFloat:
		return spf(cur , bufEnd, "%f" ,v->vFloat);
	case ltVec:
		return spf(cur, bufEnd, "[vec %f %f %f]", v->vVec.x, v->vVec.y, v->vVec.z);
	case ltString:
		return spf(buf, bufEnd, display ? "%s" : "%S", v->vString->data);
	case ltSymbol:
		return spf(cur, bufEnd, "%s",v->vSymbol->c);
	case ltSpecialForm:
	case ltNativeFunc:
		if(v->vNFunc->name){
			return spf(cur, bufEnd, "%s",v->vNFunc->name->c);
		}else{
			return spf(cur, bufEnd, "#%s_%u",v->type == ltNativeFunc ? "nfn" : "sfo", lNFuncID(v->vNFunc));
		}
	case ltGUIWidget:
		return spf(cur, bufEnd, "#gui_%p", v->vPointer);
	}
}