mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Remove method call syntax kind
This commit is contained in:
parent
2d56e3c5e2
commit
406de22ee5
@ -7,9 +7,7 @@ use crate::World;
|
|||||||
/// Try to determine a set of possible values for an expression.
|
/// Try to determine a set of possible values for an expression.
|
||||||
pub fn analyze(world: &(dyn World + 'static), node: &LinkedNode) -> Vec<Value> {
|
pub fn analyze(world: &(dyn World + 'static), node: &LinkedNode) -> Vec<Value> {
|
||||||
match node.cast::<ast::Expr>() {
|
match node.cast::<ast::Expr>() {
|
||||||
Some(
|
Some(ast::Expr::Ident(_) | ast::Expr::MathIdent(_) | ast::Expr::FuncCall(_)) => {
|
||||||
ast::Expr::Ident(_) | ast::Expr::MathIdent(_) | ast::Expr::MethodCall(_),
|
|
||||||
) => {
|
|
||||||
if let Some(parent) = node.parent() {
|
if let Some(parent) = node.parent() {
|
||||||
if parent.kind() == SyntaxKind::FieldAccess && node.index() > 0 {
|
if parent.kind() == SyntaxKind::FieldAccess && node.index() > 0 {
|
||||||
return analyze(world, parent);
|
return analyze(world, parent);
|
||||||
|
@ -4,7 +4,7 @@ use if_chain::if_chain;
|
|||||||
|
|
||||||
use super::{analyze, plain_docs_sentence, summarize_font_family};
|
use super::{analyze, plain_docs_sentence, summarize_font_family};
|
||||||
use crate::model::{methods_on, CastInfo, Scope, Value};
|
use crate::model::{methods_on, CastInfo, Scope, Value};
|
||||||
use crate::syntax::{ast, LinkedNode, Source, SyntaxKind, SyntaxNode};
|
use crate::syntax::{ast, LinkedNode, Source, SyntaxKind};
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
|
||||||
@ -936,9 +936,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
|
|
||||||
if let Some(parent) = node.parent() {
|
if let Some(parent) = node.parent() {
|
||||||
if let Some(v) = parent.cast::<ast::ForLoop>() {
|
if let Some(v) = parent.cast::<ast::ForLoop>() {
|
||||||
if node.prev_sibling().as_deref().map(SyntaxNode::kind)
|
if node.prev_sibling_kind() != Some(SyntaxKind::In) {
|
||||||
!= Some(SyntaxKind::In)
|
|
||||||
{
|
|
||||||
let pattern = v.pattern();
|
let pattern = v.pattern();
|
||||||
if let Some(key) = pattern.key() {
|
if let Some(key) = pattern.key() {
|
||||||
defined.insert(key.take());
|
defined.insert(key.take());
|
||||||
|
@ -85,8 +85,7 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
|||||||
match node.kind() {
|
match node.kind() {
|
||||||
SyntaxKind::Markup
|
SyntaxKind::Markup
|
||||||
if node.parent_kind() == Some(SyntaxKind::TermItem)
|
if node.parent_kind() == Some(SyntaxKind::TermItem)
|
||||||
&& node.next_sibling().as_ref().map(|v| v.kind())
|
&& node.next_sibling_kind() == Some(SyntaxKind::Colon) =>
|
||||||
== Some(SyntaxKind::Colon) =>
|
|
||||||
{
|
{
|
||||||
Some(Category::ListTerm)
|
Some(Category::ListTerm)
|
||||||
}
|
}
|
||||||
@ -116,17 +115,12 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
|||||||
|
|
||||||
SyntaxKind::Math => None,
|
SyntaxKind::Math => None,
|
||||||
SyntaxKind::MathIdent => highlight_ident(node),
|
SyntaxKind::MathIdent => highlight_ident(node),
|
||||||
|
SyntaxKind::MathAlignPoint => Some(Category::MathOperator),
|
||||||
SyntaxKind::MathDelimited => None,
|
SyntaxKind::MathDelimited => None,
|
||||||
SyntaxKind::MathAttach => None,
|
SyntaxKind::MathAttach => None,
|
||||||
SyntaxKind::MathFrac => None,
|
SyntaxKind::MathFrac => None,
|
||||||
SyntaxKind::MathAlignPoint => Some(Category::MathOperator),
|
|
||||||
|
|
||||||
SyntaxKind::Hashtag => node
|
|
||||||
.next_sibling()
|
|
||||||
.filter(|node| node.cast::<ast::Expr>().map_or(false, |e| e.hashtag()))
|
|
||||||
.and_then(|node| node.leftmost_leaf())
|
|
||||||
.and_then(|node| highlight(&node)),
|
|
||||||
|
|
||||||
|
SyntaxKind::Hashtag => highlight_hashtag(node),
|
||||||
SyntaxKind::LeftBrace => Some(Category::Punctuation),
|
SyntaxKind::LeftBrace => Some(Category::Punctuation),
|
||||||
SyntaxKind::RightBrace => Some(Category::Punctuation),
|
SyntaxKind::RightBrace => Some(Category::Punctuation),
|
||||||
SyntaxKind::LeftBracket => Some(Category::Punctuation),
|
SyntaxKind::LeftBracket => Some(Category::Punctuation),
|
||||||
@ -206,18 +200,8 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
|||||||
SyntaxKind::Keyed => None,
|
SyntaxKind::Keyed => None,
|
||||||
SyntaxKind::Unary => None,
|
SyntaxKind::Unary => None,
|
||||||
SyntaxKind::Binary => None,
|
SyntaxKind::Binary => None,
|
||||||
SyntaxKind::FieldAccess => match node.parent_kind() {
|
SyntaxKind::FieldAccess => None,
|
||||||
Some(
|
|
||||||
SyntaxKind::Markup
|
|
||||||
| SyntaxKind::Math
|
|
||||||
| SyntaxKind::MathFrac
|
|
||||||
| SyntaxKind::MathAttach,
|
|
||||||
) => Some(Category::Interpolated),
|
|
||||||
Some(SyntaxKind::FieldAccess) => node.parent().and_then(highlight),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
SyntaxKind::FuncCall => None,
|
SyntaxKind::FuncCall => None,
|
||||||
SyntaxKind::MethodCall => None,
|
|
||||||
SyntaxKind::Args => None,
|
SyntaxKind::Args => None,
|
||||||
SyntaxKind::Spread => None,
|
SyntaxKind::Spread => None,
|
||||||
SyntaxKind::Closure => None,
|
SyntaxKind::Closure => None,
|
||||||
@ -245,49 +229,60 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
|||||||
|
|
||||||
/// Highlight an identifier based on context.
|
/// Highlight an identifier based on context.
|
||||||
fn highlight_ident(node: &LinkedNode) -> Option<Category> {
|
fn highlight_ident(node: &LinkedNode) -> Option<Category> {
|
||||||
match node.parent_kind() {
|
// Are we directly before an argument list?
|
||||||
Some(SyntaxKind::FuncCall) => Some(Category::Function),
|
let next_leaf_kind = node.next_leaf().map(|leaf| leaf.kind());
|
||||||
Some(SyntaxKind::FieldAccess)
|
if matches!(next_leaf_kind, Some(SyntaxKind::LeftParen | SyntaxKind::LeftBracket)) {
|
||||||
if node.parent().and_then(|p| p.parent_kind())
|
return Some(Category::Function);
|
||||||
== Some(SyntaxKind::SetRule)
|
|
||||||
&& node.next_sibling().is_none() =>
|
|
||||||
{
|
|
||||||
Some(Category::Function)
|
|
||||||
}
|
|
||||||
Some(SyntaxKind::FieldAccess)
|
|
||||||
if node
|
|
||||||
.parent()
|
|
||||||
.and_then(|p| p.parent())
|
|
||||||
.filter(|gp| gp.kind() == SyntaxKind::Parenthesized)
|
|
||||||
.and_then(|gp| gp.parent())
|
|
||||||
.map_or(false, |ggp| ggp.kind() == SyntaxKind::FuncCall)
|
|
||||||
&& node.next_sibling().is_none() =>
|
|
||||||
{
|
|
||||||
Some(Category::Function)
|
|
||||||
}
|
|
||||||
Some(SyntaxKind::FieldAccess) => node.parent().and_then(highlight),
|
|
||||||
Some(SyntaxKind::MethodCall) if node.prev_sibling().is_some() => {
|
|
||||||
Some(Category::Function)
|
|
||||||
}
|
|
||||||
Some(SyntaxKind::Closure) if node.prev_sibling().is_none() => {
|
|
||||||
Some(Category::Function)
|
|
||||||
}
|
|
||||||
Some(SyntaxKind::SetRule) => Some(Category::Function),
|
|
||||||
Some(SyntaxKind::ShowRule)
|
|
||||||
if node.prev_sibling().as_ref().map(|v| v.kind())
|
|
||||||
== Some(SyntaxKind::Show) =>
|
|
||||||
{
|
|
||||||
Some(Category::Function)
|
|
||||||
}
|
|
||||||
Some(
|
|
||||||
SyntaxKind::Markup
|
|
||||||
| SyntaxKind::Math
|
|
||||||
| SyntaxKind::MathFrac
|
|
||||||
| SyntaxKind::MathAttach,
|
|
||||||
) => Some(Category::Interpolated),
|
|
||||||
_ if node.kind() == SyntaxKind::MathIdent => Some(Category::Interpolated),
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Are we in math?
|
||||||
|
if node.kind() == SyntaxKind::MathIdent {
|
||||||
|
return Some(Category::Interpolated);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the first non-field access ancestor.
|
||||||
|
let mut ancestor = node;
|
||||||
|
while ancestor.parent_kind() == Some(SyntaxKind::FieldAccess) {
|
||||||
|
ancestor = ancestor.parent()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we directly before a show rule colon?
|
||||||
|
if next_leaf_kind == Some(SyntaxKind::Colon)
|
||||||
|
&& ancestor.parent_kind() == Some(SyntaxKind::ShowRule)
|
||||||
|
{
|
||||||
|
return Some(Category::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we (or an ancestor field access) directly after a hashtag.
|
||||||
|
if ancestor.prev_leaf().map(|leaf| leaf.kind()) == Some(SyntaxKind::Hashtag) {
|
||||||
|
return Some(Category::Interpolated);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we behind a dot, that is behind another identifier?
|
||||||
|
let prev = node.prev_leaf()?;
|
||||||
|
if prev.kind() == SyntaxKind::Dot {
|
||||||
|
let prev_prev = prev.prev_leaf()?;
|
||||||
|
if is_ident(&prev_prev) {
|
||||||
|
return highlight_ident(&prev_prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Highlight a hashtag based on context.
|
||||||
|
fn highlight_hashtag(node: &LinkedNode) -> Option<Category> {
|
||||||
|
let next = node.next_sibling()?;
|
||||||
|
let expr = next.cast::<ast::Expr>()?;
|
||||||
|
if !expr.hashtag() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
highlight(&next.leftmost_leaf()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the node is one of the two identifier nodes.
|
||||||
|
fn is_ident(node: &LinkedNode) -> bool {
|
||||||
|
matches!(node.kind(), SyntaxKind::Ident | SyntaxKind::MathIdent)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -364,7 +364,6 @@ impl Eval for ast::Expr {
|
|||||||
Self::Parenthesized(v) => v.eval(vm),
|
Self::Parenthesized(v) => v.eval(vm),
|
||||||
Self::FieldAccess(v) => v.eval(vm),
|
Self::FieldAccess(v) => v.eval(vm),
|
||||||
Self::FuncCall(v) => v.eval(vm),
|
Self::FuncCall(v) => v.eval(vm),
|
||||||
Self::MethodCall(v) => v.eval(vm),
|
|
||||||
Self::Closure(v) => v.eval(vm),
|
Self::Closure(v) => v.eval(vm),
|
||||||
Self::Unary(v) => v.eval(vm),
|
Self::Unary(v) => v.eval(vm),
|
||||||
Self::Binary(v) => v.eval(vm),
|
Self::Binary(v) => v.eval(vm),
|
||||||
@ -918,12 +917,51 @@ impl Eval for ast::FuncCall {
|
|||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||||
let callee_expr = self.callee();
|
let span = self.span();
|
||||||
let callee_span = callee_expr.span();
|
let callee = self.callee();
|
||||||
let callee = callee_expr.eval(vm)?;
|
let in_math = in_math(&callee);
|
||||||
let mut args = self.args().eval(vm)?;
|
let callee_span = callee.span();
|
||||||
|
let args = self.args();
|
||||||
|
|
||||||
if in_math(&callee_expr) && !matches!(callee, Value::Func(_)) {
|
// Try to evaluate as a method call. This is possible if the callee is a
|
||||||
|
// field access and does not evaluate to a module.
|
||||||
|
let (callee, mut args) = if let ast::Expr::FieldAccess(access) = callee {
|
||||||
|
let target = access.target();
|
||||||
|
let method = access.field();
|
||||||
|
let method_span = method.span();
|
||||||
|
let method = method.take();
|
||||||
|
let point = || Tracepoint::Call(Some(method.clone()));
|
||||||
|
if methods::is_mutating(&method) {
|
||||||
|
let args = args.eval(vm)?;
|
||||||
|
let value = target.access(vm)?;
|
||||||
|
|
||||||
|
let value = if let Value::Module(module) = &value {
|
||||||
|
module.get(&method).cloned().at(method_span)?
|
||||||
|
} else {
|
||||||
|
return methods::call_mut(value, &method, args, span)
|
||||||
|
.trace(vm.world, point, span);
|
||||||
|
};
|
||||||
|
|
||||||
|
(value, args)
|
||||||
|
} else {
|
||||||
|
let target = target.eval(vm)?;
|
||||||
|
let args = args.eval(vm)?;
|
||||||
|
let value = if let Value::Module(module) = &target {
|
||||||
|
module.get(&method).cloned().at(method_span)?
|
||||||
|
} else {
|
||||||
|
return methods::call(vm, target, &method, args, span)
|
||||||
|
.trace(vm.world, point, span);
|
||||||
|
};
|
||||||
|
(value, args)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(callee.eval(vm)?, args.eval(vm)?)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle math special cases for non-functions:
|
||||||
|
// Combining accent symbols apply themselves while everything else
|
||||||
|
// simply displays the arguments verbatim.
|
||||||
|
if in_math && !matches!(callee, Value::Func(_)) {
|
||||||
if let Value::Symbol(sym) = &callee {
|
if let Value::Symbol(sym) = &callee {
|
||||||
let c = sym.get();
|
let c = sym.get();
|
||||||
if let Some(accent) = combining_accent(c) {
|
if let Some(accent) = combining_accent(c) {
|
||||||
@ -932,7 +970,6 @@ impl Eval for ast::FuncCall {
|
|||||||
return Ok(Value::Content((vm.items.math_accent)(base, accent)));
|
return Ok(Value::Content((vm.items.math_accent)(base, accent)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut body = (vm.items.text)('('.into());
|
let mut body = (vm.items.text)('('.into());
|
||||||
for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
|
for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
@ -944,8 +981,14 @@ impl Eval for ast::FuncCall {
|
|||||||
return Ok(Value::Content(callee.display() + body));
|
return Ok(Value::Content(callee.display() + body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finally, just a normal function call!
|
||||||
|
if vm.depth >= MAX_CALL_DEPTH {
|
||||||
|
bail!(span, "maximum function call depth exceeded");
|
||||||
|
}
|
||||||
|
|
||||||
let callee = callee.cast::<Func>().at(callee_span)?;
|
let callee = callee.cast::<Func>().at(callee_span)?;
|
||||||
complete_call(vm, &callee, args, self.span())
|
let point = || Tracepoint::Call(callee.name().map(Into::into));
|
||||||
|
callee.call(vm, args).trace(vm.world, point, span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -957,59 +1000,6 @@ fn in_math(expr: &ast::Expr) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_call(
|
|
||||||
vm: &mut Vm,
|
|
||||||
callee: &Func,
|
|
||||||
args: Args,
|
|
||||||
span: Span,
|
|
||||||
) -> SourceResult<Value> {
|
|
||||||
if vm.depth >= MAX_CALL_DEPTH {
|
|
||||||
bail!(span, "maximum function call depth exceeded");
|
|
||||||
}
|
|
||||||
|
|
||||||
let point = || Tracepoint::Call(callee.name().map(Into::into));
|
|
||||||
callee.call(vm, args).trace(vm.world, point, span)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eval for ast::MethodCall {
|
|
||||||
type Output = Value;
|
|
||||||
|
|
||||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
|
||||||
let span = self.span();
|
|
||||||
let method = self.method();
|
|
||||||
|
|
||||||
let result = if methods::is_mutating(&method) {
|
|
||||||
let args = self.args().eval(vm)?;
|
|
||||||
let value = self.target().access(vm)?;
|
|
||||||
|
|
||||||
if let Value::Module(module) = &value {
|
|
||||||
if let Value::Func(callee) =
|
|
||||||
module.get(&method).cloned().at(method.span())?
|
|
||||||
{
|
|
||||||
return complete_call(vm, &callee, args, self.span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
methods::call_mut(value, &method, args, span)
|
|
||||||
} else {
|
|
||||||
let value = self.target().eval(vm)?;
|
|
||||||
let args = self.args().eval(vm)?;
|
|
||||||
|
|
||||||
if let Value::Module(module) = &value {
|
|
||||||
if let Value::Func(callee) = module.get(&method).at(method.span())? {
|
|
||||||
return complete_call(vm, callee, args, self.span());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
methods::call(vm, value, &method, args, span)
|
|
||||||
};
|
|
||||||
|
|
||||||
let method = method.take();
|
|
||||||
let point = || Tracepoint::Call(Some(method.clone()));
|
|
||||||
result.trace(vm.world, point, span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eval for ast::Args {
|
impl Eval for ast::Args {
|
||||||
type Output = Args;
|
type Output = Args;
|
||||||
|
|
||||||
@ -1223,8 +1213,12 @@ impl Eval for ast::WhileLoop {
|
|||||||
fn is_invariant(expr: &SyntaxNode) -> bool {
|
fn is_invariant(expr: &SyntaxNode) -> bool {
|
||||||
match expr.cast() {
|
match expr.cast() {
|
||||||
Some(ast::Expr::Ident(_)) => false,
|
Some(ast::Expr::Ident(_)) => false,
|
||||||
Some(ast::Expr::MethodCall(call)) => {
|
Some(ast::Expr::MathIdent(_)) => false,
|
||||||
is_invariant(call.target().as_untyped())
|
Some(ast::Expr::FieldAccess(access)) => {
|
||||||
|
is_invariant(access.target().as_untyped())
|
||||||
|
}
|
||||||
|
Some(ast::Expr::FuncCall(call)) => {
|
||||||
|
is_invariant(call.callee().as_untyped())
|
||||||
&& is_invariant(call.args().as_untyped())
|
&& is_invariant(call.args().as_untyped())
|
||||||
}
|
}
|
||||||
_ => expr.children().all(is_invariant),
|
_ => expr.children().all(is_invariant),
|
||||||
@ -1434,7 +1428,7 @@ impl Access for ast::Expr {
|
|||||||
Self::Ident(v) => v.access(vm),
|
Self::Ident(v) => v.access(vm),
|
||||||
Self::Parenthesized(v) => v.access(vm),
|
Self::Parenthesized(v) => v.access(vm),
|
||||||
Self::FieldAccess(v) => v.access(vm),
|
Self::FieldAccess(v) => v.access(vm),
|
||||||
Self::MethodCall(v) => v.access(vm),
|
Self::FuncCall(v) => v.access(vm),
|
||||||
_ => {
|
_ => {
|
||||||
let _ = self.eval(vm)?;
|
let _ = self.eval(vm)?;
|
||||||
bail!(self.span(), "cannot mutate a temporary value");
|
bail!(self.span(), "cannot mutate a temporary value");
|
||||||
@ -1479,22 +1473,22 @@ impl ast::FieldAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Access for ast::MethodCall {
|
impl Access for ast::FuncCall {
|
||||||
fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> {
|
fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value> {
|
||||||
let span = self.span();
|
if let ast::Expr::FieldAccess(access) = self.callee() {
|
||||||
let method = self.method().take();
|
let method = access.field().take();
|
||||||
let world = vm.world();
|
if methods::is_accessor(&method) {
|
||||||
|
let span = self.span();
|
||||||
if !methods::is_accessor(&method) {
|
let world = vm.world();
|
||||||
let _ = self.eval(vm)?;
|
let args = self.args().eval(vm)?;
|
||||||
bail!(span, "cannot mutate a temporary value");
|
let value = access.target().access(vm)?;
|
||||||
|
let result = methods::call_access(value, &method, args, span);
|
||||||
|
let point = || Tracepoint::Call(Some(method.clone()));
|
||||||
|
return result.trace(world, point, span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = self.args().eval(vm)?;
|
let _ = self.eval(vm)?;
|
||||||
let value = self.target().access(vm)?;
|
bail!(self.span(), "cannot mutate a temporary value");
|
||||||
let result = methods::call_access(value, &method, args, span);
|
|
||||||
|
|
||||||
let point = || Tracepoint::Call(Some(method.clone()));
|
|
||||||
result.trace(world, point, span)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,10 +157,8 @@ pub enum Expr {
|
|||||||
Binary(Binary),
|
Binary(Binary),
|
||||||
/// A field access: `properties.age`.
|
/// A field access: `properties.age`.
|
||||||
FieldAccess(FieldAccess),
|
FieldAccess(FieldAccess),
|
||||||
/// An invocation of a function: `f(x, y)`.
|
/// An invocation of a function or method: `f(x, y)`.
|
||||||
FuncCall(FuncCall),
|
FuncCall(FuncCall),
|
||||||
/// An invocation of a method: `array.push(v)`.
|
|
||||||
MethodCall(MethodCall),
|
|
||||||
/// A closure: `(x, y) => z`.
|
/// A closure: `(x, y) => z`.
|
||||||
Closure(Closure),
|
Closure(Closure),
|
||||||
/// A let binding: `let x = 1`.
|
/// A let binding: `let x = 1`.
|
||||||
@ -239,7 +237,6 @@ impl AstNode for Expr {
|
|||||||
SyntaxKind::Binary => node.cast().map(Self::Binary),
|
SyntaxKind::Binary => node.cast().map(Self::Binary),
|
||||||
SyntaxKind::FieldAccess => node.cast().map(Self::FieldAccess),
|
SyntaxKind::FieldAccess => node.cast().map(Self::FieldAccess),
|
||||||
SyntaxKind::FuncCall => node.cast().map(Self::FuncCall),
|
SyntaxKind::FuncCall => node.cast().map(Self::FuncCall),
|
||||||
SyntaxKind::MethodCall => node.cast().map(Self::MethodCall),
|
|
||||||
SyntaxKind::Closure => node.cast().map(Self::Closure),
|
SyntaxKind::Closure => node.cast().map(Self::Closure),
|
||||||
SyntaxKind::LetBinding => node.cast().map(Self::Let),
|
SyntaxKind::LetBinding => node.cast().map(Self::Let),
|
||||||
SyntaxKind::SetRule => node.cast().map(Self::Set),
|
SyntaxKind::SetRule => node.cast().map(Self::Set),
|
||||||
@ -299,7 +296,6 @@ impl AstNode for Expr {
|
|||||||
Self::Binary(v) => v.as_untyped(),
|
Self::Binary(v) => v.as_untyped(),
|
||||||
Self::FieldAccess(v) => v.as_untyped(),
|
Self::FieldAccess(v) => v.as_untyped(),
|
||||||
Self::FuncCall(v) => v.as_untyped(),
|
Self::FuncCall(v) => v.as_untyped(),
|
||||||
Self::MethodCall(v) => v.as_untyped(),
|
|
||||||
Self::Closure(v) => v.as_untyped(),
|
Self::Closure(v) => v.as_untyped(),
|
||||||
Self::Let(v) => v.as_untyped(),
|
Self::Let(v) => v.as_untyped(),
|
||||||
Self::Set(v) => v.as_untyped(),
|
Self::Set(v) => v.as_untyped(),
|
||||||
@ -335,7 +331,6 @@ impl Expr {
|
|||||||
Self::Parenthesized(_) => true,
|
Self::Parenthesized(_) => true,
|
||||||
Self::FieldAccess(_) => true,
|
Self::FieldAccess(_) => true,
|
||||||
Self::FuncCall(_) => true,
|
Self::FuncCall(_) => true,
|
||||||
Self::MethodCall(_) => true,
|
|
||||||
Self::Let(_) => true,
|
Self::Let(_) => true,
|
||||||
Self::Set(_) => true,
|
Self::Set(_) => true,
|
||||||
Self::Show(_) => true,
|
Self::Show(_) => true,
|
||||||
@ -1403,7 +1398,7 @@ impl FieldAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
node! {
|
node! {
|
||||||
/// An invocation of a function: `f(x, y)`.
|
/// An invocation of a function or method: `f(x, y)`.
|
||||||
FuncCall
|
FuncCall
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1419,28 +1414,6 @@ impl FuncCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node! {
|
|
||||||
/// An invocation of a method: `array.push(v)`.
|
|
||||||
MethodCall
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MethodCall {
|
|
||||||
/// The expression to call the method on.
|
|
||||||
pub fn target(&self) -> Expr {
|
|
||||||
self.0.cast_first_match().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The name of the method.
|
|
||||||
pub fn method(&self) -> Ident {
|
|
||||||
self.0.cast_last_match().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The arguments to the method.
|
|
||||||
pub fn args(&self) -> Args {
|
|
||||||
self.0.cast_last_match().unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node! {
|
node! {
|
||||||
/// A function call's argument list: `(12pt, y)`.
|
/// A function call's argument list: `(12pt, y)`.
|
||||||
Args
|
Args
|
||||||
|
@ -210,10 +210,8 @@ pub enum SyntaxKind {
|
|||||||
Binary,
|
Binary,
|
||||||
/// A field access: `properties.age`.
|
/// A field access: `properties.age`.
|
||||||
FieldAccess,
|
FieldAccess,
|
||||||
/// An invocation of a function: `f(x, y)`.
|
/// An invocation of a function or method: `f(x, y)`.
|
||||||
FuncCall,
|
FuncCall,
|
||||||
/// An invocation of a method: `array.push(v)`.
|
|
||||||
MethodCall,
|
|
||||||
/// A function call's argument list: `(12pt, y)`.
|
/// A function call's argument list: `(12pt, y)`.
|
||||||
Args,
|
Args,
|
||||||
/// Spreaded arguments or an argument sink: `..x`.
|
/// Spreaded arguments or an argument sink: `..x`.
|
||||||
@ -416,7 +414,6 @@ impl SyntaxKind {
|
|||||||
Self::Binary => "binary expression",
|
Self::Binary => "binary expression",
|
||||||
Self::FieldAccess => "field access",
|
Self::FieldAccess => "field access",
|
||||||
Self::FuncCall => "function call",
|
Self::FuncCall => "function call",
|
||||||
Self::MethodCall => "method call",
|
|
||||||
Self::Args => "call arguments",
|
Self::Args => "call arguments",
|
||||||
Self::Spread => "spread",
|
Self::Spread => "spread",
|
||||||
Self::Closure => "closure",
|
Self::Closure => "closure",
|
||||||
|
@ -681,11 +681,6 @@ impl<'a> LinkedNode<'a> {
|
|||||||
self.parent.as_deref()
|
self.parent.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the kind of this node's parent.
|
|
||||||
pub fn parent_kind(&self) -> Option<SyntaxKind> {
|
|
||||||
Some(self.parent()?.node.kind())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the first previous non-trivia sibling node.
|
/// Get the first previous non-trivia sibling node.
|
||||||
pub fn prev_sibling(&self) -> Option<Self> {
|
pub fn prev_sibling(&self) -> Option<Self> {
|
||||||
let parent = self.parent()?;
|
let parent = self.parent()?;
|
||||||
@ -713,6 +708,21 @@ impl<'a> LinkedNode<'a> {
|
|||||||
Some(next)
|
Some(next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the kind of this node's parent.
|
||||||
|
pub fn parent_kind(&self) -> Option<SyntaxKind> {
|
||||||
|
Some(self.parent()?.node.kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the kind of this node's first previous non-trivia sibling.
|
||||||
|
pub fn prev_sibling_kind(&self) -> Option<SyntaxKind> {
|
||||||
|
Some(self.prev_sibling()?.node.kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the kind of this node's next non-trivia sibling.
|
||||||
|
pub fn next_sibling_kind(&self) -> Option<SyntaxKind> {
|
||||||
|
Some(self.next_sibling()?.node.kind())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access to leafs.
|
/// Access to leafs.
|
||||||
|
@ -374,12 +374,12 @@ fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn math_args(p: &mut Parser) {
|
fn math_args(p: &mut Parser) {
|
||||||
p.assert(SyntaxKind::Text);
|
|
||||||
|
|
||||||
let m = p.marker();
|
let m = p.marker();
|
||||||
let mut arg = p.marker();
|
p.convert(SyntaxKind::LeftParen);
|
||||||
|
|
||||||
let mut namable = true;
|
let mut namable = true;
|
||||||
let mut named = None;
|
let mut named = None;
|
||||||
|
let mut arg = p.marker();
|
||||||
|
|
||||||
while !p.eof() && !p.at(SyntaxKind::Dollar) {
|
while !p.eof() && !p.at(SyntaxKind::Dollar) {
|
||||||
if namable
|
if namable
|
||||||
@ -418,11 +418,14 @@ fn math_args(p: &mut Parser) {
|
|||||||
maybe_wrap_in_math(p, arg, named);
|
maybe_wrap_in_math(p, arg, named);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.wrap(m, SyntaxKind::Args);
|
if p.at(SyntaxKind::Text) && p.current_text() == ")" {
|
||||||
if !p.eat_if(SyntaxKind::Text) {
|
p.convert(SyntaxKind::RightParen);
|
||||||
|
} else {
|
||||||
p.expected("closing paren");
|
p.expected("closing paren");
|
||||||
p.balanced = false;
|
p.balanced = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.wrap(m, SyntaxKind::Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_wrap_in_math(p: &mut Parser, arg: Marker, named: Option<Marker>) {
|
fn maybe_wrap_in_math(p: &mut Parser, arg: Marker, named: Option<Marker>) {
|
||||||
@ -512,14 +515,7 @@ fn code_expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) {
|
|||||||
|
|
||||||
if p.eat_if(SyntaxKind::Dot) {
|
if p.eat_if(SyntaxKind::Dot) {
|
||||||
p.expect(SyntaxKind::Ident);
|
p.expect(SyntaxKind::Ident);
|
||||||
if p.directly_at(SyntaxKind::LeftParen)
|
p.wrap(m, SyntaxKind::FieldAccess);
|
||||||
|| p.directly_at(SyntaxKind::LeftBracket)
|
|
||||||
{
|
|
||||||
args(p);
|
|
||||||
p.wrap(m, SyntaxKind::MethodCall);
|
|
||||||
} else {
|
|
||||||
p.wrap(m, SyntaxKind::FieldAccess)
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
tests/ref/compiler/highlight.png
Normal file
BIN
tests/ref/compiler/highlight.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
63
tests/typ/compiler/highlight.typ
Normal file
63
tests/typ/compiler/highlight.typ
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#set page(width: auto)
|
||||||
|
|
||||||
|
```typ
|
||||||
|
#set hello()
|
||||||
|
#set hello()
|
||||||
|
#set hello.world()
|
||||||
|
#set hello.my.world()
|
||||||
|
|
||||||
|
#show heading: func
|
||||||
|
#show module.func: func
|
||||||
|
#show module.func: it => {}
|
||||||
|
#foo(ident: ident)
|
||||||
|
|
||||||
|
#hello
|
||||||
|
#hello()
|
||||||
|
#hello.world
|
||||||
|
#hello.world()
|
||||||
|
#hello().world()
|
||||||
|
#hello.my.world
|
||||||
|
#hello.my.world()
|
||||||
|
#hello.my().world
|
||||||
|
#hello.my().world()
|
||||||
|
|
||||||
|
$ hello $
|
||||||
|
$ hello() $
|
||||||
|
$ hello.world $
|
||||||
|
$ hello.world() $
|
||||||
|
$ hello().world() $
|
||||||
|
$ hello.my.world $
|
||||||
|
$ hello.my.world() $
|
||||||
|
$ hello.my().world $
|
||||||
|
$ hello.my().world() $
|
||||||
|
|
||||||
|
$ emph(hello) $
|
||||||
|
$ emph(hello()) $
|
||||||
|
$ emph(hello.world) $
|
||||||
|
$ emph(hello.world()) $
|
||||||
|
$ emph(hello().world()) $
|
||||||
|
$ emph(hello.my.world) $
|
||||||
|
$ emph(hello.my.world()) $
|
||||||
|
$ emph(hello.my().world) $
|
||||||
|
$ emph(hello.my().world()) $
|
||||||
|
|
||||||
|
$ #hello $
|
||||||
|
$ #hello() $
|
||||||
|
$ #hello.world $
|
||||||
|
$ #hello.world() $
|
||||||
|
$ #hello().world() $
|
||||||
|
$ #hello.my.world $
|
||||||
|
$ #hello.my.world() $
|
||||||
|
$ #hello.my().world $
|
||||||
|
$ #hello.my().world() $
|
||||||
|
|
||||||
|
#{ hello }
|
||||||
|
#{ hello() }
|
||||||
|
#{ hello.world }
|
||||||
|
#{ hello.world() }
|
||||||
|
#{ hello().world() }
|
||||||
|
#{ hello.my.world }
|
||||||
|
#{ hello.my.world() }
|
||||||
|
#{ hello.my().world }
|
||||||
|
#{ hello.my().world() }
|
||||||
|
```
|
@ -23,5 +23,5 @@ $ f(x, y) := cases(
|
|||||||
#set math.vec(delim: "%")
|
#set math.vec(delim: "%")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 9-12 missing argument: lower index
|
// Error: 8-13 missing argument: lower index
|
||||||
$ binom(x^2) $
|
$ binom(x^2) $
|
||||||
|
Loading…
x
Reference in New Issue
Block a user