Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filterx expr location fixes #120

Merged
merged 6 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/cfg-grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
if (N) \
{ \
(Current).name = YYRHSLOC(Rhs, 1).name; \
(Current).at_line = YYRHSLOC (Rhs, 1).at_line; \
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
Expand All @@ -79,6 +80,7 @@
else \
{ \
(Current).name = YYRHSLOC(Rhs, 0).name; \
(Current).at_line = YYRHSLOC (Rhs, 0).at_line; \
(Current).first_line = (Current).last_line = \
YYRHSLOC (Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
Expand Down
2 changes: 1 addition & 1 deletion lib/cfg-lex.l
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ yy_filter_input(CfgLexer *self, gchar *buf, gsize buf_size)
#define YY_USER_ACTION \
do { \
CFG_LTYPE *cur_lloc = &yyextra->include_stack[yyextra->include_depth].lloc; \
if (YY_START == INITIAL || YY_START == filterx) \
if (YY_START == INITIAL || YY_START == filterx || YY_START == block) \
{ \
cur_lloc->first_column = cur_lloc->last_column; \
} \
Expand Down
65 changes: 61 additions & 4 deletions lib/cfg-lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,71 @@ cfg_lexer_format_location_tag(CfgLexer *self, const CFG_LTYPE *yylloc)
return evt_tag_str("location", cfg_lexer_format_location(self, yylloc, buf, sizeof(buf)));
}

void
cfg_lexer_undo_set_file_location(CfgLexer *self, CFG_LTYPE *yylloc)
{
if (!yylloc->at_line.present)
return;

gboolean lloc_is_oneline = yylloc->first_line == yylloc->last_line;

/* calculate how much we moved, relative to the @line setting */
gint ofs_lines = yylloc->first_line - yylloc->at_line.line;
gint ofs_columns = yylloc->first_column - yylloc->at_line.column;

gint range_lines = yylloc->last_line - yylloc->first_line;

/* the line number moves the same amount as we've processed with the alternative location */
yylloc->first_line = yylloc->at_line.captured_first_line + ofs_lines;
yylloc->last_line = yylloc->first_line + range_lines;

if (ofs_lines == 0)
{
/* we remained on the same line (e.g. the one that follows @line),
* starting column is moved to where @line told us to */

g_assert(lloc_is_oneline);

/* save the length of the token within the same line */
gint range_columns = yylloc->last_column - yylloc->first_column;

/* adjust the first_column */
yylloc->first_column = yylloc->at_line.captured_first_column + ofs_columns;

/* yylloc pointed to a single line and we moved the starting
* column, so let's adjust last_column as well */

yylloc->last_column = yylloc->first_column + range_columns;
}
yylloc->name = yylloc->at_line.captured_name;
yylloc->at_line.present = FALSE;
}

void
cfg_lexer_set_file_location(CfgLexer *self, const gchar *filename, gint line, gint column)
{
CfgIncludeLevel *level = &self->include_stack[self->include_depth];
CFG_LTYPE *yylloc = &level->lloc;

level->lloc.name = g_intern_string(filename);
level->lloc.first_line = level->lloc.last_line = line;
level->lloc.first_column = level->lloc.last_column = column;
level->lloc_changed_by_at_line = TRUE;
/* we already had a previous @line, let's go back as if it didn't exist */
cfg_lexer_undo_set_file_location(self, yylloc);

if (!filename)
{
/* reset to previous state but don't establish a new location */
return;
}

yylloc->at_line.captured_first_line = yylloc->first_line;
yylloc->at_line.captured_first_column = yylloc->first_column;
yylloc->at_line.captured_name = yylloc->name;
yylloc->at_line.line = line;
yylloc->at_line.column = column;
yylloc->at_line.present = TRUE;

yylloc->name = g_intern_string(filename);
yylloc->first_line = yylloc->last_line = line;
yylloc->first_column = yylloc->last_column = column;
}

static int
Expand Down Expand Up @@ -361,6 +417,7 @@ cfg_lexer_include_level_open_buffer(CfgLexer *self, CfgIncludeLevel *level)

level->lloc.first_line = level->lloc.last_line = 1;
level->lloc.first_column = level->lloc.last_column = 1;
level->lloc.at_line.present = FALSE;
return TRUE;
}

Expand Down
28 changes: 21 additions & 7 deletions lib/cfg-lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,24 @@ typedef struct _CfgTokenBlock CfgTokenBlock;

typedef struct CFG_LTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
gint first_line;
gint first_column;
gint last_line;
gint last_column;

/* this value indicates that @line was used which changed lloc relative to
* an actual file */
struct
{
gboolean present;
/* the first line/column at the point of the @line directive */
gint captured_first_line;
gint captured_first_column;
const gchar *captured_name;
/* line/column specified by @line */
gint line;
gint column;
} at_line;

const gchar *name;
} CFG_LTYPE;
Expand Down Expand Up @@ -152,9 +166,8 @@ struct _CfgIncludeLevel
} buffer;
};

/* this value indicates that @line was used which changed lloc relative to
* an actual file */
gboolean lloc_changed_by_at_line;


CFG_LTYPE lloc;
struct yy_buffer_state *yybuf;
};
Expand Down Expand Up @@ -207,6 +220,7 @@ gboolean cfg_lexer_include_buffer(CfgLexer *self, const gchar *name, const gchar
gboolean cfg_lexer_include_buffer_without_backtick_substitution(CfgLexer *self,
const gchar *name, const gchar *buffer, gsize length);
const gchar *cfg_lexer_format_location(CfgLexer *self, const CFG_LTYPE *yylloc, gchar *buf, gsize buf_len);
void cfg_lexer_undo_set_file_location(CfgLexer *self, CFG_LTYPE *yylloc);
void cfg_lexer_set_file_location(CfgLexer *self, const gchar *filename, gint line, gint column);
EVTTAG *cfg_lexer_format_location_tag(CfgLexer *self, const CFG_LTYPE *yylloc);

Expand Down
33 changes: 18 additions & 15 deletions lib/cfg-source.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,22 @@ _report_file_location(const gchar *filename, const CFG_LTYPE *yylloc)
}

static void
_report_buffer_location(const gchar *buffer_content, const CFG_LTYPE *yylloc)
_report_buffer_location(const gchar *buffer_content, const CFG_LTYPE *file_lloc, const CFG_LTYPE *buf_lloc)
{
gchar **lines = g_strsplit(buffer_content, "\n", yylloc->first_line + CONTEXT + 1);
gchar **lines = g_strsplit(buffer_content, "\n", buf_lloc->first_line + CONTEXT + 1);
gint num_lines = g_strv_length(lines);

if (num_lines <= yylloc->first_line)
if (num_lines <= buf_lloc->first_line)
goto exit;

gint start = yylloc->first_line - 1 - CONTEXT;
gint start = buf_lloc->first_line - 1 - CONTEXT;
gint error_index = CONTEXT;
if (start < 0)
{
error_index += start;
start = 0;
}
_print_underlined_source_block(yylloc, &lines[start], error_index);
_print_underlined_source_block(file_lloc, &lines[start], error_index);

exit:
g_strfreev(lines);
Expand All @@ -159,10 +159,10 @@ cfg_source_print_source_context(CfgLexer *lexer, CfgIncludeLevel *level, const C
}
else if (level->include_type == CFGI_BUFFER)
{
if (level->lloc_changed_by_at_line)
_report_file_location(yylloc->name, yylloc);
else
_report_buffer_location(level->buffer.original_content, yylloc);
CFG_LTYPE buf_lloc = *yylloc;
cfg_lexer_undo_set_file_location(lexer, &buf_lloc);

_report_buffer_location(level->buffer.original_content, yylloc, &buf_lloc);
}
return TRUE;
}
Expand Down Expand Up @@ -234,6 +234,9 @@ _extract_source_from_buffer_location(GString *result, const gchar *buffer_conten
if (num_lines <= yylloc->first_line)
goto exit;

if (yylloc->first_column < 1)
goto exit;

for (gint lineno = yylloc->first_line; lineno <= yylloc->last_line; lineno++)
{
gchar *line = lines[lineno - 1];
Expand All @@ -242,9 +245,9 @@ _extract_source_from_buffer_location(GString *result, const gchar *buffer_conten
if (lineno == yylloc->first_line)
{
if (yylloc->first_line == yylloc->last_line)
g_string_append_len(result, &line[MIN(linelen, yylloc->first_column)], yylloc->last_column - yylloc->first_column);
g_string_append_len(result, &line[MIN(linelen, yylloc->first_column-1)], yylloc->last_column - yylloc->first_column);
else
g_string_append(result, &line[MIN(linelen, yylloc->first_column)]);
g_string_append(result, &line[MIN(linelen, yylloc->first_column-1)]);
}
else if (lineno < yylloc->last_line)
{
Expand Down Expand Up @@ -273,10 +276,10 @@ cfg_source_extract_source_text(CfgLexer *lexer, const CFG_LTYPE *yylloc, GString
return _extract_source_from_file_location(result, yylloc->name, yylloc);
else if (level->include_type == CFGI_BUFFER)
{
if (level->lloc_changed_by_at_line)
return _extract_source_from_file_location(result, yylloc->name, yylloc);
else
return _extract_source_from_buffer_location(result, level->buffer.original_content, yylloc);
CFG_LTYPE buf_lloc = *yylloc;
cfg_lexer_undo_set_file_location(lexer, &buf_lloc);

return _extract_source_from_buffer_location(result, level->buffer.original_content, &buf_lloc);
}
else
g_assert_not_reached();
Expand Down
5 changes: 5 additions & 0 deletions lib/pragma-grammar.ym
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,12 @@ line_stmt
cfg_lexer_set_file_location(lexer, $2, $3, $4);
free($2);
}
| KW_LINE LL_EOL
{
cfg_lexer_set_file_location(lexer, NULL, 0, 0);
}

;
/* INCLUDE_RULES */

%%
27 changes: 16 additions & 11 deletions lib/tests/test_lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,57 +188,62 @@ Test(lexer, block_token_is_taken_literally_between_a_pair_of_enclosing_character
_input(" { hello }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" hello ");
assert_location_range(1, 1, 1, 11);
assert_location_range(1, 2, 1, 11);

_input(" { hello\nworld }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" hello\nworld ");
assert_location_range(1, 1, 2, 8);
assert_location_range(1, 2, 2, 8);

_input(" { hello\\\nworld }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" hello\\\nworld ");
assert_location_range(1, 1, 2, 8);
assert_location_range(1, 2, 2, 8);

_input(" { 'hello' }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" 'hello' ");
assert_location_range(1, 1, 1, 13);
assert_location_range(1, 2, 1, 13);

_input(" { 'hello\nworld' }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" 'hello\nworld' ");
assert_location_range(1, 1, 2, 9);
assert_location_range(1, 2, 2, 9);

_input(" { 'hello\\\nworld' }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" 'hello\\\nworld' ");
assert_location_range(1, 1, 2, 9);
assert_location_range(1, 2, 2, 9);

_input(" { \"hello\" }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" \"hello\" ");
assert_location_range(1, 1, 1, 13);
assert_location_range(1, 2, 1, 13);

_input(" { \"hello\nworld\" }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" \"hello\nworld\" ");
assert_location_range(1, 1, 2, 9);
assert_location_range(1, 2, 2, 9);

_input(" { \"hello\\\nworld\" }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" \"hello\\\nworld\" ");
assert_location_range(1, 1, 2, 9);
assert_location_range(1, 2, 2, 9);

_input(" { \"hello \\a\\n\\r\\t\\v\\x40\\o100 world\" }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" \"hello \\a\\n\\r\\t\\v\\x40\\o100 world\" ");
assert_location_range(1, 1, 1, 39);
assert_location_range(1, 2, 1, 39);

_input(" { \"hello \\\" world\" }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block(" \"hello \\\" world\" ");
assert_location_range(1, 1, 1, 22);
assert_location_range(1, 2, 1, 22);

_input("\n{\n \"hello \\\" world\" }");
cfg_lexer_start_block_state(parser->lexer, "{}");
assert_parser_block("\n \"hello \\\" world\" ");
assert_location_range(2, 1, 3, 20);
}

Test(lexer, block_new_lines_in_text_leading_to_the_opening_bracket_are_tracked_properly)
Expand Down
Loading
Loading