~lbnz/xr0

429d6ab51e7d1df49c8e822aa17d9ffc829cb12f — Amisi Kiarie 18 days ago 1970364 chore/recursive-block-print master
chore: better recursive printing of blocks

resolves: https://github.com/xr0-org/xr0/issues/47
M README.md => README.md +1 -1
@@ 1,4 1,4 @@
# Xr0 - C But Safe
# Xr0 – C But Safe

Xr0 is a verifier for C that aims to guarantee the safety of C programs at
compile time. It will eliminate common pitfalls such as use-after-frees, double

M include/ast.h => include/ast.h +5 -2
@@ 242,7 242,10 @@ void
ast_block_destroy(struct ast_block *);

char *
ast_block_str(struct ast_block *, char *indent);
ast_block_str(struct ast_block *, int indent_level);

char *
ast_block_absstr(struct ast_block *b, int indent_level);

struct ast_block *
ast_block_copy(struct ast_block *b);


@@ 377,7 380,7 @@ struct ast_stmt *
ast_stmt_copy(struct ast_stmt *);

char *
ast_stmt_str(struct ast_stmt *);
ast_stmt_str(struct ast_stmt *, int indent_level);

bool
ast_stmt_equal(struct ast_stmt *, struct ast_stmt *);

M include/util.h => include/util.h +5 -0
@@ 9,6 9,11 @@
char *
dynamic_str(const char *);

#define INDENT_CHAR '\t'

char *
indentation(int level);


/* XXX: We know. */
struct map {

M src/ast/block.c => src/ast/block.c +26 -3
@@ 87,23 87,46 @@ copy_stmt_arr(int len, struct ast_stmt **stmt)
	return new;
}

char *
ast_block_str(struct ast_block *b, char *indent)
static char *
ast_block_str_div(struct ast_block *b, int indent_level, char divst, char divend)
{
	assert(indent_level > 0);

	char *indent = indentation(indent_level),
	     *previndent = indentation(indent_level-1);

	struct strbuilder *sb = strbuilder_create();
	strbuilder_printf(sb, "%c\n", divst);
	for (int i = 0; i < b->ndecl; i++) {
		char *s = ast_variable_str(b->decl[i]);
		strbuilder_printf(sb, "%s%s;\n", indent, s);
		free(s);
	}
	for (int i = 0; i < b->nstmt; i++) {
		char *s = ast_stmt_str(b->stmt[i]);
		char *s = ast_stmt_str(b->stmt[i], indent_level+1);
		strbuilder_printf(sb, "%s%s\n", indent, s);
		free(s);
	}
	strbuilder_printf(sb, "%s%c", previndent, divend);

	free(previndent);
	free(indent);

	return strbuilder_build(sb);
}

char *
ast_block_str(struct ast_block *b, int indent)
{
	return ast_block_str_div(b, indent, '{', '}');
}

char *
ast_block_absstr(struct ast_block *b, int indent)
{
	return ast_block_str_div(b, indent, '[', ']');
}

int
ast_block_ndecls(struct ast_block *b)
{

M src/ast/function/function.c => src/ast/function/function.c +4 -4
@@ 86,12 86,12 @@ ast_function_str(struct ast_function *f)
		strbuilder_printf(b, "%s%s", v, space);
		free(v);
	}
	char *abs = ast_block_str(f->abstract, "\t");
	strbuilder_printf(b, ") ~ [\n%s]", abs);
	char *abs = ast_block_absstr(f->abstract, 1);
	strbuilder_printf(b, ") ~ %s", abs);
	free(abs);
	if (f->body) {
		char *body = ast_block_str(f->body, "\t");
		strbuilder_printf(b, "{\n%s}", body);
		char *body = ast_block_str(f->body, 1);
		strbuilder_printf(b, "%s", body);
		free(body);
	} else {
		strbuilder_printf(b, ";");

M src/ast/stmt/stmt.c => src/ast/stmt/stmt.c +46 -27
@@ 102,9 102,10 @@ ast_stmt_isassume(struct ast_stmt *stmt)
}

static void
ast_stmt_labelled_sprint(struct ast_stmt *stmt, struct strbuilder *b)
ast_stmt_labelled_sprint(struct ast_stmt *stmt, int indent_level,
		struct strbuilder *b)
{
	char *s = ast_stmt_str(stmt->u.labelled.stmt);
	char *s = ast_stmt_str(stmt->u.labelled.stmt, indent_level);
	strbuilder_printf(b, "%s: %s", stmt->u.labelled.label, s);
	free(s);
}


@@ 153,19 154,38 @@ ast_stmt_create_compound(struct lexememarker *loc, struct ast_block *b)
struct ast_block *
ast_stmt_as_block(struct ast_stmt *stmt)
{
	assert(stmt->kind == STMT_COMPOUND);
	assert(stmt->kind == STMT_COMPOUND || stmt->kind == STMT_COMPOUND_V);
	return stmt->u.compound;
}

static void
ast_stmt_compound_sprint(struct ast_stmt *stmt, struct strbuilder *b)
ast_stmt_compound_sprint(struct ast_stmt *stmt, int indent_level,
		struct strbuilder *b)
{
	assert(stmt->kind == STMT_COMPOUND || stmt->kind == STMT_COMPOUND_V);
	char *s = ast_block_str(stmt->u.compound, "\t");
	assert(stmt->kind == STMT_COMPOUND);
	char *s = ast_block_str(stmt->u.compound, indent_level);
	strbuilder_printf(b, s);
	free(s);
}

static void
ast_stmt_compound_v_sprint(struct ast_stmt *stmt, int indent_level,
		struct strbuilder *sb)
{
	struct ast_block *b = ast_stmt_as_block(stmt);

	/* special case for nice print */
	if (ast_block_ndecls(b) == 0 && ast_block_nstmts(b) == 1) {
		char *s = ast_stmt_str(ast_block_stmts(b)[0], 0);
		strbuilder_printf(sb, "~ [ %s ]", s);
		free(s);
	} else {
		char *s = ast_block_absstr(stmt->u.compound, indent_level);
		strbuilder_printf(sb, "~ %s", s);
		free(s);
	}
}

struct ast_stmt *
ast_stmt_create_compound_v(struct lexememarker *loc, struct ast_block *b)
{


@@ 275,22 295,21 @@ ast_stmt_sel_nest(struct ast_stmt *stmt)
}

static void
ast_stmt_sel_sprint(struct ast_stmt *stmt, struct strbuilder *b)
ast_stmt_sel_sprint(struct ast_stmt *stmt, int indent_level, struct strbuilder *b)
{
	assert(stmt->kind == STMT_SELECTION);
	char *cond	= ast_expr_str(stmt->u.selection.cond),
	     *body	= ast_stmt_str(stmt->u.selection.body);
	     *body	= ast_stmt_str(stmt->u.selection.body, indent_level);

	/* XXX: we only support simple IF for now */
	strbuilder_printf(
		b,
		"if (%s) { %s }",
		"if (%s) %s",
		cond, body
	);

	struct ast_stmt *nest_stmt = stmt->u.selection.nest;
	if (nest_stmt) {
		char *nest = ast_stmt_str(nest_stmt);
		char *nest = ast_stmt_str(nest_stmt, indent_level);
		strbuilder_printf(
			b,
			" else %s",


@@ 382,20 401,20 @@ ast_stmt_copy_iter(struct ast_stmt *stmt)
}

static void
ast_stmt_iter_sprint(struct ast_stmt *stmt, struct strbuilder *b)
ast_stmt_iter_sprint(struct ast_stmt *stmt, int indent_level, struct strbuilder *b)
{
	assert(stmt->kind == STMT_ITERATION);
	char *init = ast_stmt_str(stmt->u.iteration.init),
	     *cond = ast_stmt_str(stmt->u.iteration.cond),
	     *body = ast_stmt_str(stmt->u.iteration.body),
	char *init = ast_stmt_str(stmt->u.iteration.init, indent_level),
	     *cond = ast_stmt_str(stmt->u.iteration.cond, indent_level),
	     *body = ast_stmt_str(stmt->u.iteration.body, indent_level),
	     *iter = ast_expr_str(stmt->u.iteration.iter);

	char *abs = stmt->u.iteration.abstract ?
		ast_block_str(stmt->u.iteration.abstract, "\t") : "";
		ast_block_absstr(stmt->u.iteration.abstract, indent_level) : "";

	strbuilder_printf(
		b,
		"for (%s %s %s) [%s] { %s }",
		"for (%s %s %s) ~ %s%s",
		init, cond, iter, abs, body
	);



@@ 412,11 431,11 @@ ast_stmt_create_iter_e(struct ast_stmt *stmt)
}

static void
ast_stmt_iter_e_sprint(struct ast_stmt *stmt, struct strbuilder *b)
ast_stmt_iter_e_sprint(struct ast_stmt *stmt, int indent_level, struct strbuilder *b)
{
	assert(stmt->kind == STMT_ITERATION_E);
	stmt->kind = STMT_ITERATION;
	char *s = ast_stmt_str(stmt);
	char *s = ast_stmt_str(stmt, indent_level);
	stmt->kind = STMT_ITERATION_E;
	strbuilder_printf(b, ".%s", s);
	free(s);


@@ 430,7 449,7 @@ ast_stmt_jump_sprint(struct ast_stmt *stmt, struct strbuilder *b)

	strbuilder_printf(
		b,
		"return %s;\n",
		"return %s;",
		rv
	);



@@ 545,13 564,13 @@ ast_stmt_copy(struct ast_stmt *stmt)
}

char *
ast_stmt_str(struct ast_stmt *stmt)
ast_stmt_str(struct ast_stmt *stmt, int indent_level)
{
	assert(stmt);
	struct strbuilder *b = strbuilder_create();
	switch (stmt->kind) {
	case STMT_LABELLED:
		ast_stmt_labelled_sprint(stmt, b);
		ast_stmt_labelled_sprint(stmt, indent_level, b);
		break;
	case STMT_NOP:
		ast_stmt_nop_sprint(stmt, b);


@@ 560,19 579,19 @@ ast_stmt_str(struct ast_stmt *stmt)
		ast_stmt_expr_sprint(stmt, b);
		break;
	case STMT_COMPOUND:
		ast_stmt_compound_sprint(stmt, b);
		ast_stmt_compound_sprint(stmt, indent_level, b);
		break;
	case STMT_COMPOUND_V:
		ast_stmt_compound_sprint(stmt, b);
		ast_stmt_compound_v_sprint(stmt, indent_level, b);
		break;
	case STMT_SELECTION:
		ast_stmt_sel_sprint(stmt, b);
		ast_stmt_sel_sprint(stmt, indent_level, b);
		break;
	case STMT_ITERATION:
		ast_stmt_iter_sprint(stmt, b);
		ast_stmt_iter_sprint(stmt, indent_level, b);
		break;
	case STMT_ITERATION_E:
		ast_stmt_iter_e_sprint(stmt, b);
		ast_stmt_iter_e_sprint(stmt, indent_level, b);
		break;
	case STMT_JUMP:
		ast_stmt_jump_sprint(stmt, b);

M src/main.c => src/main.c +3 -1
@@ 321,7 321,9 @@ proto_defisvalid(struct ast_function *proto, struct ast_function *def)
	struct ast_block *proto_abs = ast_function_abstract(proto),
			 *def_abs = ast_function_abstract(def);

	bool abs_match = strcmp(ast_block_str(proto_abs, ""), ast_block_str(def_abs, "")) == 0,
	/* XXX: the indent level must be >= to get around an assert in
	 * ast_block_str. this check should be made more accessible */
	bool abs_match = strcmp(ast_block_str(proto_abs, 1), ast_block_str(def_abs, 1)) == 0,
	     protoabs_only = proto_abs && ast_function_absisempty(def); 
	if (abs_match || protoabs_only) {
		return true;

M src/util/util.c => src/util/util.c +13 -0
@@ 16,6 16,19 @@ dynamic_str(const char *s)
	return t;
}

char *
indentation(int level)
{
	assert(level >= 0);
	char *s = malloc(sizeof(char) * level + 1);
	for (int i = 0; i < level; i++) {
		s[i] = INDENT_CHAR;
	}
	s[level] = '\0';
	return s;
}


static struct entry
entry_create(const char *key, const void *value)
{