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.
562 lines
17 KiB
562 lines
17 KiB
/******************************************************************************
|
|
* Copyright (C) 2018-2021 Dibyendu Majumdar
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
******************************************************************************/
|
|
#include <parser.h>
|
|
|
|
const char *raviX_get_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 "userdata";
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
|
|
static void printf_buf(TextBuffer *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);
|
|
raviX_buffer_add_string(buf, tbuf);
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 't') { /* string_object */
|
|
const StringObject *s = va_arg(ap, const StringObject *);
|
|
raviX_buffer_add_string(buf, s->str);
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 'T') { /* VariableType */
|
|
const VariableType *type;
|
|
type = va_arg(ap, const VariableType *);
|
|
if (type->type_code == RAVI_TUSERDATA) {
|
|
const StringObject *s = type->type_name;
|
|
raviX_buffer_add_string(buf, s->str);
|
|
} else {
|
|
raviX_buffer_add_string(buf, raviX_get_type_name(type->type_code));
|
|
}
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 's') { /* const char * */
|
|
const char *s;
|
|
s = va_arg(ap, const char *);
|
|
raviX_buffer_add_string(buf, s);
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 'c') { /* comment */
|
|
const char *s;
|
|
s = va_arg(ap, const char *);
|
|
raviX_buffer_add_fstring(buf, "--%s", s);
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 'i') { /* integer */
|
|
lua_Integer i;
|
|
i = va_arg(ap, lua_Integer);
|
|
raviX_buffer_add_longlong(buf, i);
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 'f') { /* float */
|
|
double d;
|
|
d = va_arg(ap, double);
|
|
raviX_buffer_add_fstring(buf, "%.16f", d);
|
|
cp++;
|
|
} else if (cp[0] == '%' && cp[1] == 'b') { /* boolean */
|
|
lua_Integer i;
|
|
i = va_arg(ap, lua_Integer);
|
|
raviX_buffer_add_bool(buf, i != 0);
|
|
cp++;
|
|
} else {
|
|
raviX_buffer_add_char(buf, *cp);
|
|
}
|
|
}
|
|
va_end(ap);
|
|
}
|
|
|
|
static void print_ast_node_list(TextBuffer *buf, AstNodeList *list, int level, const char *delimiter)
|
|
{
|
|
AstNode *node;
|
|
bool is_first = true;
|
|
FOR_EACH_PTR(list, AstNode, node)
|
|
{
|
|
if (is_first)
|
|
is_first = false;
|
|
else if (delimiter)
|
|
printf_buf(buf, "%p%s\n", level, delimiter);
|
|
raviX_print_ast_node(buf, node, level + 1);
|
|
}
|
|
END_FOR_EACH_PTR(node);
|
|
}
|
|
|
|
static void print_statement_list(TextBuffer *buf, AstNodeList *statement_list, int level)
|
|
{
|
|
print_ast_node_list(buf, statement_list, level + 1, NULL);
|
|
}
|
|
|
|
static inline const char *get_as_str(const StringObject *ts) { return ts ? ts->str : ""; }
|
|
|
|
static void print_symbol(TextBuffer *buf, LuaSymbol *sym, int level)
|
|
{
|
|
switch (sym->symbol_type) {
|
|
case SYM_ENV: {
|
|
printf_buf(buf, "%p%t %c %s %s\n", level, sym->variable.var_name, "_ENV",
|
|
raviX_get_type_name(sym->variable.value_type.type_code), get_as_str(sym->variable.value_type.type_name));
|
|
break;
|
|
}
|
|
case SYM_GLOBAL: {
|
|
printf_buf(buf, "%p%t %c %s %s\n", level, sym->variable.var_name, "global symbol",
|
|
raviX_get_type_name(sym->variable.value_type.type_code), get_as_str(sym->variable.value_type.type_name));
|
|
break;
|
|
}
|
|
case SYM_LOCAL: {
|
|
printf_buf(buf, "%p%t %c %s %s\n", level, sym->variable.var_name, "local symbol",
|
|
raviX_get_type_name(sym->variable.value_type.type_code), get_as_str(sym->variable.value_type.type_name));
|
|
break;
|
|
}
|
|
case SYM_UPVALUE: {
|
|
printf_buf(buf, "%p%t %c %s %s\n", level, sym->upvalue.target_variable->variable.var_name, "upvalue",
|
|
raviX_get_type_name(sym->upvalue.target_variable->variable.value_type.type_code),
|
|
get_as_str(sym->upvalue.target_variable->variable.value_type.type_name));
|
|
break;
|
|
}
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
static void print_symbol_name(TextBuffer *buf, LuaSymbol *sym)
|
|
{
|
|
switch (sym->symbol_type) {
|
|
case SYM_LOCAL:
|
|
case SYM_ENV:
|
|
case SYM_GLOBAL: {
|
|
printf_buf(buf, "%t", sym->variable.var_name);
|
|
break;
|
|
}
|
|
case SYM_UPVALUE: {
|
|
if (sym->upvalue.target_variable->symbol_type == SYM_ENV) {
|
|
printf_buf(buf, "%t*", sym->upvalue.target_variable->variable.var_name);
|
|
}
|
|
else {
|
|
printf_buf(buf, "%t", sym->upvalue.target_variable->variable.var_name);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
static void print_symbol_list(TextBuffer *buf, LuaSymbolList *list, int level, const char *delimiter)
|
|
{
|
|
LuaSymbol *node;
|
|
bool is_first = true;
|
|
FOR_EACH_PTR(list, LuaSymbol, 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(TextBuffer *buf, LuaSymbolList *list)
|
|
{
|
|
LuaSymbol *node;
|
|
bool is_first = true;
|
|
FOR_EACH_PTR(list, LuaSymbol, node)
|
|
{
|
|
if (is_first)
|
|
is_first = false;
|
|
else
|
|
printf_buf(buf, ", ");
|
|
print_symbol_name(buf, node);
|
|
}
|
|
END_FOR_EACH_PTR(node);
|
|
}
|
|
|
|
const char *raviX_get_unary_opr_str(UnaryOperatorType op)
|
|
{
|
|
switch (op) {
|
|
case UNOPR_NOT:
|
|
return "not";
|
|
case UNOPR_MINUS:
|
|
return "-";
|
|
case UNOPR_BNOT:
|
|
return "~";
|
|
case UNOPR_LEN:
|
|
return "#";
|
|
case UNOPR_TO_INTEGER:
|
|
return "@integer";
|
|
case UNOPR_TO_NUMBER:
|
|
return "@number";
|
|
case UNOPR_TO_INTARRAY:
|
|
return "@integer[]";
|
|
case UNOPR_TO_NUMARRAY:
|
|
return "@number[]";
|
|
case UNOPR_TO_TABLE:
|
|
return "@table";
|
|
case UNOPR_TO_CLOSURE:
|
|
return "@closure";
|
|
case UNOPR_TO_STRING:
|
|
return "@string";
|
|
case UNOPR_TO_TYPE:
|
|
return "@<usertype>";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
const char *raviX_get_binary_opr_str(BinaryOperatorType op)
|
|
{
|
|
switch (op) {
|
|
case BINOPR_ADD:
|
|
return "+";
|
|
case BINOPR_SUB:
|
|
return "-";
|
|
case BINOPR_MUL:
|
|
return "*";
|
|
case BINOPR_MOD:
|
|
return "%";
|
|
case BINOPR_POW:
|
|
return "^";
|
|
case BINOPR_DIV:
|
|
return "/";
|
|
case BINOPR_IDIV:
|
|
return "//";
|
|
case BINOPR_BAND:
|
|
return "&";
|
|
case BINOPR_BOR:
|
|
return "|";
|
|
case BINOPR_BXOR:
|
|
return "~";
|
|
case BINOPR_SHL:
|
|
return "<<";
|
|
case BINOPR_SHR:
|
|
return ">>";
|
|
case BINOPR_CONCAT:
|
|
return "..";
|
|
case BINOPR_NE:
|
|
return "~=";
|
|
case BINOPR_EQ:
|
|
return "==";
|
|
case BINOPR_LT:
|
|
return "<";
|
|
case BINOPR_LE:
|
|
return "<=";
|
|
case BINOPR_GT:
|
|
return ">";
|
|
case BINOPR_GE:
|
|
return ">=";
|
|
case BINOPR_AND:
|
|
return "and";
|
|
case BINOPR_OR:
|
|
return "or";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
void raviX_print_ast_node(TextBuffer *buf, AstNode *node, int level)
|
|
{
|
|
switch (node->type) {
|
|
case EXPR_FUNCTION: {
|
|
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 STMT_RETURN: {
|
|
printf_buf(buf, "%preturn\n", level);
|
|
print_ast_node_list(buf, node->return_stmt.expr_list, level + 1, ",");
|
|
break;
|
|
}
|
|
case STMT_LOCAL: {
|
|
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 STMT_FUNCTION: {
|
|
raviX_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]");
|
|
raviX_print_ast_node(buf, node->function_stmt.method_name, level + 2);
|
|
}
|
|
printf_buf(buf, "%p=\n", level + 1);
|
|
raviX_print_ast_node(buf, node->function_stmt.function_expr, level + 2);
|
|
break;
|
|
}
|
|
case STMT_LABEL: {
|
|
printf_buf(buf, "%p::%t::\n", level, node->label_stmt.symbol->label.label_name);
|
|
break;
|
|
}
|
|
case STMT_GOTO: {
|
|
printf_buf(buf, "%pgoto %t\n", level, node->goto_stmt.name);
|
|
break;
|
|
}
|
|
case STMT_DO: {
|
|
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 STMT_EXPR: {
|
|
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 STMT_IF: {
|
|
AstNode *test_then_block;
|
|
bool is_first = true;
|
|
FOR_EACH_PTR(node->if_stmt.if_condition_list, AstNode, test_then_block)
|
|
{
|
|
if (is_first) {
|
|
is_first = false;
|
|
printf_buf(buf, "%pif\n", level);
|
|
} else
|
|
printf_buf(buf, "%pelseif\n", level);
|
|
raviX_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 STMT_WHILE: {
|
|
printf_buf(buf, "%pwhile\n", level);
|
|
raviX_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 STMT_REPEAT: {
|
|
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);
|
|
raviX_print_ast_node(buf, node->while_or_repeat_stmt.condition, level + 1);
|
|
printf_buf(buf, "%p%c\n", level, "[repeat end]");
|
|
break;
|
|
}
|
|
case STMT_FOR_IN: {
|
|
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 STMT_FOR_NUM: {
|
|
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 EXPR_SUFFIXED: {
|
|
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);
|
|
raviX_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 EXPR_FUNCTION_CALL: {
|
|
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 EXPR_SYMBOL: {
|
|
print_symbol(buf, node->symbol_expr.var, level + 1);
|
|
break;
|
|
}
|
|
case EXPR_BINARY: {
|
|
printf_buf(buf, "%p%c %T\n", level, "[binary expr start]", &node->binary_expr.type);
|
|
raviX_print_ast_node(buf, node->binary_expr.expr_left, level + 1);
|
|
printf_buf(buf, "%p%s\n", level, raviX_get_binary_opr_str(node->binary_expr.binary_op));
|
|
raviX_print_ast_node(buf, node->binary_expr.expr_right, level + 1);
|
|
printf_buf(buf, "%p%c\n", level, "[binary expr end]");
|
|
break;
|
|
}
|
|
case EXPR_UNARY: {
|
|
printf_buf(buf, "%p%c %T\n", level, "[unary expr start]", &node->unary_expr.type);
|
|
printf_buf(buf, "%p%s\n", level, raviX_get_unary_opr_str(node->unary_expr.unary_op));
|
|
raviX_print_ast_node(buf, node->unary_expr.expr, level + 1);
|
|
printf_buf(buf, "%p%c\n", level, "[unary expr end]");
|
|
break;
|
|
}
|
|
case EXPR_LITERAL: {
|
|
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.r);
|
|
break;
|
|
case RAVI_TSTRING:
|
|
printf_buf(buf, "'%t'", node->literal_expr.u.ts);
|
|
break;
|
|
case RAVI_TVARARGS:
|
|
printf_buf(buf, "...");
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
printf_buf(buf, "\n");
|
|
break;
|
|
}
|
|
case EXPR_FIELD_SELECTOR: {
|
|
printf_buf(buf, "%p%c %T\n", level, "[field selector start]", &node->index_expr.type);
|
|
printf_buf(buf, "%p.\n", level + 1);
|
|
raviX_print_ast_node(buf, node->index_expr.expr, level + 2);
|
|
printf_buf(buf, "%p%c\n", level, "[field selector end]");
|
|
break;
|
|
}
|
|
case EXPR_Y_INDEX: {
|
|
printf_buf(buf, "%p%c %T\n", level, "[Y index start]", &node->index_expr.type);
|
|
printf_buf(buf, "%p[\n", level + 1);
|
|
raviX_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 EXPR_TABLE_ELEMENT_ASSIGN: {
|
|
printf_buf(buf, "%p%c %T\n", level, "[indexed assign start]", &node->table_elem_assign_expr.type);
|
|
if (node->table_elem_assign_expr.key_expr) {
|
|
printf_buf(buf, "%p%c\n", level, "[index start]");
|
|
raviX_print_ast_node(buf, node->table_elem_assign_expr.key_expr, level + 1);
|
|
printf_buf(buf, "%p%c\n", level, "[index end]");
|
|
}
|
|
printf_buf(buf, "%p%c\n", level, "[value start]");
|
|
raviX_print_ast_node(buf, node->table_elem_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 EXPR_TABLE_LITERAL: {
|
|
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);
|
|
}
|
|
}
|
|
|
|
void raviX_output_ast(CompilerState *container, FILE *fp)
|
|
{
|
|
TextBuffer mbuf;
|
|
raviX_buffer_init(&mbuf, 1024);
|
|
raviX_print_ast_node(&mbuf, container->main_function, 0);
|
|
fputs(mbuf.buf, fp);
|
|
raviX_buffer_free(&mbuf);
|
|
}
|