diff --git a/src/lex/indent.c b/src/lex/indent.c index a6defd5..470f06e 100644 --- a/src/lex/indent.c +++ b/src/lex/indent.c @@ -108,58 +108,53 @@ static uint32_t count_indents(enum indent_type type) { return counter; } -static void new_indent(void) { +// Returns `true` if a new indentation level was introduced. +static _Bool new_indent(void) { struct indent indent = { 0, 0 }; indent.tabs = count_indents(INDENT_TABS); indent.spaces = count_indents(INDENT_SPACES); char c = peekc(); - if (c == '\t' && (indent.spaces > 0 || !tabs_allowed())) { + if ((indent.tabs > 0 && !tabs_allowed()) || (c == '\t' && indent.spaces > 0)) { fprintf(stderr, "lexical error: all tabs on a line must precede all spaces\n"); exit(1); } - if (is_newline(c)) { - return; - } - if (indent_levels == MAX_INDENTS) { + if (indent_levels == MAX_INDENTS && !is_newline(c)) { fprintf(stderr, "lexical error: too many indentation levels! factor your code!\n"); exit(1); } indents[indent_levels] = indent; - indent_levels++; + return indent.tabs > 0 || indent.spaces > 0; } -int32_t lex_indentation(void) { +uint32_t lex_line_indentation(void) { uint32_t indent_level = 0; - char c = peekc(); - while (true) { - while (is_newline(c)) { - nextc(); - c = peekc(); - } - if (c == 0) { - indent_levels = 0; + while (indent_level < indent_levels) { + if (!is_indent(peekc())) { return indent_level; } - if (!is_indent(c)) { - break; - } + struct indent expected_indent = indents[indent_level]; + expect_indent(INDENT_TABS, expected_indent.tabs); + expect_indent(INDENT_SPACES, expected_indent.spaces); + indent_level++; + } + if (new_indent()) { + return indent_level + 1; + } + return indent_level; +} + +uint32_t lex_indentation(void) { + uint32_t indent_level; + while (true) { + indent_level = lex_line_indentation(); + // We ignore trailing whitespace on empty lines, + // but don't know that a line will be empty until we've reached the end. + if (!is_newline(peekc())) { break; } + nextc(); + } + if (peekc() == 0) { + // EOF closes all indentation-based blocks. indent_level = 0; - while (is_indent(c) && indent_level < indent_levels) { - struct indent indent = indents[indent_level]; - expect_indent(INDENT_TABS, indent.tabs); - expect_indent(INDENT_SPACES, indent.spaces); - indent_level++; - c = peekc(); - } - if (is_indent(c)) { - new_indent(); - c = peekc(); - if (!is_newline(c)) { - indent_levels++; - return indent_levels; - } - } - c = peekc(); } indent_levels = indent_level; return indent_levels; diff --git a/src/lex/indent.h b/src/lex/indent.h index 5504d4a..dc7eff6 100644 --- a/src/lex/indent.h +++ b/src/lex/indent.h @@ -9,6 +9,6 @@ _Bool is_newline(char c); _Bool is_indent(char c); -int32_t lex_indentation(void); +uint32_t lex_indentation(void); #endif