Use NonZero types for 1-based line numbers

Since we have a mix of both 0-based and 1-based line numbers in the code base,
we can now distinguish between them by type alone. Also stop using 0 as a
placeholder value for "no line number available" except in explicit helper
functions such as `get_lineno_for_display()`.
This commit is contained in:
Mahmoud Al-Qudsi 2024-07-07 20:58:09 -05:00
parent 92cae9b576
commit 4730a04f25
5 changed files with 22 additions and 15 deletions

View File

@ -340,7 +340,7 @@ pub fn function(
definition_file,
is_copy: false,
copy_definition_file: None,
copy_definition_lineno: 0,
copy_definition_lineno: None,
};
// Add the function itself.

View File

@ -456,7 +456,7 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O
// streams.out.append_format(L"%d\n", parser.get_lineno(opts.level));
streams
.out
.appendln(parser.get_lineno().unwrap_or(0).to_wstring());
.appendln(parser.get_lineno_for_display().to_wstring());
}
STATUS_IS_INTERACTIVE => {
if is_interactive_session() {

View File

@ -16,6 +16,7 @@ use crate::wchar::prelude::*;
use crate::wutil::{dir_iter::DirIter, sprintf};
use once_cell::sync::Lazy;
use std::collections::{HashMap, HashSet};
use std::num::NonZeroU32;
use std::sync::{Arc, Mutex};
#[derive(Clone)]
@ -49,8 +50,8 @@ pub struct FunctionProperties {
/// The file from which the function was copied, or None if not from a file.
pub copy_definition_file: Option<FilenameRef>,
/// The line number where the specified function was copied.
pub copy_definition_lineno: i32,
/// The 1-based line number where the specified function was copied.
pub copy_definition_lineno: Option<NonZeroU32>,
}
/// FunctionProperties are safe to share between threads.
@ -306,7 +307,7 @@ pub fn copy(name: &wstr, new_name: WString, parser: &Parser) -> bool {
new_props.is_autoload.store(false);
new_props.is_copy = true;
new_props.copy_definition_file = filename;
new_props.copy_definition_lineno = lineno.unwrap_or(0) as i32;
new_props.copy_definition_lineno = lineno;
// Note this will NOT overwrite an existing function with the new name.
// TODO: rationalize if this behavior is desired.
@ -390,9 +391,11 @@ impl FunctionProperties {
.count() as i32
}
/// If this function is a copy, return the original line number, else 0.
pub fn copy_definition_lineno(&self) -> i32 {
/// If this function is a copy, return the original 1-based line number. Otherwise, return 0.
pub fn copy_definition_lineno(&self) -> u32 {
self.copy_definition_lineno
.map(|val| val.get())
.unwrap_or(0)
}
/// Return a definition of the function, annotated with properties like event handlers and wrap

View File

@ -247,9 +247,10 @@ impl<NodeType: Node> LineCounter<NodeType> {
}
// Returns the 0-based line number of the node.
pub fn line_offset_of_node(&mut self) -> Option<usize> {
pub fn line_offset_of_node(&mut self) -> Option<u32> {
let src_offset = self.source_offset_of_node()?;
Some(self.line_offset_of_character_at_offset(src_offset))
// Safe to cast/truncate to u32 since SourceRange stores it as a u32 internally
Some(self.line_offset_of_character_at_offset(src_offset) as u32)
}
// Return the 0 based character offset of the node.

View File

@ -668,7 +668,7 @@ impl Parser {
return WString::new();
};
let lineno = self.get_lineno().unwrap_or(0);
let lineno = self.get_lineno_for_display();
let file = self.current_filename();
let mut prefix = WString::new();
@ -709,12 +709,17 @@ impl Parser {
}
/// Returns the current line number, indexed from 1.
pub fn get_lineno(&self) -> Option<usize> {
pub fn get_lineno(&self) -> Option<NonZeroU32> {
// The offset is 0 based; the number is 1 based.
self.line_counter
.borrow_mut()
.line_offset_of_node()
.map(|offset| offset + 1)
.map(|offset| NonZeroU32::new(offset.saturating_add(1)).unwrap())
}
/// Returns the current line number, indexed from 1, or zero if not sourced.
pub fn get_lineno_for_display(&self) -> u32 {
self.get_lineno().map(|val| val.get()).unwrap_or(0)
}
/// Return whether we are currently evaluating a "block" such as an if statement.
@ -846,9 +851,7 @@ impl Parser {
/// Pushes a new block. Returns a pointer to the block, stored in the parser.
pub fn push_block(&self, mut block: Block) -> BlockId {
block.src_lineno = self
.get_lineno()
.and_then(|num| NonZeroU32::new(num.try_into().unwrap_or(u32::MAX)));
block.src_lineno = self.get_lineno();
block.src_filename = self.current_filename();
if block.typ() != BlockType::top {
let new_scope = block.typ() == BlockType::function_call { shadows: true };