aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--parse_execution.cpp60
-rw-r--r--parse_execution.h10
-rw-r--r--parser.cpp10
-rw-r--r--tests/test9.in5
-rw-r--r--tests/test9.out3
5 files changed, 87 insertions, 1 deletions
diff --git a/parse_execution.cpp b/parse_execution.cpp
index 726f2920..15c7de5f 100644
--- a/parse_execution.cpp
+++ b/parse_execution.cpp
@@ -50,7 +50,7 @@ static wcstring profiling_cmd_name_for_redirectable_block(const parse_node_t &no
return result;
}
-parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, parser_t *p, int initial_eval_level) : tree(t), src(s), parser(p), eval_level(initial_eval_level)
+parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, parser_t *p, int initial_eval_level) : tree(t), src(s), parser(p), eval_level(initial_eval_level), executing_node_idx(NODE_OFFSET_INVALID), cached_lineno_offset(0), cached_lineno_count(0)
{
}
@@ -1302,6 +1302,9 @@ parse_execution_result_t parse_execution_context_t::run_1_job(const parse_node_t
/* Increment the eval_level for the duration of this command */
scoped_push<int> saved_eval_level(&eval_level, eval_level + 1);
+
+ /* Save the node index */
+ scoped_push<node_offset_t> saved_node_offset(&executing_node_idx, this->get_offset(job_node));
/* Profiling support */
long long start_time = 0, parse_time = 0, exec_time = 0;
@@ -1525,3 +1528,58 @@ parse_execution_result_t parse_execution_context_t::eval_node_at_offset(node_off
return status;
}
+
+int parse_execution_context_t::get_current_line_number()
+{
+ /* If we're not executing anything, return -1 */
+ if (this->executing_node_idx == NODE_OFFSET_INVALID)
+ {
+ return -1;
+ }
+
+ /* If for some reason we're executing a node without source, return -1 */
+ const parse_node_t &node = tree.at(this->executing_node_idx);
+ if (! node.has_source())
+ {
+ return -1;
+ }
+
+ /* Count the number of newlines, leveraging our cache */
+ const size_t offset = tree.at(this->executing_node_idx).source_start;
+ assert(offset <= src.size());
+
+ /* Easy hack to handle 0 */
+ if (offset == 0)
+ {
+ return 1;
+ }
+
+ /* We want to return (one plus) the number of newlines at offsets less than the given offset. cached_lineno_count is the number of newlines at indexes less than cached_lineno_offset. */
+ const wchar_t *str = src.c_str();
+ if (offset > cached_lineno_offset)
+ {
+ size_t i;
+ for (i = cached_lineno_offset; str[i] != L'\0' && i < offset; i++)
+ {
+ /* Add one for every newline we find in the range [cached_lineno_offset, offset) */
+ if (str[i] == L'\n')
+ {
+ cached_lineno_count++;
+ }
+ }
+ cached_lineno_offset = i; //note: i, not offset, in case offset is beyond the length of the string
+ }
+ else if (offset < cached_lineno_offset)
+ {
+ /* Subtract one for every newline we find in the range [offset, cached_lineno_offset) */
+ for (size_t i = offset; i < cached_lineno_offset; i++)
+ {
+ if (str[i] == L'\n')
+ {
+ cached_lineno_count--;
+ }
+ }
+ cached_lineno_offset = offset;
+ }
+ return cached_lineno_count + 1;
+}
diff --git a/parse_execution.h b/parse_execution.h
index 8ab5c5d6..91c32c99 100644
--- a/parse_execution.h
+++ b/parse_execution.h
@@ -39,6 +39,13 @@ private:
//parse_error_list_t errors;
int eval_level;
+
+ /* The currently executing node index, used to indicate the line number */
+ node_offset_t executing_node_idx;
+
+ /* Cached line number information */
+ size_t cached_lineno_offset;
+ int cached_lineno_count;
/* No copying allowed */
parse_execution_context_t(const parse_execution_context_t&);
@@ -105,6 +112,9 @@ public:
/* Returns the current eval level */
int current_eval_level() const { return eval_level; }
+
+ /* Returns the current line number. Not const since it touches cached_lineno_offset */
+ int get_current_line_number();
/* Start executing at the given node offset. Returns 0 if there was no error, 1 if there was an error */
parse_execution_result_t eval_node_at_offset(node_offset_t offset, const block_t *associated_block, const io_chain_t &io);
diff --git a/parser.cpp b/parser.cpp
index 0a4f004a..3febef09 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -928,6 +928,16 @@ const wchar_t *parser_t::is_function() const
int parser_t::get_lineno() const
{
+ if (parser_use_ast())
+ {
+ int lineno = -1;
+ if (! execution_contexts.empty())
+ {
+ lineno = execution_contexts.back()->get_current_line_number();
+ }
+ return lineno;
+ }
+
int lineno;
if (! current_tokenizer || ! tok_string(current_tokenizer))
diff --git a/tests/test9.in b/tests/test9.in
index 32a537f7..a3a48151 100644
--- a/tests/test9.in
+++ b/tests/test9.in
@@ -79,4 +79,9 @@ for $var1 in 1 2 3
end
echo
+# Test status -n
+eval 'status -n
+status -n
+status -n'
+
false
diff --git a/tests/test9.out b/tests/test9.out
index e44b2604..d4261863 100644
--- a/tests/test9.out
+++ b/tests/test9.out
@@ -10,3 +10,6 @@ Foop
Doop
Testing for loop
123
+1
+2
+3