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.
|
||||
pub fn analyze(world: &(dyn World + 'static), node: &LinkedNode) -> Vec<Value> {
|
||||
match node.cast::<ast::Expr>() {
|
||||
Some(
|
||||
ast::Expr::Ident(_) | ast::Expr::MathIdent(_) | ast::Expr::MethodCall(_),
|
||||
) => {
|
||||
Some(ast::Expr::Ident(_) | ast::Expr::MathIdent(_) | ast::Expr::FuncCall(_)) => {
|
||||
if let Some(parent) = node.parent() {
|
||||
if parent.kind() == SyntaxKind::FieldAccess && node.index() > 0 {
|
||||
return analyze(world, parent);
|
||||
|
@ -4,7 +4,7 @@ use if_chain::if_chain;
|
||||
|
||||
use super::{analyze, plain_docs_sentence, summarize_font_family};
|
||||
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::World;
|
||||
|
||||
@ -936,9 +936,7 @@ impl<'a> CompletionContext<'a> {
|
||||
|
||||
if let Some(parent) = node.parent() {
|
||||
if let Some(v) = parent.cast::<ast::ForLoop>() {
|
||||
if node.prev_sibling().as_deref().map(SyntaxNode::kind)
|
||||
!= Some(SyntaxKind::In)
|
||||
{
|
||||
if node.prev_sibling_kind() != Some(SyntaxKind::In) {
|
||||
let pattern = v.pattern();
|
||||
if let Some(key) = pattern.key() {
|
||||
defined.insert(key.take());
|
||||
|
@ -85,8 +85,7 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
||||
match node.kind() {
|
||||
SyntaxKind::Markup
|
||||
if node.parent_kind() == Some(SyntaxKind::TermItem)
|
||||
&& node.next_sibling().as_ref().map(|v| v.kind())
|
||||
== Some(SyntaxKind::Colon) =>
|
||||
&& node.next_sibling_kind() == Some(SyntaxKind::Colon) =>
|
||||
{
|
||||
Some(Category::ListTerm)
|
||||
}
|
||||
@ -116,17 +115,12 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
||||
|
||||
SyntaxKind::Math => None,
|
||||
SyntaxKind::MathIdent => highlight_ident(node),
|
||||
SyntaxKind::MathAlignPoint => Some(Category::MathOperator),
|
||||
SyntaxKind::MathDelimited => None,
|
||||
SyntaxKind::MathAttach => 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::RightBrace => Some(Category::Punctuation),
|
||||
SyntaxKind::LeftBracket => Some(Category::Punctuation),
|
||||
@ -206,18 +200,8 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
||||
SyntaxKind::Keyed => None,
|
||||
SyntaxKind::Unary => None,
|
||||
SyntaxKind::Binary => None,
|
||||
SyntaxKind::FieldAccess => match node.parent_kind() {
|
||||
Some(
|
||||
SyntaxKind::Markup
|
||||
| SyntaxKind::Math
|
||||
| SyntaxKind::MathFrac
|
||||
| SyntaxKind::MathAttach,
|
||||
) => Some(Category::Interpolated),
|
||||
Some(SyntaxKind::FieldAccess) => node.parent().and_then(highlight),
|
||||
_ => None,
|
||||
},
|
||||
SyntaxKind::FieldAccess => None,
|
||||
SyntaxKind::FuncCall => None,
|
||||
SyntaxKind::MethodCall => None,
|
||||
SyntaxKind::Args => None,
|
||||
SyntaxKind::Spread => None,
|
||||
SyntaxKind::Closure => None,
|
||||
@ -245,49 +229,60 @@ pub fn highlight(node: &LinkedNode) -> Option<Category> {
|
||||
|
||||
/// Highlight an identifier based on context.
|
||||
fn highlight_ident(node: &LinkedNode) -> Option<Category> {
|
||||
match node.parent_kind() {
|
||||
Some(SyntaxKind::FuncCall) => Some(Category::Function),
|
||||
Some(SyntaxKind::FieldAccess)
|
||||
if node.parent().and_then(|p| p.parent_kind())
|
||||
== 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 directly before an argument list?
|
||||
let next_leaf_kind = node.next_leaf().map(|leaf| leaf.kind());
|
||||
if matches!(next_leaf_kind, Some(SyntaxKind::LeftParen | SyntaxKind::LeftBracket)) {
|
||||
return Some(Category::Function);
|
||||
}
|
||||
|
||||
// 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)]
|
||||
|
@ -364,7 +364,6 @@ impl Eval for ast::Expr {
|
||||
Self::Parenthesized(v) => v.eval(vm),
|
||||
Self::FieldAccess(v) => v.eval(vm),
|
||||
Self::FuncCall(v) => v.eval(vm),
|
||||
Self::MethodCall(v) => v.eval(vm),
|
||||
Self::Closure(v) => v.eval(vm),
|
||||
Self::Unary(v) => v.eval(vm),
|
||||
Self::Binary(v) => v.eval(vm),
|
||||
@ -918,12 +917,51 @@ impl Eval for ast::FuncCall {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let callee_expr = self.callee();
|
||||
let callee_span = callee_expr.span();
|
||||
let callee = callee_expr.eval(vm)?;
|
||||
let mut args = self.args().eval(vm)?;
|
||||
let span = self.span();
|
||||
let callee = self.callee();
|
||||
let in_math = in_math(&callee);
|
||||
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 {
|
||||
let c = sym.get();
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
let mut body = (vm.items.text)('('.into());
|
||||
for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
@ -944,8 +981,14 @@ impl Eval for ast::FuncCall {
|
||||
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)?;
|
||||
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 {
|
||||
type Output = Args;
|
||||
|
||||
@ -1223,8 +1213,12 @@ impl Eval for ast::WhileLoop {
|
||||
fn is_invariant(expr: &SyntaxNode) -> bool {
|
||||
match expr.cast() {
|
||||
Some(ast::Expr::Ident(_)) => false,
|
||||
Some(ast::Expr::MethodCall(call)) => {
|
||||
is_invariant(call.target().as_untyped())
|
||||
Some(ast::Expr::MathIdent(_)) => false,
|
||||
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())
|
||||
}
|
||||
_ => expr.children().all(is_invariant),
|
||||
@ -1434,7 +1428,7 @@ impl Access for ast::Expr {
|
||||
Self::Ident(v) => v.access(vm),
|
||||
Self::Parenthesized(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)?;
|
||||
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> {
|
||||
let span = self.span();
|
||||
let method = self.method().take();
|
||||
let world = vm.world();
|
||||
|
||||
if !methods::is_accessor(&method) {
|
||||
let _ = self.eval(vm)?;
|
||||
bail!(span, "cannot mutate a temporary value");
|
||||
if let ast::Expr::FieldAccess(access) = self.callee() {
|
||||
let method = access.field().take();
|
||||
if methods::is_accessor(&method) {
|
||||
let span = self.span();
|
||||
let world = vm.world();
|
||||
let args = self.args().eval(vm)?;
|
||||
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 value = self.target().access(vm)?;
|
||||
let result = methods::call_access(value, &method, args, span);
|
||||
|
||||
let point = || Tracepoint::Call(Some(method.clone()));
|
||||
result.trace(world, point, span)
|
||||
let _ = self.eval(vm)?;
|
||||
bail!(self.span(), "cannot mutate a temporary value");
|
||||
}
|
||||
}
|
||||
|
@ -157,10 +157,8 @@ pub enum Expr {
|
||||
Binary(Binary),
|
||||
/// 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(MethodCall),
|
||||
/// A closure: `(x, y) => z`.
|
||||
Closure(Closure),
|
||||
/// A let binding: `let x = 1`.
|
||||
@ -239,7 +237,6 @@ impl AstNode for Expr {
|
||||
SyntaxKind::Binary => node.cast().map(Self::Binary),
|
||||
SyntaxKind::FieldAccess => node.cast().map(Self::FieldAccess),
|
||||
SyntaxKind::FuncCall => node.cast().map(Self::FuncCall),
|
||||
SyntaxKind::MethodCall => node.cast().map(Self::MethodCall),
|
||||
SyntaxKind::Closure => node.cast().map(Self::Closure),
|
||||
SyntaxKind::LetBinding => node.cast().map(Self::Let),
|
||||
SyntaxKind::SetRule => node.cast().map(Self::Set),
|
||||
@ -299,7 +296,6 @@ impl AstNode for Expr {
|
||||
Self::Binary(v) => v.as_untyped(),
|
||||
Self::FieldAccess(v) => v.as_untyped(),
|
||||
Self::FuncCall(v) => v.as_untyped(),
|
||||
Self::MethodCall(v) => v.as_untyped(),
|
||||
Self::Closure(v) => v.as_untyped(),
|
||||
Self::Let(v) => v.as_untyped(),
|
||||
Self::Set(v) => v.as_untyped(),
|
||||
@ -335,7 +331,6 @@ impl Expr {
|
||||
Self::Parenthesized(_) => true,
|
||||
Self::FieldAccess(_) => true,
|
||||
Self::FuncCall(_) => true,
|
||||
Self::MethodCall(_) => true,
|
||||
Self::Let(_) => true,
|
||||
Self::Set(_) => true,
|
||||
Self::Show(_) => true,
|
||||
@ -1403,7 +1398,7 @@ impl FieldAccess {
|
||||
}
|
||||
|
||||
node! {
|
||||
/// An invocation of a function: `f(x, y)`.
|
||||
/// An invocation of a function or method: `f(x, y)`.
|
||||
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! {
|
||||
/// A function call's argument list: `(12pt, y)`.
|
||||
Args
|
||||
|
@ -210,10 +210,8 @@ pub enum SyntaxKind {
|
||||
Binary,
|
||||
/// A field access: `properties.age`.
|
||||
FieldAccess,
|
||||
/// An invocation of a function: `f(x, y)`.
|
||||
/// An invocation of a function or method: `f(x, y)`.
|
||||
FuncCall,
|
||||
/// An invocation of a method: `array.push(v)`.
|
||||
MethodCall,
|
||||
/// A function call's argument list: `(12pt, y)`.
|
||||
Args,
|
||||
/// Spreaded arguments or an argument sink: `..x`.
|
||||
@ -416,7 +414,6 @@ impl SyntaxKind {
|
||||
Self::Binary => "binary expression",
|
||||
Self::FieldAccess => "field access",
|
||||
Self::FuncCall => "function call",
|
||||
Self::MethodCall => "method call",
|
||||
Self::Args => "call arguments",
|
||||
Self::Spread => "spread",
|
||||
Self::Closure => "closure",
|
||||
|
@ -681,11 +681,6 @@ impl<'a> LinkedNode<'a> {
|
||||
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.
|
||||
pub fn prev_sibling(&self) -> Option<Self> {
|
||||
let parent = self.parent()?;
|
||||
@ -713,6 +708,21 @@ impl<'a> LinkedNode<'a> {
|
||||
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.
|
||||
|
@ -374,12 +374,12 @@ fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usiz
|
||||
}
|
||||
|
||||
fn math_args(p: &mut Parser) {
|
||||
p.assert(SyntaxKind::Text);
|
||||
|
||||
let m = p.marker();
|
||||
let mut arg = p.marker();
|
||||
p.convert(SyntaxKind::LeftParen);
|
||||
|
||||
let mut namable = true;
|
||||
let mut named = None;
|
||||
let mut arg = p.marker();
|
||||
|
||||
while !p.eof() && !p.at(SyntaxKind::Dollar) {
|
||||
if namable
|
||||
@ -418,11 +418,14 @@ fn math_args(p: &mut Parser) {
|
||||
maybe_wrap_in_math(p, arg, named);
|
||||
}
|
||||
|
||||
p.wrap(m, SyntaxKind::Args);
|
||||
if !p.eat_if(SyntaxKind::Text) {
|
||||
if p.at(SyntaxKind::Text) && p.current_text() == ")" {
|
||||
p.convert(SyntaxKind::RightParen);
|
||||
} else {
|
||||
p.expected("closing paren");
|
||||
p.balanced = false;
|
||||
}
|
||||
|
||||
p.wrap(m, SyntaxKind::Args);
|
||||
}
|
||||
|
||||
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) {
|
||||
p.expect(SyntaxKind::Ident);
|
||||
if p.directly_at(SyntaxKind::LeftParen)
|
||||
|| p.directly_at(SyntaxKind::LeftBracket)
|
||||
{
|
||||
args(p);
|
||||
p.wrap(m, SyntaxKind::MethodCall);
|
||||
} else {
|
||||
p.wrap(m, SyntaxKind::FieldAccess)
|
||||
}
|
||||
p.wrap(m, SyntaxKind::FieldAccess);
|
||||
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: "%")
|
||||
|
||||
---
|
||||
// Error: 9-12 missing argument: lower index
|
||||
// Error: 8-13 missing argument: lower index
|
||||
$ binom(x^2) $
|
||||
|
Loading…
x
Reference in New Issue
Block a user