/*- * Copyright (c) 2015 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "ast.h" #include "eprintf.h" #include "strung.h" #include "syntax.h" static void printloc(FILE *out, struct ast_srcloc loc) { efprintf(out, "%s:%zu:%zu", loc.filename, loc.lineno, loc.column); } static void printoptname(FILE *out, struct ast_optname *name) { size_t i; for (i = 0; i < name->nparts; i++) { char *v = NULL; switch (name->parts[i].t) { case AST_OPTPART_NORMAL: v = string_evisciiz(name->parts[i].u.normal); efprintf(out, "%s", v); break; case AST_OPTPART_EXTENSION: v = string_evisciiz(name->parts[i].u.extension); efprintf(out, "(%s)", v); break; default: efprintf(out, "{bad option part %d}", (int)name->parts[i].t); break; } if (v) free(v); if (i + 1 < name->nparts) efprintf(out, "."); } } static void dump_option(FILE *out, struct ast_option *option, unsigned indent) { struct ast_optval *val = &option->value; efprintf(out, "%*soption ", indent, ""); printoptname(out, &option->name); efprintf(out, " at "); printloc(out, option->loc); efprintf(out, ": "); switch (val->t) { char *v; case AST_OPTVAL_ID: v = string_evisciiz(val->u.id); goto str; case AST_OPTVAL_UINT: efprintf(out, "%"PRIuMAX, val->u.uint); break; case AST_OPTVAL_SINT: efprintf(out, "%"PRIdMAX, val->u.sint); break; case AST_OPTVAL_REAL: efprintf(out, "%a", val->u.real); break; case AST_OPTVAL_BOOLEAN: efprintf(out, "%s", val->u.boolean? "true" : "false"); break; case AST_OPTVAL_STRING: v = string_evisciiz(val->u.id); goto str; str: efprintf(out, "%s", v); free(v); break; default: efprintf(out, "bad option value %d", (int)val->t); } efprintf(out, "\n"); } static void dump_options(FILE *out, struct ast_option *options, size_t noptions, unsigned indent) { size_t i; for (i = 0; i < noptions; i++) dump_option(out, &options[i], indent); } static void dump_enumerand(FILE *out, struct ast_enumerand *enumerand, unsigned indent) { { char *v = string_evisciiz(enumerand->id); efprintf(out, "%*senumerand %s = %"PRId32" at ", indent, "", v, enumerand->value); printloc(out, enumerand->loc); efprintf(out, "\n"); free(v); } indent += 2; dump_options(out, enumerand->options.options, enumerand->options.noptions, indent); } static void dump_enumeration(FILE *out, struct ast_enumeration *enumeration, unsigned indent) { struct ast_enum_stmt *stmts = enumeration->stmts.stmts; size_t i, nstmts = enumeration->stmts.nstmts; { char *v = string_evisciiz(enumeration->id); efprintf(out, "%*senumeration %s at ", indent, "", v); printloc(out, enumeration->loc); efprintf(out, "\n"); free(v); } indent += 2; for (i = 0; i < nstmts; i++) { switch (stmts[i].t) { case AST_ENUM_STMT_NULL: efprintf(out, "%*snull\n", indent, ""); break; case AST_ENUM_STMT_OPTION: dump_option(out, &stmts[i].u.option, indent); break; case AST_ENUM_STMT_ENUMERAND: dump_enumerand(out, &stmts[i].u.enumerand, indent); break; default: efprintf(out, "%*sbad enumeration stmt %d\n", indent, "", (int)stmts[i].t); } } } static void dump_rpc(FILE *out, struct ast_rpc *rpc, unsigned indent) { { char *v_id = string_evisciiz(rpc->id); char *v_in = string_evisciiz(rpc->intype.text); char *v_out = string_evisciiz(rpc->outtype.text); efprintf(out, "%*srpc %s at ", indent, "", v_id); printloc(out, rpc->loc); efprintf(out, "\n"); efprintf(out, "%*s input %s\n", indent, "", v_in); efprintf(out, "%*s output %s\n", indent, "", v_out); free(v_out); free(v_in); free(v_id); } indent += 2; dump_options(out, rpc->options.options, rpc->options.noptions, indent); } static void dump_service(FILE *out, struct ast_service *service, unsigned indent) { struct ast_service_stmt *stmts = service->stmts.stmts; size_t i, nstmts = service->stmts.nstmts; { char *v = string_evisciiz(service->id); efprintf(out, "%*sservice %s at ", indent, "", v); printloc(out, service->loc); efprintf(out, "\n"); free(v); } indent += 2; for (i = 0; i < nstmts; i++) { switch (stmts[i].t) { case AST_SERVICE_STMT_NULL: efprintf(out, "%*snull\n", indent, ""); break; case AST_SERVICE_STMT_OPTION: dump_option(out, &stmts[i].u.option, indent); break; case AST_SERVICE_STMT_RPC: dump_rpc(out, &stmts[i].u.rpc, indent); break; default: efprintf(out, "%*sbad service stmt %d\n", indent, "", (int)stmts[i].t); } } } static void dump_package(FILE *out, struct ast_package *package, unsigned indent) { { char *v = string_evisciiz(package->name); efprintf(out, "%*spackage %s at ", indent, "", v); printloc(out, package->loc); efprintf(out, "\n"); } } static const char * importqualstr(enum ast_import_qual qual) { switch (qual) { case AST_IQ_DEFAULT: return "default"; case AST_IQ_PUBLIC: return "public"; case AST_IQ_WEAK: return "weak"; default: return "(bad)"; } } static void dump_import(FILE *out, struct ast_import *import, unsigned indent) { { char *v = string_evisciiz(import->pathname); efprintf(out, "%*simport %s (%s) at ", indent, "", v, importqualstr(import->qual)); printloc(out, import->loc); free(v); } } static void dump_extensions(FILE *out, struct ast_extensions *extensions, unsigned indent) { struct ast_extension_range *ranges = extensions->ranges.ranges; size_t i, nranges = extensions->ranges.nranges; efprintf(out, "%*sextensions at ", indent, ""); printloc(out, extensions->loc); efprintf(out, "\n"); indent += 2; for (i = 0; i < nranges; i++) { efprintf(out, "%*s%"PRI_field_tag" to ", indent, "", ranges[i].min); if (ranges[i].max == FIELD_TAG_MAX) efprintf(out, "max"); else efprintf(out, "%"PRI_field_tag, ranges[i].max); efprintf(out, "\n"); } } static void printfieldval(FILE *out, struct ast_fieldval *fv) { switch (fv->t) { char *v; case AST_FIELDVAL_UINT: efprintf(out, "%"PRIu64, fv->u.uint); break; case AST_FIELDVAL_SINT: efprintf(out, "%"PRId64, fv->u.sint); break; case AST_FIELDVAL_REAL: efprintf(out, "%a", fv->u.real); break; case AST_FIELDVAL_BOOLEAN: efprintf(out, "%s", fv->u.boolean? "true" : "false"); break; case AST_FIELDVAL_STRING: v = string_evisciiz(fv->u.string); goto str; case AST_FIELDVAL_ID: v = string_evisciiz(fv->u.id); goto str; str: efprintf(out, "%s", v); free(v); break; default: efprintf(out, "bad fieldval %d", (int)fv->t); } } static const char * fieldquantstr(enum ast_field_quant quant) { switch (quant) { case AST_FQ_REQUIRED: return "required"; case AST_FQ_OPTIONAL: return "optional"; case AST_FQ_REPEATED: return "repeated"; default: return "unknown"; } } static void dump_field(FILE *out, struct ast_field *field, unsigned indent) { { char *v_id = string_evisciiz(field->id); char *v_type = string_evisciiz(field->type.text); efprintf(out, "%*sfield %s quant %s type %s tag %"PRI_field_tag" at ", indent, "", v_id, fieldquantstr(field->quant), v_type, field->tag); printloc(out, field->loc); if (field->options.default_present) { efprintf(out, " default "); printfieldval(out, &field->options.default_value); } efprintf(out, "\n"); free(v_type); free(v_id); } indent += 2; dump_options(out, field->options.options, field->options.noptions, indent); } static void dump_extend(FILE *out, struct ast_extend *extend, unsigned indent) { struct ast_field *fields = extend->fields.fields; size_t i, nfields = extend->fields.nfields; { char *v = string_evisciiz(extend->type.text); efprintf(out, "%*sextend %s at ", indent, "", v); printloc(out, extend->loc); efprintf(out, "\n"); free(v); } indent += 2; for (i = 0; i < nfields; i++) dump_field(out, &fields[i], indent); } static void dump_message(FILE *out, struct ast_message *msg, unsigned indent) { struct ast_message_stmt *stmts = msg->stmts.stmts; size_t i, nstmts = msg->stmts.nstmts; { char *v = string_evisciiz(msg->id); efprintf(out, "%*smessage %s at ", indent, "", v); printloc(out, msg->loc); efprintf(out, "\n"); free(v); } indent += 2; for (i = 0; i < nstmts; i++) { switch (stmts[i].t) { case AST_MESSAGE_STMT_NULL: efprintf(out, "%*snull\n", indent, ""); break; case AST_MESSAGE_STMT_MESSAGE: dump_message(out, &stmts[i].u.message, indent); break; case AST_MESSAGE_STMT_ENUMERATION: dump_enumeration(out, &stmts[i].u.enumeration, indent); break; case AST_MESSAGE_STMT_EXTEND: dump_extend(out, &stmts[i].u.extend, indent); break; case AST_MESSAGE_STMT_OPTION: dump_option(out, &stmts[i].u.option, indent); break; case AST_MESSAGE_STMT_EXTENSIONS: dump_extensions(out, &stmts[i].u.extensions, indent); break; case AST_MESSAGE_STMT_FIELD: dump_field(out, &stmts[i].u.field, indent); break; default: efprintf(out, "%*sbad message stmt %d\n", indent, "", (int)stmts[i].t); } } } static void dump_proto(FILE *out, struct ast_proto *proto, unsigned indent) { struct ast_proto_stmt *stmts = proto->stmts.stmts; size_t i, nstmts = proto->stmts.nstmts; efprintf(out, "%*sproto\n", indent, ""); indent += 2; for (i = 0; i < nstmts; i++) { switch (stmts[i].t) { case AST_PROTO_STMT_NULL: efprintf(out, "%*snull\n", indent, ""); break; case AST_PROTO_STMT_MESSAGE: dump_message(out, &stmts[i].u.message, indent); break; case AST_PROTO_STMT_ENUMERATION: dump_enumeration(out, &stmts[i].u.enumeration, indent); break; case AST_PROTO_STMT_SERVICE: dump_service(out, &stmts[i].u.service, indent); break; case AST_PROTO_STMT_EXTEND: dump_extend(out, &stmts[i].u.extend, indent); break; case AST_PROTO_STMT_IMPORT: dump_import(out, &stmts[i].u.import, indent); break; case AST_PROTO_STMT_PACKAGE: dump_package(out, &stmts[i].u.package, indent); break; case AST_PROTO_STMT_OPTION: dump_option(out, &stmts[i].u.option, indent); break; default: efprintf(out, "%*sbad proto stmt %d\n", indent, "", (int)stmts[i].t); } } } void picopbc_dump(FILE *out, struct ast_proto *proto) { dump_proto(out, proto, 0); }