Attach parameter list span to function

This commit is contained in:
Laurenz 2023-03-18 17:50:57 +01:00
parent f2b0c5e08d
commit 5d475ae32e
3 changed files with 45 additions and 26 deletions

View File

@ -20,7 +20,12 @@ use crate::World;
/// An evaluatable function. /// An evaluatable function.
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
pub struct Func(Arc<Prehashed<Repr>>, Span); pub struct Func {
/// The internal representation.
repr: Arc<Prehashed<Repr>>,
/// The span with which errors are reported when this function is called.
span: Span,
}
/// The different kinds of function representations. /// The different kinds of function representations.
#[derive(Hash)] #[derive(Hash)]
@ -38,7 +43,7 @@ enum Repr {
impl Func { impl Func {
/// The name of the function. /// The name of the function.
pub fn name(&self) -> Option<&str> { pub fn name(&self) -> Option<&str> {
match &**self.0 { match &**self.repr {
Repr::Native(native) => Some(native.info.name), Repr::Native(native) => Some(native.info.name),
Repr::Node(node) => Some(node.info.name), Repr::Node(node) => Some(node.info.name),
Repr::Closure(closure) => closure.name.as_deref(), Repr::Closure(closure) => closure.name.as_deref(),
@ -48,7 +53,7 @@ impl Func {
/// Extract details the function. /// Extract details the function.
pub fn info(&self) -> Option<&FuncInfo> { pub fn info(&self) -> Option<&FuncInfo> {
match &**self.0 { match &**self.repr {
Repr::Native(native) => Some(&native.info), Repr::Native(native) => Some(&native.info),
Repr::Node(node) => Some(&node.info), Repr::Node(node) => Some(&node.info),
Repr::With(func, _) => func.info(), Repr::With(func, _) => func.info(),
@ -58,20 +63,20 @@ impl Func {
/// The function's span. /// The function's span.
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
self.1 self.span
} }
/// Attach a span to this function if it doesn't already have one. /// Attach a span to this function if it doesn't already have one.
pub fn spanned(mut self, span: Span) -> Self { pub fn spanned(mut self, span: Span) -> Self {
if self.1.is_detached() { if self.span.is_detached() {
self.1 = span; self.span = span;
} }
self self
} }
/// The number of positional arguments this function takes, if known. /// The number of positional arguments this function takes, if known.
pub fn argc(&self) -> Option<usize> { pub fn argc(&self) -> Option<usize> {
match &**self.0 { match &**self.repr {
Repr::Closure(closure) => closure.argc(), Repr::Closure(closure) => closure.argc(),
Repr::With(wrapped, applied) => Some(wrapped.argc()?.saturating_sub( Repr::With(wrapped, applied) => Some(wrapped.argc()?.saturating_sub(
applied.items.iter().filter(|arg| arg.name.is_none()).count(), applied.items.iter().filter(|arg| arg.name.is_none()).count(),
@ -82,7 +87,7 @@ impl Func {
/// Call the function with the given arguments. /// Call the function with the given arguments.
pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> { pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> {
match &**self.0 { match &**self.repr {
Repr::Native(native) => { Repr::Native(native) => {
let value = (native.func)(vm, &mut args)?; let value = (native.func)(vm, &mut args)?;
args.finish()?; args.finish()?;
@ -133,8 +138,11 @@ impl Func {
/// Apply the given arguments to the function. /// Apply the given arguments to the function.
pub fn with(self, args: Args) -> Self { pub fn with(self, args: Args) -> Self {
let span = self.1; let span = self.span;
Self(Arc::new(Prehashed::new(Repr::With(self, args))), span) Self {
repr: Arc::new(Prehashed::new(Repr::With(self, args))),
span,
}
} }
/// Create a selector for this function's node type, filtering by node's /// Create a selector for this function's node type, filtering by node's
@ -147,7 +155,7 @@ impl Func {
/// The node id of this function if it is an element function. /// The node id of this function if it is an element function.
pub fn id(&self) -> Option<NodeId> { pub fn id(&self) -> Option<NodeId> {
match **self.0 { match **self.repr {
Repr::Node(id) => Some(id), Repr::Node(id) => Some(id),
_ => None, _ => None,
} }
@ -155,7 +163,7 @@ impl Func {
/// Execute the function's set rule and return the resulting style map. /// Execute the function's set rule and return the resulting style map.
pub fn set(&self, mut args: Args) -> SourceResult<StyleMap> { pub fn set(&self, mut args: Args) -> SourceResult<StyleMap> {
Ok(match &**self.0 { Ok(match &**self.repr {
Repr::Node(node) => { Repr::Node(node) => {
let styles = (node.set)(&mut args)?; let styles = (node.set)(&mut args)?;
args.finish()?; args.finish()?;
@ -190,13 +198,16 @@ impl Debug for Func {
impl PartialEq for Func { impl PartialEq for Func {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
hash128(&self.0) == hash128(&other.0) hash128(&self.repr) == hash128(&other.repr)
} }
} }
impl From<Repr> for Func { impl From<Repr> for Func {
fn from(repr: Repr) -> Self { fn from(repr: Repr) -> Self {
Self(Arc::new(Prehashed::new(repr)), Span::detached()) Self {
repr: Arc::new(Prehashed::new(repr)),
span: Span::detached(),
}
} }
} }
@ -318,7 +329,7 @@ impl Closure {
depth: usize, depth: usize,
mut args: Args, mut args: Args,
) -> SourceResult<Value> { ) -> SourceResult<Value> {
let closure = match &**this.0 { let closure = match &**this.repr {
Repr::Closure(closure) => closure, Repr::Closure(closure) => closure,
_ => panic!("`this` must be a closure"), _ => panic!("`this` must be a closure"),
}; };
@ -436,7 +447,7 @@ impl<'a> CapturesVisitor<'a> {
// body is evaluated. Care must be taken so that the default values // body is evaluated. Care must be taken so that the default values
// of named parameters cannot access previous parameter bindings. // of named parameters cannot access previous parameter bindings.
Some(ast::Expr::Closure(expr)) => { Some(ast::Expr::Closure(expr)) => {
for param in expr.params() { for param in expr.params().children() {
if let ast::Param::Named(named) = param { if let ast::Param::Named(named) = param {
self.visit(named.expr().as_untyped()); self.visit(named.expr().as_untyped());
} }
@ -447,7 +458,7 @@ impl<'a> CapturesVisitor<'a> {
self.bind(name); self.bind(name);
} }
for param in expr.params() { for param in expr.params().children() {
match param { match param {
ast::Param::Pos(ident) => self.bind(ident), ast::Param::Pos(ident) => self.bind(ident),
ast::Param::Named(named) => self.bind(named.name()), ast::Param::Named(named) => self.bind(named.name()),

View File

@ -158,7 +158,7 @@ pub fn eval_code_str(
/// virtual machine is created for each module evaluation and function call. /// virtual machine is created for each module evaluation and function call.
pub struct Vm<'a> { pub struct Vm<'a> {
/// The underlying virtual typesetter. /// The underlying virtual typesetter.
vt: Vt<'a>, pub vt: Vt<'a>,
/// The language items. /// The language items.
items: LangItems, items: LangItems,
/// The route of source ids the VM took to reach its current location. /// The route of source ids the VM took to reach its current location.
@ -1153,7 +1153,7 @@ impl Eval for ast::Closure {
let mut sink = None; let mut sink = None;
// Collect parameters and an optional sink parameter. // Collect parameters and an optional sink parameter.
for param in self.params() { for param in self.params().children() {
match param { match param {
ast::Param::Pos(name) => { ast::Param::Pos(name) => {
params.push((name, None)); params.push((name, None));
@ -1180,7 +1180,7 @@ impl Eval for ast::Closure {
body: self.body(), body: self.body(),
}; };
Ok(Value::Func(Func::from(closure).spanned(self.span()))) Ok(Value::Func(Func::from(closure).spanned(self.params().span())))
} }
} }

View File

@ -1504,12 +1504,8 @@ impl Closure {
} }
/// The parameter bindings. /// The parameter bindings.
pub fn params(&self) -> impl DoubleEndedIterator<Item = Param> + '_ { pub fn params(&self) -> Params {
self.0 self.0.cast_first_match().unwrap_or_default()
.children()
.find(|x| x.kind() == SyntaxKind::Params)
.map_or([].iter(), |params| params.children())
.filter_map(SyntaxNode::cast)
} }
/// The body of the closure. /// The body of the closure.
@ -1518,6 +1514,18 @@ impl Closure {
} }
} }
node! {
/// A closure's parameters: `(x, y)`.
Params
}
impl Params {
/// The parameter bindings.
pub fn children(&self) -> impl DoubleEndedIterator<Item = Param> + '_ {
self.0.children().filter_map(SyntaxNode::cast)
}
}
/// A parameter to a closure. /// A parameter to a closure.
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub enum Param { pub enum Param {