Fix argument sinks

Fixes #886.
This commit is contained in:
Laurenz 2023-04-19 17:51:33 +02:00
parent 5a6330dbfc
commit f08ae95b9d
7 changed files with 29 additions and 12 deletions

View File

@ -1,6 +1,9 @@
name: Continuous integration name: Continuous integration
on: [push, pull_request] on: [push, pull_request]
env:
RUSTFLAGS: "-Dwarnings"
jobs: jobs:
ci: ci:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -541,7 +541,7 @@ pub fn gcd(
/// The second integer. /// The second integer.
b: i64, b: i64,
) -> Value { ) -> Value {
Value::Int(calculate_gcd(a, b).into()) Value::Int(calculate_gcd(a, b))
} }
/// Calculates the greatest common divisor of two integers /// Calculates the greatest common divisor of two integers

View File

@ -62,14 +62,23 @@ impl Args {
} }
/// Consume n positional arguments if possible. /// Consume n positional arguments if possible.
pub fn consume(&mut self, n: usize) -> SourceResult<EcoVec<Arg>> { pub fn consume(&mut self, n: usize) -> SourceResult<Vec<Arg>> {
if n > self.items.len() { let mut list = vec![];
let mut i = 0;
while i < self.items.len() && list.len() < n {
if self.items[i].name.is_none() {
list.push(self.items.remove(i));
} else {
i += 1;
}
}
if list.len() < n {
bail!(self.span, "not enough arguments"); bail!(self.span, "not enough arguments");
} }
let vec = self.items.to_vec();
let (left, right) = vec.split_at(n); Ok(list)
self.items = right.into();
Ok(left.into())
} }
/// Consume and cast the first positional argument. /// Consume and cast the first positional argument.

View File

@ -38,20 +38,20 @@ impl<'a> Scopes<'a> {
/// Try to access a variable immutably. /// Try to access a variable immutably.
pub fn get(&self, var: &str) -> StrResult<&Value> { pub fn get(&self, var: &str) -> StrResult<&Value> {
Ok(std::iter::once(&self.top) std::iter::once(&self.top)
.chain(self.scopes.iter().rev()) .chain(self.scopes.iter().rev())
.chain(self.base.map(|base| base.global.scope())) .chain(self.base.map(|base| base.global.scope()))
.find_map(|scope| scope.get(var)) .find_map(|scope| scope.get(var))
.ok_or(eco_format!("unknown variable: {}", var))?) .ok_or_else(|| eco_format!("unknown variable: {}", var))
} }
/// Try to access a variable immutably in math. /// Try to access a variable immutably in math.
pub fn get_in_math(&self, var: &str) -> StrResult<&Value> { pub fn get_in_math(&self, var: &str) -> StrResult<&Value> {
Ok(std::iter::once(&self.top) std::iter::once(&self.top)
.chain(self.scopes.iter().rev()) .chain(self.scopes.iter().rev())
.chain(self.base.map(|base| base.math.scope())) .chain(self.base.map(|base| base.math.scope()))
.find_map(|scope| scope.get(var)) .find_map(|scope| scope.get(var))
.ok_or(eco_format!("unknown variable: {}", var))?) .ok_or_else(|| eco_format!("unknown variable: {}", var))
} }
/// Try to access a variable mutably. /// Try to access a variable mutably.

View File

@ -1047,7 +1047,7 @@ fn validate_dict(p: &mut Parser, m: Marker) {
}; };
if !used.insert(key.clone()) { if !used.insert(key.clone()) {
first.convert_to_error(eco_format!("duplicate key: {}", key)); first.convert_to_error(eco_format!("duplicate key: {key}"));
child.make_erroneous(); child.make_erroneous();
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

View File

@ -0,0 +1,5 @@
// Test bugs with argument sinks.
---
#let foo(..body) = repr(body.pos())
#foo(a: "1", b: "2", 1, 2, 3, 4, 5, 6)