hammer/src/pprint.c

203 lines
5 KiB
C
Raw Normal View History

/* Pretty-printer for Hammer.
* Copyright (C) 2012 Meredith L. Patterson, Dan "TQ" Hirsch
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "platform.h"
#include <stdio.h>
#include <string.h>
#include "hammer.h"
#include "internal.h"
#include <stdlib.h>
2013-10-18 12:14:18 +02:00
#include <inttypes.h>
typedef struct pp_state {
int delta;
int indent_amt;
int at_bol;
} pp_state_t;
2012-05-26 14:06:52 +02:00
void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta) {
switch (tok->token_type) {
case TT_NONE:
2012-05-26 14:06:52 +02:00
fprintf(stream, "%*snull\n", indent, "");
break;
case TT_BYTES:
if (tok->bytes.len == 0)
2012-05-26 14:06:52 +02:00
fprintf(stream, "%*s<>\n", indent, "");
else {
2012-05-26 14:06:52 +02:00
fprintf(stream, "%*s", indent, "");
for (size_t i = 0; i < tok->bytes.len; i++) {
2012-05-26 14:06:52 +02:00
fprintf(stream,
"%c%02hhx",
(i == 0) ? '<' : '.',
tok->bytes.token[i]);
}
2012-05-26 14:06:52 +02:00
fprintf(stream, ">\n");
}
break;
case TT_SINT:
2012-05-18 18:43:02 +02:00
if (tok->sint < 0)
2013-10-18 12:14:18 +02:00
fprintf(stream, "%*ss -%#" PRIx64 "\n", indent, "", -tok->sint);
2012-05-18 18:43:02 +02:00
else
2013-10-18 12:14:18 +02:00
fprintf(stream, "%*ss %#" PRIx64 "\n", indent, "", tok->sint);
2012-05-18 18:43:02 +02:00
break;
case TT_UINT:
2013-10-18 12:14:18 +02:00
fprintf(stream, "%*su %#" PRIx64 "\n", indent, "", tok->uint);
break;
case TT_SEQUENCE: {
2012-05-26 14:06:52 +02:00
fprintf(stream, "%*s[\n", indent, "");
for (size_t i = 0; i < tok->seq->used; i++) {
2012-05-26 14:06:52 +02:00
h_pprint(stream, tok->seq->elements[i], indent + delta, delta);
}
2012-05-26 14:06:52 +02:00
fprintf(stream, "%*s]\n", indent, "");
2012-05-26 19:14:26 +02:00
}
break;
case TT_USER:
fprintf(stream, "%*sUSER:%s\n", indent, "", h_get_token_type_name(tok->token_type));
2012-05-26 19:14:26 +02:00
break;
default:
2013-01-15 01:24:47 +01:00
if(tok->token_type > TT_USER) {
fprintf(stream, "%*sUSER:%s %d\n", indent, "", h_get_token_type_name(tok->token_type), tok->token_type-TT_USER);
2013-01-15 01:24:47 +01:00
} else {
assert_message(0, "Should not reach here.");
}
}
}
struct result_buf {
char* output;
size_t len;
size_t capacity;
};
static inline bool ensure_capacity(struct result_buf *buf, int amt) {
while (buf->len + amt >= buf->capacity) {
buf->output = (&system_allocator)->realloc(&system_allocator, buf->output, buf->capacity *= 2);
if (!buf->output) {
return false;
}
}
return true;
}
static inline bool append_buf(struct result_buf *buf, const char* input, int len) {
if (ensure_capacity(buf, len)) {
memcpy(buf->output + buf->len, input, len);
buf->len += len;
return true;
} else {
return false;
}
}
static inline bool append_buf_c(struct result_buf *buf, char v) {
if (ensure_capacity(buf, 1)) {
buf->output[buf->len++] = v;
return true;
} else {
return false;
}
}
/** append a formatted string to the result buffer */
static inline bool append_buf_formatted(struct result_buf *buf, char* format, ...)
{
char* tmpbuf;
int len;
bool result;
va_list ap;
va_start(ap, format);
len = h_platform_vasprintf(&tmpbuf, format, ap);
result = append_buf(buf, tmpbuf, len);
free(tmpbuf);
va_end(ap);
return result;
}
static void unamb_sub(const HParsedToken* tok, struct result_buf *buf) {
if (!tok) {
append_buf(buf, "NULL", 4);
return;
}
switch (tok->token_type) {
case TT_NONE:
append_buf(buf, "null", 4);
break;
case TT_BYTES:
if (tok->bytes.len == 0)
append_buf(buf, "<>", 2);
else {
for (size_t i = 0; i < tok->bytes.len; i++) {
2012-05-13 01:01:26 +01:00
const char *HEX = "0123456789abcdef";
append_buf_c(buf, (i == 0) ? '<': '.');
char c = tok->bytes.token[i];
append_buf_c(buf, HEX[(c >> 4) & 0xf]);
append_buf_c(buf, HEX[(c >> 0) & 0xf]);
}
append_buf_c(buf, '>');
}
break;
case TT_SINT:
2012-05-18 18:43:02 +02:00
if (tok->sint < 0)
append_buf_formatted(buf, "s-%#" PRIx64, -tok->sint);
2012-05-18 18:43:02 +02:00
else
append_buf_formatted(buf, "s%#" PRIx64, tok->sint);
break;
case TT_UINT:
append_buf_formatted(buf, "u%#" PRIx64, tok->uint);
break;
2012-05-12 21:53:54 +01:00
case TT_ERR:
append_buf(buf, "ERR", 3);
break;
case TT_SEQUENCE: {
append_buf_c(buf, '(');
for (size_t i = 0; i < tok->seq->used; i++) {
if (i > 0)
append_buf_c(buf, ' ');
unamb_sub(tok->seq->elements[i], buf);
}
append_buf_c(buf, ')');
}
break;
default:
fprintf(stderr, "Unexpected token type %d\n", tok->token_type);
assert_message(0, "Should not reach here.");
}
}
2012-05-26 14:06:52 +02:00
char* h_write_result_unamb(const HParsedToken* tok) {
struct result_buf buf = {
.output = (&system_allocator)->alloc(&system_allocator, 16),
.len = 0,
.capacity = 16
};
if (!buf.output) {
return NULL;
}
unamb_sub(tok, &buf);
append_buf_c(&buf, 0);
return buf.output;
}