/* display.c -- Functions to print various structures. Copyright © 2011-2016 Samuel Lidén Borell 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 #include "display.h" #include "misc.h" static const char ast_types[LRL_AST_LastType][15+1] = { /* Namespaces */ "namespace", "uses", "interop", /* Definitions statements */ "def_type", "def_data", "def_function", /* Values */ "val_undefined", "val_none", "val_nan", "val_inf", "val_ident", "val_typeident", "val_scalar", "val_struct", "val_array", /* Expressions */ "expr_arrayindex", "expr_member", "expr_funcmember", "expr_call", "expr_as", "expr_typeassert", "expr_unaryop", "expr_binaryop", "expr_cond", "expr_evaluated", /* Types */ "type_ident", "type_enum", "type_bitfield", "type_struct", "type_union", "type_function", "type_array", "type_pointer", "type_optional", "type_parametric", "type_builtin", "type_private", "type_any", /* Statements */ "stmt_compound", "stmt_decl", "stmt_expr", "stmt_deftype", "stmt_if", "stmt_while", "stmt_for", "stmt_goto", "stmt_skipto", "stmt_repeatfrom", "stmt_label", "stmt_break", "stmt_continue", "stmt_return", "stmt_unreachable", "stmt_typeassert", "stmt_assert" }; const char *lrl_display_get_ast_name(LRLASTNodeType ast_type) { return ast_types[ast_type]; } void lrl_display_loc(const LRLCodeLocation *loc) { printf("%.*s", size2int(loc->length), loc->start); } static const char token_types[LRL_TT_LastType][10+1] = { "", "lparen", "rparen", "lsquare", "rsquare", "lcurly", "rcurly", "semicolon", "comma", "ns_sep", "arrayindex", "+>", "*>", "+*>", "c_var_arg", "+", "-", "*", "/", "mod", "<<", ">>", "compl", "bitand", "bitor", "bitxor", ".", "->", "^", "@", "?", "makeopt", "enumbase", "sizeof", "minsizeof", "offsetof", "alignof", "then", "not", "and", "or", "xor", "==", "!=", "<", "<=", ">", ">=", "=", "+=", "-=", "*=", "/=", "<<=", ">>=", "typedef", "struct", "union", "enum", "bitfield", "noreturn", "private", "incomplete", "any", "const", "gc", "mine", "own", "shared", "var", "cond", "precond", "postcond", "alias", "alignas", "deprecated", "import", "export", "linkname", "local", "declonly", "if", "else", "elif", "while", "do", "for", "loopend", "loopempty", "switch", "case", "default", "goto", "skipto", "repeatfrom", "label", "continue", "break", "flow", "leave", "return", "unreachable", "uses", "as", "typeassert", "assert", "namespace", "interop", "at", "in", "is", "of", "unused", "using", "with", "yield", "ident", "int", "real", "string", "undefined", "none", "NaN", "inf", "here", "" }; void lrl_display_token_type(LRLTokenType type) { printf("%s", token_types[type]); } void lrl_display_token(const LRLToken *token) { if (!token) { printf(""); return; } putchar('['); lrl_display_token_type(token->type); putchar(']'); lrl_display_loc(&token->loc); } static void display_whitespace(const LRLToken *from, const LRLToken *to) { const char *start = from->loc.start + from->loc.length; size_t length = to->loc.start - start; fwrite(start, length, 1, stdout); } void lrl_display_tokens(const LRLToken *tokens, size_t num_tokens) { while (num_tokens) { lrl_display_token(tokens); display_whitespace(tokens, tokens+1); tokens++; num_tokens--; } } void lrl_display_ident(const LRLIdent *ident) { if (!ident) { printf(""); return; } if (ident->scope && ident->scope->scope) { lrl_display_ident(ident->scope); putchar(':'); } if (ident->def_token) { lrl_display_loc(&ident->def_token->loc); } else if (ident->name) { printf("%s", ident->name); } else { /* Anonymous scope */ if (!ident->scope) { } /* root */ else if (ident->scope->name) printf(""); /* not a header */ else if (!ident->scope->scope) printf(""); /* not a system scope */ else printf(""); } } void lrl_display_identref(const LRLIdentRef *identref) { const LRLIdent *ident = identref->ident; if (lrl_ident_valid(ident)) { lrl_display_ident(ident); } else { printf("'); } } static void display_exprlist(const LRLASTExprList *exprlist) { size_t i; for (i = 0; i < exprlist->num_args; i++) { putchar(' '); lrl_display_expr(exprlist->values[i]); } } void lrl_display_expr(const LRLASTExpr *expr) { if (!expr) { printf(""); return; } switch (expr->ast_type) { case LRL_AST_Value_Scalar: /*display_token_type(expr->kind.scalar.token);*/ lrl_display_loc(&expr->kind.scalar.token->loc); break; case LRL_AST_Value_TypeIdent: case LRL_AST_Value_Ident: if (expr->kind.ident.type_params) printf("(parametric "); lrl_display_identref(&expr->kind.ident.identref); if (expr->kind.ident.type_params) { LRLASTTypeList *param = expr->kind.ident.type_params; for (; param; param = param->next) { putchar(' '); /* XXX breaks indentation! */ lrl_display_type(param->type, 0); } putchar(')'); } break; case LRL_AST_Value_Array: printf("(array_val"); display_exprlist(&expr->kind.array.values); putchar(')'); break; case LRL_AST_Value_Struct: printf("(struct_val"); display_exprlist(&expr->kind.struc.values); putchar(')'); break; case LRL_AST_Value_None: printf("(none)"); break; case LRL_AST_Value_NaN: printf("(not_a_number)"); break; case LRL_AST_Value_Inf: printf("(infinity)"); break; case LRL_AST_Value_Undefined: printf("(undefined)"); break; case LRL_AST_Expr_BinaryOp: putchar('('); lrl_display_token_type(expr->kind.binary_op.token_type); putchar(' '); lrl_display_expr(expr->kind.binary_op.operand1); putchar(' '); lrl_display_expr(expr->kind.binary_op.operand2); putchar(')'); break; case LRL_AST_Expr_UnaryOp: putchar('('); lrl_display_token_type(expr->kind.unary_op.token_type); putchar(' '); lrl_display_expr(expr->kind.unary_op.operand); putchar(')'); break; case LRL_AST_Expr_Conditional: printf("(conditional "); lrl_display_expr(expr->kind.conditional.condexpr); putchar(' '); lrl_display_expr(expr->kind.conditional.trueexpr); putchar(' '); lrl_display_expr(expr->kind.conditional.falseexpr); putchar(')'); break; case LRL_AST_Expr_Call: printf("(call "); lrl_display_expr(expr->kind.call.function); display_exprlist(&expr->kind.call.args); putchar(')'); break; case LRL_AST_Expr_ArrayIndex: printf("(index "); lrl_display_expr(expr->kind.index.array); putchar(' '); lrl_display_expr(expr->kind.index.index); putchar(')'); break; case LRL_AST_Expr_Member: case LRL_AST_Expr_FuncMember: printf(expr->ast_type == LRL_AST_Expr_Member ? "(member " : "(functionmember "); lrl_display_expr(expr->kind.member.struc); putchar(' '); if (expr->kind.member.ident) { lrl_display_ident(expr->kind.member.ident); } else { printf("kind.member.token->loc); putchar('>'); } putchar(')'); break; case LRL_AST_Expr_As: printf("(asexpr "); lrl_display_expr(expr->kind.asexpr.expr); putchar(' '); /* XXX breaks indentation! */ lrl_display_type(expr->kind.asexpr.type, 0); putchar(')'); break; case LRL_AST_Expr_TypeAssert: printf("(typeassertexpr "); lrl_display_expr(expr->kind.typeassert.expr); putchar(' '); /* XXX breaks indentation! */ lrl_display_type(expr->kind.typeassert.type, 0); putchar(')'); break; case LRL_AST_Expr_Evaluated: printf("(evaluated "); lrl_display_expr(expr->kind.evaluated.original); putchar(' '); lrl_display_expr(expr->kind.evaluated.evaluated); putchar(')'); break; LRL_case_except_ast_exprs_values default: fail("dpyexpr_switch"); } } static void display_indent(int indent) { while (indent--) printf(" "); } static void display_start(const char *name, int indent) { display_indent(indent); printf("(%s\n", name); } static void display_end(int indent) { display_indent(indent); printf(")\n"); } void lrl_display_qualifiers(LRLTypeQualifiers quals) { size_t i; printf("(quallist"); for (i = 0; i < LRL_NumQualifiers; i++) { if (quals & 1) printf(" %s", token_types[LRL_FirstQual+i]); quals = quals >> 1; } printf(")"); } static void display_enumlist(const LRLASTDefList *list, int indent) { display_start("enum_deflist", indent++); for (; list; list = list->next) { if (list->def.ast_type == LRL_AST_Def_Data) { const LRLASTDefData *def = &list->def.kind.data; display_start("enum_item", indent++); /* Identifier */ display_indent(indent); lrl_display_ident(def->ident); putchar('\n'); /* Value */ display_indent(indent); lrl_display_expr(def->value); putchar('\n'); display_end(--indent); } else { fail("dpyenumlist_notdata"); /* shouldn't happen */ } } display_end(--indent); } void lrl_display_type(const LRLASTType *type, int indent) { display_indent(indent); lrl_display_qualifiers(type->quals); printf("\n"); switch (type->ast_type) { case LRL_AST_Type_Array: display_start("array_type", indent++); display_indent(indent); lrl_display_expr(type->kind.array.length); printf("\n"); lrl_display_type(type->kind.array.type, indent); display_end(--indent); break; case LRL_AST_Type_Function: display_start("function_type", indent++); lrl_display_type(type->kind.function.args, indent); if (type->kind.function.flags & LRL_FF_NoReturn) { display_indent(indent); printf("(noreturn)\n"); } else { lrl_display_type(type->kind.function.ret, indent); } display_end(--indent); break; case LRL_AST_Type_Ident: display_indent(indent); lrl_display_identref(&type->kind.identref); printf("\n"); break; case LRL_AST_Type_Optional: display_start("optional_type", indent++); lrl_display_type(type->kind.optional.type, indent); display_end(--indent); break; case LRL_AST_Type_Parametric: display_start("parametric_type", indent++); lrl_display_type(type->kind.parametric.type, indent); display_start("type_params", indent++); lrl_display_typelist(type->kind.parametric.params, indent); display_end(--indent); display_end(--indent); break; case LRL_AST_Type_Pointer: { static const char modes[][22+1] = { "pointer_type", "flexi_pointer_type", "raw_pointer_type", "raw_flexi_pointer_type" }; display_start(modes[type->kind.pointer.flags], indent++); lrl_display_type(type->kind.pointer.type, indent); display_end(--indent); break; } case LRL_AST_Type_Enum: display_start("enum_type", indent++); display_start("base_type", indent++); lrl_display_type(type->kind.enu.base_type, indent); display_end(--indent); display_enumlist(type->kind.enu.values, indent); display_end(--indent); break; case LRL_AST_Type_Bitfield: display_start("bitfield_type", indent++); if (type->kind.enu.base_type) { display_start("base_type", indent++); lrl_display_type(type->kind.enu.base_type, indent); display_end(--indent); } else { display_indent(indent); printf("(no_base_type)\n"); } display_enumlist(type->kind.enu.values, indent); display_end(--indent); break; case LRL_AST_Type_Struct: display_start("struct_type", indent++); lrl_display_deflist(type->kind.struc.members, indent); if (type->kind.struc.flags & LRL_SF_CVarArg) { display_indent(indent); printf("(c_var_arg)\n"); } display_end(--indent); break; case LRL_AST_Type_Union: display_start("union_type", indent++); lrl_display_deflist(type->kind.unio.members, indent); display_end(--indent); break; case LRL_AST_Type_Builtin: display_indent(indent); printf("\n", lrl_builtin_get_name(type->kind.builtin)); break; case LRL_AST_Type_Private: display_indent(indent); printf("(private)\n"); break; case LRL_AST_Type_Any: display_indent(indent); printf("(any)\n"); break; LRL_case_except_ast_types default: fail("dpytype_switch"); } } void lrl_display_typelist(const LRLASTTypeList *list, int indent) { for (; list; list = list->next) { /* Type */ lrl_display_type(list->type, indent); if (list->next) printf("\n"); } } void lrl_display_typenames(const LRLASTDefList *list, int indent) { display_start("typenames", indent++); for (; list; list = list->next) { if (list->def.ast_type != LRL_AST_Def_Type && list->def.ast_type != LRL_AST_Stmt_DefType) { fail("dpytypenames_nottype"); } lrl_display_def_type(&list->def.kind.type, indent); printf("\n"); } display_end(--indent); } void lrl_display_defflags(const LRLDefFlags flags) { printf("(flags"); if (flags & LRL_DeFl_Alias) printf(" alias"); if (flags & LRL_DeFl_Incomplete) printf(" incomplete"); if (flags & LRL_DeFl_Deprecated) printf(" deprecated"); if (flags & LRL_DeFl_Local) printf(" local"); if (flags & LRL_DeFl_DeclOnly) printf(" declonly"); if (flags & LRL_DeFl_Export) printf(" export"); if (flags & LRL_DeFl_Import) printf(" import"); putchar(')'); } void lrl_display_def_type(const LRLASTDefType *def, int indent) { display_start("typedef", indent++); /* Flags */ display_indent(indent); lrl_display_defflags(def->flags); putchar('\n'); /* Identifier */ display_indent(indent); lrl_display_ident(def->ident); putchar('\n'); /* Type names */ lrl_display_typenames(def->typenames, indent); /* Type */ lrl_display_type(def->type, indent); display_end(--indent); } void lrl_display_def_data(const LRLASTDefData *def, int indent) { display_start("data", indent++); /* Flags */ display_indent(indent); lrl_display_defflags(def->flags); putchar('\n'); /* Identifier */ display_indent(indent); lrl_display_ident(def->ident); putchar('\n'); /* Type */ lrl_display_type(def->type, indent); /* Value */ display_indent(indent); lrl_display_expr(def->value); putchar('\n'); display_end(--indent); } void lrl_display_def_function(const LRLASTDefFunction *def, int indent) { display_start("function", indent++); /* Flags */ display_indent(indent); lrl_display_defflags(def->flags); putchar('\n'); /* Identifier */ display_indent(indent); lrl_display_ident(def->ident); putchar('\n'); /* Type names */ lrl_display_typenames(def->typenames, indent); /* Type */ lrl_display_type(&def->type, indent); /* Function body */ if (def->code) { lrl_display_statement(def->code, indent); } else { display_indent(indent); printf("(prototype)\n"); } display_end(--indent); } void lrl_display_uses(const LRLASTUses *uses, int indent) { display_start("uses", indent++); /* Identifier */ display_indent(indent); lrl_display_identref(&uses->identref); putchar('\n'); display_end(--indent); } void lrl_display_namespace(const LRLASTNamespace *namespac, int indent) { display_start("namespace", indent++); /* Identifier */ display_indent(indent); lrl_display_ident(namespac->ident); putchar('\n'); /* Contents */ lrl_display_deflist(namespac->list, indent); display_end(--indent); } void lrl_display_interop(const LRLASTInterop *interop, int indent) { display_start("interop", indent++); /* Identifier */ display_indent(indent); lrl_display_ident(interop->ident); putchar('\n'); /* Name of language */ display_indent(indent); lrl_display_loc(&interop->name->loc); putchar('\n'); /* Options */ display_indent(indent); lrl_display_expr(interop->options_expr); putchar('\n'); display_end(--indent); } void lrl_display_deflist(const LRLASTDefList *list, int indent) { display_start("deflist", indent++); for (; list; list = list->next) { switch (list->def.ast_type) { case LRL_AST_Def_Type: lrl_display_def_type(&list->def.kind.type, indent); break; case LRL_AST_Def_Data: lrl_display_def_data(&list->def.kind.data, indent); break; case LRL_AST_Def_Function: lrl_display_def_function(&list->def.kind.function, indent); break; case LRL_AST_Uses: lrl_display_uses(&list->def.kind.uses, indent); break; case LRL_AST_Namespace: lrl_display_namespace(list->def.kind.namespac, indent); break; case LRL_AST_Interop: lrl_display_interop(&list->def.kind.interop, indent); break; LRL_case_except_ast_namespaces_defs default: fail("dpydeflist_switch"); /* shouldn't happen */ } printf("\n"); } display_end(--indent); } void lrl_display_deflist_interops(const LRLASTDefList *list) { for (; list; list = list->next) { switch (list->def.ast_type) { case LRL_AST_Def_Type: case LRL_AST_Def_Data: case LRL_AST_Def_Function: case LRL_AST_Uses: /* Do nothing */ break; case LRL_AST_Namespace: lrl_display_deflist_interops(list->def.kind.namespac->list); break; case LRL_AST_Interop: if (!list->def.kind.interop.translated) { printf("(missing_interop_ast)\n"); } else { lrl_display_deflist(list->def.kind.interop.translated, 0); } break; LRL_case_except_ast_namespaces_defs default: fail("dpydeflist_switch"); /* shouldn't happen */ } printf("\n"); } } void lrl_display_statement(const LRLASTStmt *stmt, int indent) { LRLASTStmtList *entry; if (!stmt) { display_indent(indent); printf("(missing_statement)\n"); return; } switch (stmt->ast_type) { case LRL_AST_Stmt_Compound: /* Compound statement: { ... } */ display_start("compound_stmt", indent++); for (entry = stmt->kind.compound; entry; entry = entry->next) { lrl_display_statement(entry->statement, indent); } display_end(--indent); break; case LRL_AST_Stmt_Decl: /* Declaration statement: int i; */ display_start("decl_stmt", indent++); lrl_display_def_data(&stmt->kind.data, indent); display_end(--indent); break; case LRL_AST_Stmt_Expr: /* Expression statement: i; */ display_start("expr_stmt", indent++); display_indent(indent); lrl_display_expr(stmt->kind.expr); printf("\n"); display_end(--indent); break; case LRL_AST_Stmt_DefType: /* Type definition: typedef x = ...; */ display_start("deftype_stmt", indent++); lrl_display_def_type(&stmt->kind.deftype, indent); display_end(--indent); break; case LRL_AST_Stmt_If: /* if expr { true; } else { false; } */ display_start("if_stmt", indent++); display_indent(indent); lrl_display_expr(stmt->kind.ifstm.boolexpr); printf("\n"); lrl_display_statement(stmt->kind.ifstm.body_true, indent); if (stmt->kind.ifstm.body_false) { display_indent(indent); printf("(else)\n"); lrl_display_statement(stmt->kind.ifstm.body_false, indent); } display_end(--indent); break; case LRL_AST_Stmt_Switch: { size_t ci; /* switch expr { case x { } case y { } default { } } */ display_start("switch_stmt", indent++); display_indent(indent); lrl_display_expr(stmt->kind.switchstm.switchexpr); printf("\n"); for (ci = 0; ci < stmt->kind.switchstm.num_cases; ci++) { size_t ei; const LRLASTCase *casenode = &stmt->kind.switchstm.cases[ci]; display_start("case", indent++); for (ei = 0; ei < casenode->num_matchvalues; ei++) { LRLASTCaseMatch *matchval = &casenode->matchvalues[ei]; display_indent(indent); lrl_display_expr(matchval->expr); if (matchval->withstm) { display_start("with", indent++); lrl_display_statement(matchval->withstm, indent); display_end(--indent); } printf("\n"); } lrl_display_statement(casenode->stmt, indent); display_end(--indent); } if (stmt->kind.switchstm.defaultstm) { display_start("default", indent++); lrl_display_statement(stmt->kind.switchstm.defaultstm, indent); display_end(--indent); } display_end(--indent); break; } case LRL_AST_Stmt_While: /* while expr { work; } */ display_start("while_stmt", indent++); display_indent(indent); lrl_display_expr(stmt->kind.whilestm.boolexpr); printf("\n"); lrl_display_statement(stmt->kind.whilestm.body, indent); display_end(--indent); break; case LRL_AST_Stmt_DoWhile: /* do { work; } while expr; */ display_start("dowhile_stmt", indent++); display_indent(indent); lrl_display_expr(stmt->kind.whilestm.boolexpr); printf("\n"); lrl_display_statement(stmt->kind.whilestm.body, indent); display_end(--indent); break; case LRL_AST_Stmt_For: /* for decl in expr { work; } */ display_start("for_stmt", indent++); lrl_display_def_data(&stmt->kind.forstm.valuedef.kind.data, indent); display_indent(indent); lrl_display_expr(stmt->kind.forstm.iterexpr); printf("\n"); lrl_display_statement(stmt->kind.forstm.body, indent); if (stmt->kind.forstm.body_end) { display_start("end", indent++); lrl_display_statement(stmt->kind.forstm.body_end, indent); display_end(--indent); } if (stmt->kind.forstm.body_empty) { display_start("empty", indent++); lrl_display_statement(stmt->kind.forstm.body_empty, indent); display_end(--indent); } display_end(--indent); break; case LRL_AST_Stmt_Break: display_indent(indent); printf("(break)\n"); break; case LRL_AST_Stmt_Continue: display_indent(indent); printf("(continue)\n"); break; case LRL_AST_Stmt_Goto: case LRL_AST_Stmt_SkipTo: case LRL_AST_Stmt_RepeatFrom: display_indent(indent); printf(stmt->ast_type == LRL_AST_Stmt_Goto ? "(goto " : stmt->ast_type == LRL_AST_Stmt_SkipTo ? "(skipto " : "(repeatfrom "); lrl_display_identref(&stmt->kind.gotostm.identref); printf(")\n"); break; case LRL_AST_Stmt_Label: display_indent(indent); printf("(label "); lrl_display_ident(stmt->kind.labelstm.ident); printf(")\n"); break; case LRL_AST_Stmt_Return: /* return; -or- return expr; */ display_start("return_stmt", indent++); if (stmt->kind.retstm.retexpr) { display_indent(indent); lrl_display_expr(stmt->kind.retstm.retexpr); printf("\n"); } display_end(--indent); break; case LRL_AST_Stmt_TypeAssert: { /* typeassert ident is type in min..max else { false; }; */ LRLTypeAssert *cond; display_start("typeassert_stmt", indent++); for (cond = stmt->kind.typeassertstm.asserts; cond; cond = cond->next) { display_indent(indent); lrl_display_identref(&cond->refexpr.kind.ident.identref); printf("\n"); lrl_display_def_data(&cond->def.kind.data, indent); /* TODO print range also (if any) */ } if (stmt->kind.typeassertstm.body_do) { display_start("do", indent++); lrl_display_statement(stmt->kind.typeassertstm.body_do, indent); display_end(--indent); } if (stmt->kind.typeassertstm.body_else) { display_start("else", indent++); lrl_display_statement(stmt->kind.typeassertstm.body_else, indent); display_end(--indent); } display_end(--indent); break; } case LRL_AST_Stmt_Assert: /* assert expr; */ display_start("assert_stmt", indent++); display_indent(indent); lrl_display_expr(stmt->kind.assertstm.boolexpr); printf("\n"); display_end(--indent); break; case LRL_AST_Stmt_Unreachable: /* unreachable; */ display_indent(indent); printf("(unreachable)\n"); break; LRL_case_except_ast_stmts default: fail("dpystmt_switch"); /* shouldn't happen */ } } void lrl_display_scope(const LRLIdent *scope, int indent) { size_t bucket; LRLIdent *subscope; /* Display full identifier with namespace */ display_indent(indent); lrl_display_ident(scope); putchar('\n'); /* Display sub scopes */ for (bucket = 0; bucket < scope->contents.num_buckets; bucket++) { for (subscope = scope->contents.buckets[bucket]; subscope; subscope = subscope->next) { lrl_display_scope(subscope, indent); } } }