You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ravi/src/ravi_ast_print.c

521 lines
17 KiB

/*
Copyright (C) 2018-2020 Dibyendu Majumdar
*/
#include <ravi_ast.h>
#include "ravi_ast.h"
static const char *type_name(ravitype_t tt) {
switch (tt) {
case RAVI_TANY:
return "any";
case RAVI_TNIL:
return "nil";
case RAVI_TBOOLEAN:
return "boolean";
case RAVI_TNUMFLT:
return "number";
case RAVI_TNUMINT:
return "integer";
case RAVI_TTABLE:
return "table";
case RAVI_TSTRING:
return "string";
case RAVI_TARRAYINT:
return "integer[]";
case RAVI_TARRAYFLT:
return "number[]";
case RAVI_TFUNCTION:
return "closure";
case RAVI_TUSERDATA:
return "";
default:
return "";
}
}
static void printf_buf(membuff_t *buf, const char *format, ...) {
static const char *PADDING = " ";
char tbuf[128] = {0};
va_list ap;
const char *cp;
va_start(ap, format);
for (cp = format; *cp; cp++) {
if (cp[0] == '%' && cp[1] == 'p') { /* padding */
int level = va_arg(ap, int);
snprintf(tbuf, sizeof tbuf, "%.*s", level, PADDING);
membuff_add_string(buf, tbuf);
cp++;
}
else if (cp[0] == '%' && cp[1] == 't') { /* TString */
const TString *ts;
ts = va_arg(ap, const TString *);
const char *s = getstr(ts);
membuff_add_string(buf, s);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'T') { /* struct var_type */
const struct var_type *type;
type = va_arg(ap, const struct var_type *);
if (type->type_code == RAVI_TUSERDATA) {
const char *s = getstr(type->type_name);
membuff_add_string(buf, s);
}
else {
membuff_add_string(buf, type_name(type->type_code));
}
cp++;
}
else if (cp[0] == '%' && cp[1] == 's') { /* const char * */
const char *s;
s = va_arg(ap, const char *);
membuff_add_string(buf, s);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'c') { /* comment */
const char *s;
s = va_arg(ap, const char *);
membuff_add_fstring(buf, "--%s", s);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'i') { /* integer */
lua_Integer i;
i = va_arg(ap, lua_Integer);
membuff_add_longlong(buf, i);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'f') { /* float */
double d;
d = va_arg(ap, double);
membuff_add_fstring(buf, "%.16f", d);
cp++;
}
else if (cp[0] == '%' && cp[1] == 'b') { /* boolean */
lua_Integer i;
i = va_arg(ap, lua_Integer);
membuff_add_bool(buf, i != 0);
cp++;
}
else {
membuff_add_char(buf, *cp);
}
}
va_end(ap);
}
static void print_ast_node_list(membuff_t *buf, struct ast_node_list *list, int level, const char *delimiter) {
struct ast_node *node;
bool is_first = true;
FOR_EACH_PTR(list, node) {
if (is_first)
is_first = false;
else if (delimiter)
printf_buf(buf, "%p%s\n", level, delimiter);
raviA_print_ast_node(buf, node, level + 1);
}
END_FOR_EACH_PTR(node);
}
static void print_statement_list(membuff_t *buf, struct ast_node_list *statement_list, int level) {
print_ast_node_list(buf, statement_list, level + 1, NULL);
}
static inline const char *get_as_str(const TString *ts) { return ts ? getstr(ts) : ""; }
static void print_symbol(membuff_t *buf, struct lua_symbol *sym, int level) {
switch (sym->symbol_type) {
case SYM_GLOBAL: {
printf_buf(buf, "%p%t %c %s %s\n", level, sym->var.var_name, "global symbol",
raviY_typename(sym->value_type.type_code), get_as_str(sym->value_type.type_name));
break;
}
case SYM_LOCAL: {
printf_buf(buf, "%p%t %c %s %s\n", level, sym->var.var_name, "local symbol",
raviY_typename(sym->value_type.type_code), get_as_str(sym->value_type.type_name));
break;
}
case SYM_UPVALUE: {
printf_buf(buf, "%p%t %c %s %s\n", level, sym->upvalue.var->var.var_name, "upvalue",
raviY_typename(sym->upvalue.var->value_type.type_code),
get_as_str(sym->upvalue.var->value_type.type_name));
break;
}
default:
assert(0);
}
}
static void print_symbol_name(membuff_t *buf, struct lua_symbol *sym) {
switch (sym->symbol_type) {
case SYM_LOCAL:
case SYM_GLOBAL: {
printf_buf(buf, "%t", sym->var.var_name);
break;
}
case SYM_UPVALUE: {
printf_buf(buf, "%t", sym->upvalue.var->var.var_name);
break;
}
default:
assert(0);
}
}
static void print_symbol_list(membuff_t *buf, struct lua_symbol_list *list, int level, const char *delimiter) {
struct lua_symbol *node;
bool is_first = true;
FOR_EACH_PTR(list, node) {
if (is_first)
is_first = false;
else if (delimiter)
printf_buf(buf, "%p%s\n", level, delimiter);
print_symbol(buf, node, level + 1);
}
END_FOR_EACH_PTR(node);
}
static void print_symbol_names(membuff_t *buf, struct lua_symbol_list *list) {
struct lua_symbol *node;
bool is_first = true;
FOR_EACH_PTR(list, node) {
if (is_first)
is_first = false;
else
printf_buf(buf, ", ");
print_symbol_name(buf, node);
}
END_FOR_EACH_PTR(node);
}
static const char *get_unary_opr_str(UnOpr op) {
switch (op) {
case OPR_NOT:
return "not";
case OPR_MINUS:
return "-";
case OPR_BNOT:
return "~";
case OPR_LEN:
return "#";
case OPR_TO_INTEGER:
return "@integer";
case OPR_TO_NUMBER:
return "@number";
case OPR_TO_INTARRAY:
return "@integer[]";
case OPR_TO_NUMARRAY:
return "@number[]";
case OPR_TO_TABLE:
return "@table";
case OPR_TO_CLOSURE:
return "@closure";
case OPR_TO_STRING:
return "@string";
case OPR_TO_TYPE:
return "@<usertype>";
default:
return "";
}
}
static const char *get_binary_opr_str(BinOpr op) {
switch (op) {
case OPR_ADD:
return "+";
case OPR_SUB:
return "-";
case OPR_MUL:
return "*";
case OPR_MOD:
return "%";
case OPR_POW:
return "^";
case OPR_DIV:
return "/";
case OPR_IDIV:
return "//";
case OPR_BAND:
return "&";
case OPR_BOR:
return "|";
case OPR_BXOR:
return "~";
case OPR_SHL:
return "<<";
case OPR_SHR:
return ">>";
case OPR_CONCAT:
return "..";
case OPR_NE:
return "~=";
case OPR_EQ:
return "==";
case OPR_LT:
return "<";
case OPR_LE:
return "<=";
case OPR_GT:
return ">";
case OPR_GE:
return ">=";
case OPR_AND:
return "and";
case OPR_OR:
return "or";
default:
return "";
}
}
void raviA_print_ast_node(membuff_t *buf, struct ast_node *node, int level) {
switch (node->type) {
case AST_FUNCTION_EXPR: {
if (node->function_expr.args) {
printf_buf(buf, "%pfunction(\n", level);
print_symbol_list(buf, node->function_expr.args, level + 1, ",");
printf_buf(buf, "%p)\n", level);
}
else {
printf_buf(buf, "%pfunction()\n", level);
}
if (node->function_expr.locals) {
printf_buf(buf, "%p%c ", level, "locals ");
print_symbol_names(buf, node->function_expr.locals);
printf_buf(buf, "\n");
}
if (node->function_expr.upvalues) {
printf_buf(buf, "%p%c ", level, "upvalues ");
print_symbol_names(buf, node->function_expr.upvalues);
printf_buf(buf, "\n");
}
print_statement_list(buf, node->function_expr.function_statement_list, level);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_NONE:
break;
case AST_RETURN_STMT: {
printf_buf(buf, "%preturn\n", level);
print_ast_node_list(buf, node->return_stmt.expr_list, level + 1, ",");
break;
}
case AST_LOCAL_STMT: {
printf_buf(buf, "%plocal\n", level);
printf_buf(buf, "%p%c\n", level, "[symbols]");
print_symbol_list(buf, node->local_stmt.var_list, level + 1, ",");
if (node->local_stmt.expr_list) {
printf_buf(buf, "%p%c\n", level, "[expressions]");
print_ast_node_list(buf, node->local_stmt.expr_list, level + 1, ",");
}
break;
}
case AST_FUNCTION_STMT: {
raviA_print_ast_node(buf, node->function_stmt.name, level);
if (node->function_stmt.selectors) {
printf_buf(buf, "%p%c\n", level + 1, "[selectors]");
print_ast_node_list(buf, node->function_stmt.selectors, level + 2, NULL);
}
if (node->function_stmt.method_name) {
printf_buf(buf, "%p%c\n", level + 1, "[method name]");
raviA_print_ast_node(buf, node->function_stmt.method_name, level + 2);
}
printf_buf(buf, "%p=\n", level + 1);
raviA_print_ast_node(buf, node->function_stmt.function_expr, level + 2);
break;
}
case AST_LABEL_STMT: {
printf_buf(buf, "%p::%t::\n", level, node->label_stmt.symbol->label.label_name);
break;
}
case AST_GOTO_STMT: {
printf_buf(buf, "%pgoto %t\n", level, node->goto_stmt.name);
break;
}
case AST_DO_STMT: {
printf_buf(buf, "%pdo\n", level);
print_ast_node_list(buf, node->do_stmt.do_statement_list, level + 1, NULL);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_EXPR_STMT: {
printf_buf(buf, "%p%c\n", level, "[expression statement start]");
if (node->expression_stmt.var_expr_list) {
printf_buf(buf, "%p%c\n", level + 1, "[var list start]");
print_ast_node_list(buf, node->expression_stmt.var_expr_list, level + 2, ",");
printf_buf(buf, "%p= %c\n", level + 1, "[var list end]");
}
printf_buf(buf, "%p%c\n", level + 1, "[expression list start]");
print_ast_node_list(buf, node->expression_stmt.expr_list, level + 2, ",");
printf_buf(buf, "%p%c\n", level + 1, "[expression list end]");
printf_buf(buf, "%p%c\n", level, "[expression statement end]");
break;
}
case AST_IF_STMT: {
struct ast_node *test_then_block;
bool is_first = true;
FOR_EACH_PTR(node->if_stmt.if_condition_list, test_then_block) {
if (is_first) {
is_first = false;
printf_buf(buf, "%pif\n", level);
}
else
printf_buf(buf, "%pelseif\n", level);
raviA_print_ast_node(buf, test_then_block->test_then_block.condition, level + 1);
printf_buf(buf, "%pthen\n", level);
print_ast_node_list(buf, test_then_block->test_then_block.test_then_statement_list, level + 1, NULL);
}
END_FOR_EACH_PTR(node);
if (node->if_stmt.else_block) {
printf_buf(buf, "%pelse\n", level);
print_ast_node_list(buf, node->if_stmt.else_statement_list, level + 1, NULL);
}
printf_buf(buf, "%pend\n", level);
break;
}
case AST_WHILE_STMT: {
printf_buf(buf, "%pwhile\n", level);
raviA_print_ast_node(buf, node->while_or_repeat_stmt.condition, level + 1);
printf_buf(buf, "%pdo\n", level);
print_ast_node_list(buf, node->while_or_repeat_stmt.loop_statement_list, level + 1, NULL);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_REPEAT_STMT: {
printf_buf(buf, "%prepeat\n", level);
print_ast_node_list(buf, node->while_or_repeat_stmt.loop_statement_list, level + 1, NULL);
printf_buf(buf, "%puntil\n", level);
raviA_print_ast_node(buf, node->while_or_repeat_stmt.condition, level + 1);
printf_buf(buf, "%p%c\n", level, "[repeat end]");
break;
}
case AST_FORIN_STMT: {
printf_buf(buf, "%pfor\n", level);
print_symbol_list(buf, node->for_stmt.symbols, level + 1, ",");
printf_buf(buf, "%pin\n", level);
print_ast_node_list(buf, node->for_stmt.expr_list, level + 1, ",");
printf_buf(buf, "%pdo\n", level);
print_statement_list(buf, node->for_stmt.for_statement_list, level + 1);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_FORNUM_STMT: {
printf_buf(buf, "%pfor\n", level);
print_symbol_list(buf, node->for_stmt.symbols, level + 1, NULL);
printf_buf(buf, "%p=\n", level);
print_ast_node_list(buf, node->for_stmt.expr_list, level + 1, ",");
printf_buf(buf, "%pdo\n", level);
print_statement_list(buf, node->for_stmt.for_statement_list, level + 1);
printf_buf(buf, "%pend\n", level);
break;
}
case AST_SUFFIXED_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[suffixed expr start]", &node->suffixed_expr.type);
printf_buf(buf, "%p%c %T\n", level+1, "[primary start]", &node->suffixed_expr.primary_expr->common_expr.type);
raviA_print_ast_node(buf, node->suffixed_expr.primary_expr, level + 2);
printf_buf(buf, "%p%c\n", level+1, "[primary end]");
if (node->suffixed_expr.suffix_list) {
printf_buf(buf, "%p%c\n", level+1, "[suffix list start]");
print_ast_node_list(buf, node->suffixed_expr.suffix_list, level + 2, NULL);
printf_buf(buf, "%p%c\n", level+1, "[suffix list end]");
}
printf_buf(buf, "%p%c\n", level, "[suffixed expr end]");
break;
}
case AST_FUNCTION_CALL_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[function call start]", &node->function_call_expr.type);
if (node->function_call_expr.method_name) {
printf_buf(buf, "%p: %t (\n", level + 1, node->function_call_expr.method_name);
}
else {
printf_buf(buf, "%p(\n", level + 1);
}
print_ast_node_list(buf, node->function_call_expr.arg_list, level + 2, ",");
printf_buf(buf, "%p)\n", level + 1);
printf_buf(buf, "%p%c\n", level, "[function call end]");
break;
}
case AST_SYMBOL_EXPR: {
print_symbol(buf, node->symbol_expr.var, level + 1);
break;
}
case AST_BINARY_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[binary expr start]", &node->binary_expr.type);
raviA_print_ast_node(buf, node->binary_expr.expr_left, level + 1);
printf_buf(buf, "%p%s\n", level, get_binary_opr_str(node->binary_expr.binary_op));
raviA_print_ast_node(buf, node->binary_expr.expr_right, level + 1);
printf_buf(buf, "%p%c\n", level, "[binary expr end]");
break;
}
case AST_UNARY_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[unary expr start]", &node->unary_expr.type);
printf_buf(buf, "%p%s\n", level, get_unary_opr_str(node->unary_expr.unary_op));
raviA_print_ast_node(buf, node->unary_expr.expr, level + 1);
printf_buf(buf, "%p%c\n", level, "[unary expr end]");
break;
}
case AST_LITERAL_EXPR: {
printf_buf(buf, "%p", level);
switch (node->literal_expr.type.type_code) {
case RAVI_TNIL:
printf_buf(buf, "nil");
break;
case RAVI_TBOOLEAN:
printf_buf(buf, "%b", node->literal_expr.u.i);
break;
case RAVI_TNUMINT:
printf_buf(buf, "%i", node->literal_expr.u.i);
break;
case RAVI_TNUMFLT:
printf_buf(buf, "%f", node->literal_expr.u.n);
break;
case RAVI_TSTRING:
printf_buf(buf, "'%t'", node->literal_expr.u.s);
break;
default:
assert(0);
}
printf_buf(buf, "\n");
break;
}
case AST_FIELD_SELECTOR_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[field selector start]", &node->index_expr.type);
printf_buf(buf, "%p.\n", level + 1);
raviA_print_ast_node(buf, node->index_expr.expr, level + 2);
printf_buf(buf, "%p%c\n", level, "[field selector end]");
break;
}
case AST_Y_INDEX_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[Y index start]", &node->index_expr.type);
printf_buf(buf, "%p[\n", level + 1);
raviA_print_ast_node(buf, node->index_expr.expr, level + 2);
printf_buf(buf, "%p]\n", level + 1);
printf_buf(buf, "%p%c\n", level, "[Y index end]");
break;
}
case AST_INDEXED_ASSIGN_EXPR: {
printf_buf(buf, "%p%c %T\n", level, "[indexed assign start]", &node->indexed_assign_expr.type);
if (node->indexed_assign_expr.index_expr) {
printf_buf(buf, "%p%c\n", level, "[index start]");
raviA_print_ast_node(buf, node->indexed_assign_expr.index_expr, level + 1);
printf_buf(buf, "%p%c\n", level, "[index end]");
}
printf_buf(buf, "%p%c\n", level, "[value start]");
raviA_print_ast_node(buf, node->indexed_assign_expr.value_expr, level + 1);
printf_buf(buf, "%p%c\n", level, "[value end]");
printf_buf(buf, "%p%c\n", level, "[indexed assign end]");
break;
}
case AST_TABLE_EXPR: {
printf_buf(buf, "%p{ %c %T\n", level, "[table constructor start]", &node->table_expr.type);
print_ast_node_list(buf, node->table_expr.expr_list, level + 1, ",");
printf_buf(buf, "%p} %c\n", level, "[table constructor end]");
break;
}
default:
printf_buf(buf, "%pUnsupported node type %d\n", level, node->type);
assert(0);
}
}