Files
Noja/src/compiler/serialize.c
T
2021-11-05 17:01:34 +01:00

199 lines
4.6 KiB
C

/* -- WHAT IS THIS FILE? --
*
* This file implements the routines that serialize the AST
* into JSON format. The JSON manipulation is handled by the
* third party library xJSON (written by me, still).
* The serialization functionality is exposed through the
* `serialize` function, that takes as an `AST` as argument
* and outputs a string of valid JSON. Therefore the xJSON
* dependency isn't exposed to the caller and can be regarded
* as an implementation detail.
* The way the serialization occurres is by converting the
* AST's representation native to the compiler to one native
* to xJSON, an then calling xj_encode on the converted AST.
*
*/
#include <assert.h>
#include <xjson.h>
#include "serialize.h"
#include "ASTi.h"
#define UNREACHABLE assert(0)
static xj_value *convert_node(Node *node, xj_error *error, xj_alloc **alloc);
char *serialize(AST *ast, int *len)
{
xj_alloc *alloc = NULL;
xj_error error;
xj_value *value = convert_node(ast->root, &error, &alloc);
if(value == NULL)
{
xj_free(alloc);
return NULL;
}
else
{
char *serialized = xj_encode(value, len);
xj_free(alloc);
return serialized;
}
}
static const char *expr_kind_name(ExprNode *expr)
{
switch(expr->kind)
{
case EXPR_POS: return "pos";
case EXPR_NEG: return "neg";
case EXPR_ADD: return "add";
case EXPR_SUB: return "sub";
case EXPR_MUL: return "mul";
case EXPR_DIV: return "div";
case EXPR_INT: return "int";
case EXPR_FLOAT: return "float";
case EXPR_STRING: return "string";
case EXPR_IDENT: return "ident";
default:
UNREACHABLE;
return NULL;
}
UNREACHABLE;
return NULL;
}
static xj_value *convert_node_list(Node *head, xj_error *error, xj_alloc **alloc);
static xj_value *convert_node(Node *node, xj_error *error, xj_alloc **alloc)
{
switch(node->kind)
{
case NODE_EXPR:
ExprNode *expr = (ExprNode*) node;
switch(expr->kind)
{
case EXPR_POS:
case EXPR_NEG:
case EXPR_ADD:
case EXPR_SUB:
case EXPR_MUL:
case EXPR_DIV:
{
OperExprNode *oper = (OperExprNode*) expr;
xj_value *operands = NULL;
if(oper->count > 0)
{
operands = convert_node_list((Node*) oper->head, error, alloc);
if(operands == NULL)
return NULL;
}
return xj_decodef(error, alloc,
"{"
"\t\"node-kind\": \"expr\", \n"
"\t\"expr-kind\": %Q, \n"
"\t\"operands\": %L\n"
"}", expr_kind_name(expr), operands);
}
case EXPR_INT:
return xj_decodef(error, alloc,
"{"
"\t\"node-kind\": \"expr\", \n"
"\t\"expr-kind\": %Q, \n"
"\t\"value\": %d\n"
"}", expr_kind_name(expr), ((IntExprNode*) expr)->val);
case EXPR_FLOAT:
return xj_decodef(error, alloc,
"{"
"\t\"node-kind\": \"expr\", \n"
"\t\"expr-kind\": %Q, \n"
"\t\"value\": %f\n"
"}", expr_kind_name(expr), ((FloatExprNode*) expr)->val);
case EXPR_STRING:
return xj_decodef(error, alloc,
"{"
"\t\"node-kind\": \"expr\", \n"
"\t\"expr-kind\": %Q, \n"
"\t\"value\": %Q\n"
"}", expr_kind_name(expr), ((StringExprNode*) expr)->val);
case EXPR_IDENT:
return xj_decodef(error, alloc,
"{"
"\t\"node-kind\": \"expr\", \n"
"\t\"expr-kind\": %Q, \n"
"\t\"value\": %Q\n"
"}", expr_kind_name(expr), ((IdentExprNode*) expr)->val);
default:
UNREACHABLE;
break;
}
break;
case NODE_IFELSE:
{
IfElseNode *ifelse = (IfElseNode*) node;
xj_value *condition = convert_node(ifelse->condition, error, alloc);
if(condition == NULL) return NULL;
xj_value *true_branch = convert_node(ifelse->true_branch, error, alloc);
if(true_branch == NULL) return NULL;
xj_value *false_branch = convert_node(ifelse->false_branch, error, alloc);
if(false_branch == NULL) return NULL;
return xj_decodef(error, alloc,
"{"
"\t\"node-kind\": \"if-else\", \n"
"\t\"condition\": %v, \n"
"\t\"true-branch\": %v, \n"
"\t\"false-branch\": %v\n"
"}", condition, true_branch, false_branch);
}
default:
UNREACHABLE;
break;
}
UNREACHABLE;
return NULL;
}
static xj_value *convert_node_list(Node *head, xj_error *error, xj_alloc **alloc)
{
xj_value *json_head = NULL;
xj_value **json_tail = &json_head;
Node *curs = head;
while(curs)
{
xj_value *temp = convert_node(curs, error, alloc);
if(temp == NULL)
return NULL;
temp->next = NULL;
*json_tail = temp;
json_tail = &temp->next;
curs = curs->next;
}
return json_head;
}