From patchwork Wed Jun 22 22:34:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1646810 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=J3gqDfoN; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LSyzn1SR7z9sGp for ; Thu, 23 Jun 2022 08:41:41 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C3D323881873 for ; Wed, 22 Jun 2022 22:41:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C3D323881873 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1655937698; bh=Sbjpn+eVAp/4TyIfZ1t1ZGD6ivrK0yowCnfzfe6Sduo=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=J3gqDfoN5JayGe5eoTW+z0/ZmBohyiVBS/cUJ9ztCluVTDPf5HgSqFxQy+zh24HVu qAiXBbZ6HZuLswhcrXVB1cMgBFtxzDzAmOBe3i6C7tVBAL5yzYd9AYiEoMQ62cULIH ZaHBhyu1U9ffRRsXqdEdMpE0AjjI0EiUqlVWjtmE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id A2D163830654 for ; Wed, 22 Jun 2022 22:34:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A2D163830654 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-649-ZkNWAfjAPWC-wFU1srMogw-1; Wed, 22 Jun 2022 18:34:50 -0400 X-MC-Unique: ZkNWAfjAPWC-wFU1srMogw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 202671C06907 for ; Wed, 22 Jun 2022 22:34:50 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.61]) by smtp.corp.redhat.com (Postfix) with ESMTP id 001C01121314; Wed, 22 Jun 2022 22:34:49 +0000 (UTC) To: gcc-patches@gcc.gnu.org Subject: [PATCH 08/12] Add json-reader.h/cc Date: Wed, 22 Jun 2022 18:34:43 -0400 Message-Id: <20220622223447.2462880-9-dmalcolm@redhat.com> In-Reply-To: <20220622223447.2462880-1-dmalcolm@redhat.com> References: <20220622223447.2462880-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch adds classes that better integrate the JSON parser with GCC's diagnostic subsystem (e.g. line_maps). gcc/ChangeLog: * json-reader.cc: New file. * json-reader.h: New file. Signed-off-by: David Malcolm --- gcc/json-reader.cc | 122 +++++++++++++++++++++++++++++++++++++++++++++ gcc/json-reader.h | 107 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 gcc/json-reader.cc create mode 100644 gcc/json-reader.h diff --git a/gcc/json-reader.cc b/gcc/json-reader.cc new file mode 100644 index 00000000000..e4fbd0db803 --- /dev/null +++ b/gcc/json-reader.cc @@ -0,0 +1,122 @@ +/* Integration of JSON parsing with GCC diagnostics. + Copyright (C) 2022 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "diagnostic.h" +#include "json-reader.h" + +/* Read the contents of PATH into memory, returning a 0-terminated buffer + that must be freed by the caller. + Issue a fatal error if there are any problems. */ + +char * +read_file (const char *path) +{ + FILE *f_in = fopen (path, "r"); + if (!f_in) + fatal_error (UNKNOWN_LOCATION, "unable to open file %qs: %s", + path, xstrerror (errno)); + + /* Read content, allocating a buffer for it. */ + char *result = NULL; + size_t total_sz = 0; + size_t alloc_sz = 0; + char buf[4096]; + size_t iter_sz_in; + + while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) ) + { + gcc_assert (alloc_sz >= total_sz); + size_t old_total_sz = total_sz; + total_sz += iter_sz_in; + /* Allow 1 extra byte for 0-termination. */ + if (alloc_sz < (total_sz + 1)) + { + size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1; + result = (char *)xrealloc (result, new_alloc_sz); + alloc_sz = new_alloc_sz; + } + memcpy (result + old_total_sz, buf, iter_sz_in); + } + + if (!feof (f_in)) + fatal_error (UNKNOWN_LOCATION, "error reading from %qs: %s", path, + xstrerror (errno)); + + fclose (f_in); + + /* 0-terminate the buffer. */ + gcc_assert (total_sz < alloc_sz); + result[total_sz] = '\0'; + + return result; +} + +/* json_reader's ctor. */ + +json_reader::json_reader (const char *filename) +: m_filename (filename), + m_json_loc_map (filename, line_table) +{ +} + +/* Parse UTF8, capturing source location information in m_json_loc_map. + If successful, return the top-level value. + Otherwise, return NULL and write to *ERR_OUT. */ + +json::value * +json_reader::parse_utf8_string (const char *utf8, bool allow_comments, + json::error **err_out) +{ + json::value *result + = json::parse_utf8_string (utf8, allow_comments, err_out, &m_json_loc_map); + return result; +} + +/* Issue an error diagnostic for GMSGID at the location of JV, and exit. */ + +void +json_reader::fatal_error (json::value *jv, const char *gmsgid, ...) +{ + location_t loc = m_json_loc_map.get_range_for_value (jv); + + auto_diagnostic_group d; + va_list ap; + va_start (ap, gmsgid); + rich_location richloc (line_table, loc); + emit_diagnostic_valist (DK_ERROR, &richloc, NULL, 0, gmsgid, &ap); + va_end (ap); + exit (1); + /* Ideally we'd use ::fatal_error here, but we seem to need to use + DK_ERROR for it to be usable from DejaGnu. */ +} + +/* Issue an error diagnostic for ERR, and exit. */ + +void +json_reader::fatal_error (json::error *err) +{ + location_t loc = m_json_loc_map.make_location_for_range (err->get_range ()); + ::error_at (loc, "%s", err->get_msg ()); + exit (1); + /* Ideally we'd use ::fatal_error here, but we seem to need to use + DK_ERROR for it to be usable from DejaGnu. */ +} diff --git a/gcc/json-reader.h b/gcc/json-reader.h new file mode 100644 index 00000000000..4537e29cb6a --- /dev/null +++ b/gcc/json-reader.h @@ -0,0 +1,107 @@ +/* Integration of JSON parsing with GCC diagnostics. + Copyright (C) 2022 David Malcolm . + Contributed by David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_JSON_READER_H +#define GCC_JSON_READER_H + +#include "json-parsing.h" + +/* Concrete implementation of json::location_map that integrates + with a line_table, creating location_t values for the locations + in the JSON file. */ + +class json_line_map : public json::location_map +{ +public: + json_line_map (const char *filename, + line_maps *line_table) + : m_filename (filename), + m_line_table (line_table) + { + linemap_add (m_line_table, LC_ENTER, false, xstrdup (m_filename), 0); + } + + void record_range_for_value (json::value *jv, const range &r) final override + { + location_t loc = make_location_for_range (r); + m_map.put (jv, loc); + } + + void on_finished_parsing () final override + { + linemap_add (m_line_table, LC_LEAVE, false, NULL, 0); + } + + location_t get_range_for_value (json::value *jv) + { + if (location_t *slot = m_map.get (jv)) + return *slot; + return UNKNOWN_LOCATION; + } + + location_t make_location_for_range (const range &r) + { + location_t start = make_location_for_point (r.m_start); + location_t end = make_location_for_point (r.m_end); + return make_location (start, start, end); + } + +private: + location_t make_location_for_point (const point &p) + { + /* json::location_map::point columns are zero-based, + whereas libcpp/gcc columns are 1-based. */ + const int gcc_column = p.m_column + 1; + const int max_column = MAX (1024, gcc_column); + linemap_line_start (m_line_table, p.m_line, max_column); + return linemap_position_for_column (m_line_table, gcc_column); + } + + const char *m_filename; + hash_map m_map; + line_maps *m_line_table; +}; + +/* Class for reading a JSON file, capturing location_t values for + the json::values, and emitting fatal error messages. */ + +class json_reader +{ +public: + json_reader (const char *filename); + json::value *parse_utf8_string (const char *utf8, bool allow_comments, + json::error **err_out); + + void fatal_error (json::value *jv, + const char *gmsgid, ...) + ATTRIBUTE_GCC_DIAG(3,4) + ATTRIBUTE_NORETURN; + + void fatal_error (json::error *err) + ATTRIBUTE_NORETURN; + +protected: + const char *m_filename; + json_line_map m_json_loc_map; +}; + +extern char *read_file (const char *path); + +#endif /* GCC_JSON_READER_H */