summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Magnusson <ulfalizer@gmail.com>2015-06-15 22:10:19 +0200
committerUlf Magnusson <ulfalizer@gmail.com>2015-06-15 23:29:09 +0200
commit0cebc87848210bf99993527694bb96efe45b9598 (patch)
treeedee507756373a92817d7174d099c54dbf6d869d
parentce80cb14127ff5d592f0d8875a4eb781c6048d04 (diff)
Report correct locations in the presence of continuation lines.
The line number was previously for logical lines only. Oversight. Get rid of _get_lines() and keep the raw lines in _FileFeed instead, only joining lines with continuation lines as they are fetched. This makes the index correspond to the correct line number from the file. (It also means most lines are returned as-is without any logic applied to them, which is nice.) Litter tests/Klocation with continuation lines to get test coverage. Remove some unused functions that were previously inherited from _Feed and remove it as a base class of _FileFeed.
-rw-r--r--kconfiglib.py72
-rw-r--r--tests/Klocation30
-rw-r--r--testsuite.py32
3 files changed, 85 insertions, 49 deletions
diff --git a/kconfiglib.py b/kconfiglib.py
index ad02373..d1e090c 100644
--- a/kconfiglib.py
+++ b/kconfiglib.py
@@ -3099,38 +3099,68 @@ class _Feed(object):
return True
return False
- def unget(self):
- if self.i <= 0:
- _internal_error("Attempt to move back in Feed while already at "
- "the beginning.")
- self.i -= 1
-
def unget_all(self):
self.i = 0
def __len__(self):
return self.length
-class _FileFeed(_Feed):
+class _FileFeed(object):
- """_Feed subclass that feeds lines from a file. Joins any line ending in
- \\ with the following line. Keeps track of the filename and current line
- number."""
+ """Feeds lines from a file. Keeps track of the filename and current line
+ number. Joins any line ending in \\ with the following line. We need to be
+ careful to get the line number right in the presence of continuation
+ lines."""
def __init__(self, filename):
self.filename = _clean_up_path(filename)
- _Feed.__init__(self, _get_lines(filename))
+ with open(filename, "r") as f:
+ # No interleaving of I/O and processing yet. Don't know if it would
+ # help.
+ self.lines = f.readlines()
+ self.length = len(self.lines)
+ self.linenr = 0
+
+ def get_next(self):
+ if self.linenr >= self.length:
+ return None
+ line = self.lines[self.linenr]
+ self.linenr += 1
+ while line.endswith("\\\n"):
+ line = line[:-2] + self.lines[self.linenr]
+ self.linenr += 1
+ return line
+
+ def peek_next(self):
+ linenr = self.linenr
+ if linenr >= self.length:
+ return None
+ line = self.lines[linenr]
+ while line.endswith("\\\n"):
+ linenr += 1
+ line = res[:-2] + self.lines[linenr]
+ return line
+
+ def unget(self):
+ self.linenr -= 1
+ while self.lines[self.linenr].endswith("\\\n"):
+ self.linenr -= 1
def remove_blank(self):
"""Removes lines until the first non-blank (not all-space) line."""
- while self.i < self.length and self.items[self.i].isspace():
- self.i += 1
+ while 1:
+ line = self.get_next()
+ if line is None:
+ break
+ if not line.isspace():
+ self.unget()
+ break
def get_filename(self):
return self.filename
def get_linenr(self):
- return self.i
+ return self.linenr
#
# Internal functions
@@ -3348,20 +3378,6 @@ def _comment(s):
return res + "#"
return res
-def _get_lines(filename):
- """Returns a list of lines from 'filename', joining any line ending in \\
- with the following line."""
- with open(filename, "r") as f:
- lines = []
- accum = ""
- for line in f:
- if line.endswith("\\\n"):
- accum += line[:-2]
- else:
- lines.append(accum + line)
- accum = ""
- return lines
-
def _clean_up_path(path):
"""Strips an initial "./" and any trailing slashes from 'path'."""
if path.startswith("./"):
diff --git a/tests/Klocation b/tests/Klocation
index e445deb..76a886b 100644
--- a/tests/Klocation
+++ b/tests/Klocation
@@ -1,10 +1,15 @@
+# Include some line continuations to make sure they don't mess up line numbers
+
# Defined and referenced in multiple locations
config A
bool
+# Throw in some line continuations too to make sure it doesn't mess up the line
+# numbers
menu "menu 1"
depends on A
- visible if A && NOT_DEFINED
+ visible if A && \
+ NOT_DEFINED
# Also defined in Klocation_included
choice B
@@ -16,6 +21,8 @@ config C
config D
bool "d"
+\
+
endchoice
config A
@@ -29,16 +36,29 @@ config E
endmenu
-config FOO
+config \
+ FOO
string
- option env="FOO"
+ option \
+ env\
+ =\
+ "FOO"
+
+\
+\
config BAR
string
- default "_included"
+ default \
+ "_included"
# Expands to "tests/Klocation_included"
-source "$FOO/Klocation$BAR"
+source \
+"$FOO/Klocation$BAR"
+
+\
+\
+\
config I
int
diff --git a/testsuite.py b/testsuite.py
index a4c9cb3..20974d0 100644
--- a/testsuite.py
+++ b/testsuite.py
@@ -710,12 +710,12 @@ def run_selftests():
verify_def_locations("y")
verify_def_locations("A",
- ("Kconfiglib/tests/Klocation", 2),
- ("Kconfiglib/tests/Klocation", 21),
+ ("Kconfiglib/tests/Klocation", 4),
+ ("Kconfiglib/tests/Klocation", 28),
("Kconfiglib/tests/Klocation_included", 1),
("Kconfiglib/tests/Klocation_included", 3))
verify_def_locations("C",
- ("Kconfiglib/tests/Klocation", 13))
+ ("Kconfiglib/tests/Klocation", 18))
verify_def_locations("M",
("Kconfiglib/tests/Klocation_included", 6))
verify_def_locations("N",
@@ -738,11 +738,11 @@ def run_selftests():
c = kconfiglib.Config("Kconfiglib/tests/Klocation", base_dir = "Kconfiglib")
verify_ref_locations("A",
- ("Kconfiglib/tests/Klocation", 6),
- ("Kconfiglib/tests/Klocation", 7),
- ("Kconfiglib/tests/Klocation", 11),
- ("Kconfiglib/tests/Klocation", 27),
- ("Kconfiglib/tests/Klocation", 28),
+ ("Kconfiglib/tests/Klocation", 10),
+ ("Kconfiglib/tests/Klocation", 12),
+ ("Kconfiglib/tests/Klocation", 16),
+ ("Kconfiglib/tests/Klocation", 34),
+ ("Kconfiglib/tests/Klocation", 35),
("Kconfiglib/tests/Klocation_included", 7),
("Kconfiglib/tests/Klocation_included", 8),
("Kconfiglib/tests/Klocation_included", 9),
@@ -750,13 +750,13 @@ def run_selftests():
("Kconfiglib/tests/Klocation_included", 13),
("Kconfiglib/tests/Klocation_included", 33),
("Kconfiglib/tests/Klocation_included", 38),
- ("Kconfiglib/tests/Klocation", 45),
- ("Kconfiglib/tests/Klocation", 46),
- ("Kconfiglib/tests/Klocation", 47))
+ ("Kconfiglib/tests/Klocation", 65),
+ ("Kconfiglib/tests/Klocation", 66),
+ ("Kconfiglib/tests/Klocation", 67))
verify_ref_locations("C")
verify_ref_locations("NOT_DEFINED",
- ("Kconfiglib/tests/Klocation", 7),
- ("Kconfiglib/tests/Klocation", 22),
+ ("Kconfiglib/tests/Klocation", 12),
+ ("Kconfiglib/tests/Klocation", 29),
("Kconfiglib/tests/Klocation_included", 12),
("Kconfiglib/tests/Klocation_included", 33),
("Kconfiglib/tests/Klocation_included", 39))
@@ -781,7 +781,7 @@ def run_selftests():
"The second choice should have no name")
verify_choice_locations(choice_1,
- ("Kconfiglib/tests/Klocation", 10),
+ ("Kconfiglib/tests/Klocation", 15),
("Kconfiglib/tests/Klocation_included", 22))
verify_choice_locations(choice_2,
("Kconfiglib/tests/Klocation_included", 15))
@@ -802,9 +802,9 @@ def run_selftests():
menu_1, menu_2 = c.get_menus()[:-1]
comment_1, comment_2 = c.get_comments()
- verify_location(menu_1, ("Kconfiglib/tests/Klocation", 5))
+ verify_location(menu_1, ("Kconfiglib/tests/Klocation", 9))
verify_location(menu_2, ("Kconfiglib/tests/Klocation_included", 5))
- verify_location(comment_1, ("Kconfiglib/tests/Klocation", 24))
+ verify_location(comment_1, ("Kconfiglib/tests/Klocation", 31))
verify_location(comment_2, ("Kconfiglib/tests/Klocation_included", 34))
#