blob: c3dcc6e2781141db64143926919ed9de684b3421 [file]
/* m2linemap.cc provides an interface to GCC linemaps.
Copyright (C) 2012-2026 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.ac.uk>.
This file is part of GNU Modula-2.
GNU Modula-2 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.
GNU Modula-2 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 GNU Modula-2; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_STRING
#include "gcc-consolidation.h"
/* Utilize some of the C build routines */
#include "../gm2-lang.h"
#include "../m2-tree.h"
#include "m2assert.h"
#include "m2block.h"
#include "m2decl.h"
#include "m2expr.h"
#include "m2options.h"
#include "m2tree.h"
#include "m2type.h"
#define m2linemap_c
#include "m2linemap.h"
#include "m2color.h"
static int inFile = FALSE;
#if defined(__cplusplus)
#define EXTERN extern "C"
#else
#define EXTERN
#endif
/* Start getting locations from a new file. */
EXTERN
void
m2linemap_StartFile (void *filename, unsigned int linebegin)
{
if (inFile)
m2linemap_EndFile ();
linemap_add (line_table, LC_ENTER, false,
xstrdup (reinterpret_cast<char *> (filename)), linebegin);
inFile = TRUE;
}
/* Tell the line table the file has ended. */
EXTERN
void
m2linemap_EndFile (void)
{
linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
inFile = FALSE;
}
/* Indicate that there is a new source file line number with a
maximum width. */
EXTERN
void
m2linemap_StartLine (unsigned int linenumber, unsigned int linesize)
{
linemap_line_start (line_table, linenumber, linesize);
}
/* GetLocationColumn, returns a location_t based on the current line
number and column. */
EXTERN
location_t
m2linemap_GetLocationColumn (unsigned int column)
{
return linemap_position_for_column (line_table, column);
}
/* GetLocationRange, returns a location based on the start column
and end column. */
EXTERN
location_t
m2linemap_GetLocationRange (unsigned int start, unsigned int end)
{
location_t caret = m2linemap_GetLocationColumn (start);
source_range where;
where.m_start = linemap_position_for_column (line_table, start);
where.m_finish = linemap_position_for_column (line_table, end);
return make_location (caret, where);
}
static
int
isSrcLocation (location_t location)
{
return (location != BUILTINS_LOCATION) && (location != UNKNOWN_LOCATION);
}
/* GetLocationBinary, returns a location based on the expression
start caret finish locations. */
EXTERN
location_t
m2linemap_GetLocationBinary (location_t caret, location_t start, location_t finish)
{
if (isSrcLocation (start) && isSrcLocation (finish) && isSrcLocation (caret)
&& (m2linemap_GetFilenameFromLocation (start) != NULL))
{
linemap_add (line_table, LC_ENTER, false, xstrdup (m2linemap_GetFilenameFromLocation (start)), 1);
gcc_assert (inFile);
location_t location = make_location (caret, start, finish);
linemap_add (line_table, LC_LEAVE, false, NULL, 0);
return location;
}
return caret;
}
/* GetLineNoFromLocation - returns the lineno given a location. */
EXTERN
int
m2linemap_GetLineNoFromLocation (location_t location)
{
if (isSrcLocation (location) && (!M2Options_GetCpp ()))
{
expanded_location xl = expand_location (location);
return xl.line;
}
return 0;
}
/* GetColumnNoFromLocation - returns the columnno given a location. */
EXTERN
int
m2linemap_GetColumnNoFromLocation (location_t location)
{
if (isSrcLocation (location) && (!M2Options_GetCpp ()))
{
expanded_location xl = expand_location (location);
return xl.column;
}
return 0;
}
/* GetFilenameFromLocation - returns the filename given a location. */
EXTERN
const char *
m2linemap_GetFilenameFromLocation (location_t location)
{
if (isSrcLocation (location) && (!M2Options_GetCpp ()))
{
expanded_location xl = expand_location (location);
return xl.file;
}
return NULL;
}
/* ErrorAt - issue an error message. */
EXTERN
void
m2linemap_ErrorAt (location_t location, char *message)
{
error_at (location, "%s", message);
}
/* m2linemap_ErrorAtf - wraps up an error message. */
static void
m2linemap_ErrorAtf_1 (location_t location, const char *message, ...)
{
diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, message);
diagnostic_set_info (&diagnostic, message, &ap, &richloc,
diagnostics::kind::error);
diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
}
void
m2linemap_ErrorAtf (location_t location, const char *message)
{
m2linemap_ErrorAtf_1 (location, "%s", message);
}
/* m2linemap_WarningAtf - wraps up a warning message. */
static void
m2linemap_WarningAtf_1 (location_t location, const char *message, ...)
{
diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, message);
diagnostic_set_info (&diagnostic, message, &ap, &richloc,
diagnostics::kind::warning);
diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
}
void
m2linemap_WarningAtf (location_t location, const char *message)
{
m2linemap_WarningAtf_1 (location, "%s", message);
}
/* m2linemap_NoteAtf - wraps up a note message. */
static void
m2linemap_NoteAtf_1 (location_t location, const char *message, ...)
{
diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, message);
diagnostic_set_info (&diagnostic, message, &ap, &richloc,
diagnostics::kind::note);
diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
}
void
m2linemap_NoteAtf (location_t location, const char *message)
{
m2linemap_NoteAtf_1 (location, "%s", message);
}
/* m2linemap_internal_error - allow Modula-2 to use the GCC internal error. */
void
m2linemap_internal_error (const char *message)
{
internal_error ("%s", message);
}
/* Code derived from rust. */
static std::string
mformat_value ()
{
return std::string (xstrerror (errno));
}
static std::string
expand_format (const char *fmt)
{
std::string result;
for (const char *c = fmt; *c; ++c)
{
if (*c != '%')
{
result += *c;
continue;
}
c++;
switch (*c)
{
case '\0': {
// malformed format string
gcc_unreachable ();
}
case '%': {
result += '%';
break;
}
case 'm': {
result += mformat_value ();
break;
}
case '<': {
result += m2color_open_quote ();
break;
}
case '>': {
result += m2color_close_quote ();
break;
}
case 'q': {
result += m2color_open_quote ();
c++;
if (*c == 'm')
result += mformat_value ();
else
{
result += '%';
result += *c;
}
result += m2color_close_quote ();
break;
}
default: {
result += '%';
result += *c;
}
}
}
return result;
}
static std::string
expand_message (const char *fmt, va_list ap)
{
char *mbuf = 0;
std::string expanded_fmt = expand_format (fmt);
int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap);
if (nwr == -1)
{
// memory allocation failed
error_at (UNKNOWN_LOCATION,
"memory allocation failed in vasprintf");
gcc_assert (0);
}
std::string rval = std::string (mbuf);
free (mbuf);
return rval;
}
static void
gm2_internal_error_at (location_t location, const std::string &errmsg)
{
expanded_location exp_loc = expand_location (location);
std::string loc_str;
std::string file_str;
if (exp_loc.file == NULL)
file_str.clear ();
else
file_str = std::string (exp_loc.file);
if (! file_str.empty ())
{
loc_str += file_str;
loc_str += ':';
loc_str += std::to_string (exp_loc.line);
loc_str += ':';
loc_str += std::to_string (exp_loc.column);
}
if (loc_str.empty ())
internal_error ("%s", errmsg.c_str ());
else
internal_error ("at %s, %s", loc_str.c_str (), errmsg.c_str ());
}
void
m2linemap_internal_error_at (location_t location, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
gm2_internal_error_at (location, expand_message (fmt, ap));
va_end (ap);
}
/* UnknownLocation - return the predefined location representing an
unknown location. */
EXTERN
location_t
m2linemap_UnknownLocation (void)
{
return UNKNOWN_LOCATION;
}
/* BuiltinsLocation - return the predefined location representing a
builtin. */
EXTERN
location_t
m2linemap_BuiltinsLocation (void)
{
return BUILTINS_LOCATION;
}