/* Copyright (C) 2018-2020 Dibyendu Majumdar */ #include #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 "@"; 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); } }