mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
refactor SyntaxKind::Pattern (#831)
This commit is contained in:
parent
d2784f6f90
commit
428c55b6ee
@ -1179,16 +1179,16 @@ impl Eval for ast::Closure {
|
|||||||
impl ast::Pattern {
|
impl ast::Pattern {
|
||||||
// Destruct the given value into the pattern.
|
// Destruct the given value into the pattern.
|
||||||
pub fn define(&self, vm: &mut Vm, value: Value) -> SourceResult<Value> {
|
pub fn define(&self, vm: &mut Vm, value: Value) -> SourceResult<Value> {
|
||||||
match self.kind() {
|
match self {
|
||||||
ast::PatternKind::Ident(ident) => {
|
ast::Pattern::Ident(ident) => {
|
||||||
vm.define(ident, value);
|
vm.define(ident.clone(), value);
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
}
|
}
|
||||||
ast::PatternKind::Destructure(pattern) => {
|
ast::Pattern::Destructuring(destruct) => {
|
||||||
match value {
|
match value {
|
||||||
Value::Array(value) => {
|
Value::Array(value) => {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for p in &pattern {
|
for p in destruct.bindings() {
|
||||||
match p {
|
match p {
|
||||||
ast::DestructuringKind::Ident(ident) => {
|
ast::DestructuringKind::Ident(ident) => {
|
||||||
let Ok(v) = value.at(i) else {
|
let Ok(v) = value.at(i) else {
|
||||||
@ -1198,7 +1198,7 @@ impl ast::Pattern {
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
ast::DestructuringKind::Sink(ident) => {
|
ast::DestructuringKind::Sink(ident) => {
|
||||||
(1 + value.len() as usize).checked_sub(pattern.len()).and_then(|sink_size| {
|
(1 + value.len() as usize).checked_sub(destruct.bindings().count()).and_then(|sink_size| {
|
||||||
let Ok(sink) = value.slice(i, Some(i + sink_size as i64)) else {
|
let Ok(sink) = value.slice(i, Some(i + sink_size as i64)) else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
@ -1224,10 +1224,10 @@ impl ast::Pattern {
|
|||||||
Value::Dict(value) => {
|
Value::Dict(value) => {
|
||||||
let mut sink = None;
|
let mut sink = None;
|
||||||
let mut used = HashSet::new();
|
let mut used = HashSet::new();
|
||||||
for p in &pattern {
|
for p in destruct.bindings() {
|
||||||
match p {
|
match p {
|
||||||
ast::DestructuringKind::Ident(ident) => {
|
ast::DestructuringKind::Ident(ident) => {
|
||||||
let Ok(v) = value.at(ident) else {
|
let Ok(v) = value.at(&ident) else {
|
||||||
bail!(ident.span(), "destructuring key not found in dictionary");
|
bail!(ident.span(), "destructuring key not found in dictionary");
|
||||||
};
|
};
|
||||||
vm.define(ident.clone(), v.clone());
|
vm.define(ident.clone(), v.clone());
|
||||||
@ -1237,7 +1237,7 @@ impl ast::Pattern {
|
|||||||
sink = ident.clone()
|
sink = ident.clone()
|
||||||
}
|
}
|
||||||
ast::DestructuringKind::Named(key, ident) => {
|
ast::DestructuringKind::Named(key, ident) => {
|
||||||
let Ok(v) = value.at(key) else {
|
let Ok(v) = value.at(&key) else {
|
||||||
bail!(ident.span(), "destructuring key not found in dictionary");
|
bail!(ident.span(), "destructuring key not found in dictionary");
|
||||||
};
|
};
|
||||||
vm.define(ident.clone(), v.clone());
|
vm.define(ident.clone(), v.clone());
|
||||||
@ -1451,8 +1451,8 @@ impl Eval for ast::ForLoop {
|
|||||||
let iter = self.iter().eval(vm)?;
|
let iter = self.iter().eval(vm)?;
|
||||||
let pattern = self.pattern();
|
let pattern = self.pattern();
|
||||||
|
|
||||||
match (pattern.kind(), iter.clone()) {
|
match (&pattern, iter.clone()) {
|
||||||
(ast::PatternKind::Ident(_), Value::Str(string)) => {
|
(ast::Pattern::Ident(_), Value::Str(string)) => {
|
||||||
// Iterate over graphemes of string.
|
// Iterate over graphemes of string.
|
||||||
iter!(for pattern in string.as_str().graphemes(true));
|
iter!(for pattern in string.as_str().graphemes(true));
|
||||||
}
|
}
|
||||||
@ -1464,7 +1464,7 @@ impl Eval for ast::ForLoop {
|
|||||||
// Iterate over values of array.
|
// Iterate over values of array.
|
||||||
iter!(for pattern in array);
|
iter!(for pattern in array);
|
||||||
}
|
}
|
||||||
(ast::PatternKind::Ident(_), _) => {
|
(ast::Pattern::Ident(_), _) => {
|
||||||
bail!(self.iter().span(), "cannot loop over {}", iter.type_name());
|
bail!(self.iter().span(), "cannot loop over {}", iter.type_name());
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
|
@ -239,14 +239,13 @@ pub fn highlight(node: &LinkedNode) -> Option<Tag> {
|
|||||||
SyntaxKind::Conditional => None,
|
SyntaxKind::Conditional => None,
|
||||||
SyntaxKind::WhileLoop => None,
|
SyntaxKind::WhileLoop => None,
|
||||||
SyntaxKind::ForLoop => None,
|
SyntaxKind::ForLoop => None,
|
||||||
SyntaxKind::ForPattern => None,
|
|
||||||
SyntaxKind::ModuleImport => None,
|
SyntaxKind::ModuleImport => None,
|
||||||
SyntaxKind::ImportItems => None,
|
SyntaxKind::ImportItems => None,
|
||||||
SyntaxKind::ModuleInclude => None,
|
SyntaxKind::ModuleInclude => None,
|
||||||
SyntaxKind::LoopBreak => None,
|
SyntaxKind::LoopBreak => None,
|
||||||
SyntaxKind::LoopContinue => None,
|
SyntaxKind::LoopContinue => None,
|
||||||
SyntaxKind::FuncReturn => None,
|
SyntaxKind::FuncReturn => None,
|
||||||
SyntaxKind::Pattern => None,
|
SyntaxKind::Destructuring => None,
|
||||||
|
|
||||||
SyntaxKind::LineComment => Some(Tag::Comment),
|
SyntaxKind::LineComment => Some(Tag::Comment),
|
||||||
SyntaxKind::BlockComment => Some(Tag::Comment),
|
SyntaxKind::BlockComment => Some(Tag::Comment),
|
||||||
|
@ -1533,10 +1533,7 @@ impl Closure {
|
|||||||
///
|
///
|
||||||
/// This only exists if you use the function syntax sugar: `let f(x) = y`.
|
/// This only exists if you use the function syntax sugar: `let f(x) = y`.
|
||||||
pub fn name(&self) -> Option<Ident> {
|
pub fn name(&self) -> Option<Ident> {
|
||||||
match self.0.cast_first_match::<Pattern>()?.kind() {
|
self.0.children().next()?.cast()
|
||||||
PatternKind::Ident(ident) => Some(ident),
|
|
||||||
_ => Option::None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The parameter bindings.
|
/// The parameter bindings.
|
||||||
@ -1594,16 +1591,7 @@ impl AstNode for Param {
|
|||||||
|
|
||||||
node! {
|
node! {
|
||||||
/// A destructuring pattern: `x` or `(x, _, ..y)`.
|
/// A destructuring pattern: `x` or `(x, _, ..y)`.
|
||||||
Pattern
|
Destructuring
|
||||||
}
|
|
||||||
|
|
||||||
/// The kind of a pattern.
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub enum PatternKind {
|
|
||||||
/// A single identifier: `x`.
|
|
||||||
Ident(Ident),
|
|
||||||
/// A destructuring pattern: `(x, _, ..y)`.
|
|
||||||
Destructure(Vec<DestructuringKind>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of an element in a destructuring pattern.
|
/// The kind of an element in a destructuring pattern.
|
||||||
@ -1617,57 +1605,74 @@ pub enum DestructuringKind {
|
|||||||
Named(Ident, Ident),
|
Named(Ident, Ident),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern {
|
impl Destructuring {
|
||||||
/// The kind of the pattern.
|
/// The bindings of the destructuring.
|
||||||
pub fn kind(&self) -> PatternKind {
|
pub fn bindings(&self) -> impl Iterator<Item = DestructuringKind> + '_ {
|
||||||
if self
|
self.0.children().filter_map(|child| match child.kind() {
|
||||||
.0
|
SyntaxKind::Ident => {
|
||||||
.children()
|
Some(DestructuringKind::Ident(child.cast().unwrap_or_default()))
|
||||||
.map(SyntaxNode::kind)
|
|
||||||
.skip_while(|&kind| kind == SyntaxKind::LeftParen)
|
|
||||||
.take_while(|&kind| kind != SyntaxKind::RightParen)
|
|
||||||
.eq([SyntaxKind::Ident])
|
|
||||||
{
|
|
||||||
return PatternKind::Ident(self.0.cast_first_match().unwrap_or_default());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut bindings = Vec::new();
|
|
||||||
for child in self.0.children() {
|
|
||||||
match child.kind() {
|
|
||||||
SyntaxKind::Ident => {
|
|
||||||
bindings
|
|
||||||
.push(DestructuringKind::Ident(child.cast().unwrap_or_default()));
|
|
||||||
}
|
|
||||||
SyntaxKind::Spread => {
|
|
||||||
bindings.push(DestructuringKind::Sink(child.cast_first_match()));
|
|
||||||
}
|
|
||||||
SyntaxKind::Named => {
|
|
||||||
let mut filtered = child.children().filter_map(SyntaxNode::cast);
|
|
||||||
let key = filtered.next().unwrap_or_default();
|
|
||||||
let ident = filtered.next().unwrap_or_default();
|
|
||||||
bindings.push(DestructuringKind::Named(key, ident));
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
SyntaxKind::Spread => Some(DestructuringKind::Sink(child.cast_first_match())),
|
||||||
|
SyntaxKind::Named => {
|
||||||
PatternKind::Destructure(bindings)
|
let mut filtered = child.children().filter_map(SyntaxNode::cast);
|
||||||
|
let key = filtered.next().unwrap_or_default();
|
||||||
|
let ident = filtered.next().unwrap_or_default();
|
||||||
|
Some(DestructuringKind::Named(key, ident))
|
||||||
|
}
|
||||||
|
_ => Option::None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of all identifiers in the pattern.
|
// Returns a list of all identifiers in the pattern.
|
||||||
pub fn idents(&self) -> Vec<Ident> {
|
pub fn idents(&self) -> impl Iterator<Item = Ident> + '_ {
|
||||||
match self.kind() {
|
self.bindings().into_iter().filter_map(|binding| match binding {
|
||||||
PatternKind::Ident(ident) => vec![ident],
|
DestructuringKind::Ident(ident) => Some(ident),
|
||||||
PatternKind::Destructure(bindings) => bindings
|
DestructuringKind::Sink(ident) => ident,
|
||||||
.into_iter()
|
DestructuringKind::Named(_, ident) => Some(ident),
|
||||||
.filter_map(|binding| match binding {
|
})
|
||||||
DestructuringKind::Ident(ident) => Some(ident),
|
}
|
||||||
DestructuringKind::Sink(ident) => ident,
|
}
|
||||||
DestructuringKind::Named(_, ident) => Some(ident),
|
|
||||||
})
|
/// The kind of a pattern.
|
||||||
.collect(),
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub enum Pattern {
|
||||||
|
/// A single identifier: `x`.
|
||||||
|
Ident(Ident),
|
||||||
|
/// A destructuring pattern: `(x, _, ..y)`.
|
||||||
|
Destructuring(Destructuring),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AstNode for Pattern {
|
||||||
|
fn from_untyped(node: &SyntaxNode) -> Option<Self> {
|
||||||
|
match node.kind() {
|
||||||
|
SyntaxKind::Ident => node.cast().map(Self::Ident),
|
||||||
|
SyntaxKind::Destructuring => node.cast().map(Self::Destructuring),
|
||||||
|
_ => Option::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_untyped(&self) -> &SyntaxNode {
|
||||||
|
match self {
|
||||||
|
Self::Ident(v) => v.as_untyped(),
|
||||||
|
Self::Destructuring(v) => v.as_untyped(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pattern {
|
||||||
|
// Returns a list of all identifiers in the pattern.
|
||||||
|
pub fn idents(&self) -> Vec<Ident> {
|
||||||
|
match self {
|
||||||
|
Pattern::Ident(ident) => vec![ident.clone()],
|
||||||
|
Pattern::Destructuring(destruct) => destruct.idents().collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Pattern {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Ident(Ident::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node! {
|
node! {
|
||||||
@ -1675,6 +1680,7 @@ node! {
|
|||||||
LetBinding
|
LetBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum LetBindingKind {
|
pub enum LetBindingKind {
|
||||||
/// A normal binding: `let x = 1`.
|
/// A normal binding: `let x = 1`.
|
||||||
Normal(Pattern),
|
Normal(Pattern),
|
||||||
@ -1713,7 +1719,12 @@ impl LetBinding {
|
|||||||
/// The expression the binding is initialized with.
|
/// The expression the binding is initialized with.
|
||||||
pub fn init(&self) -> Option<Expr> {
|
pub fn init(&self) -> Option<Expr> {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
LetBindingKind::Normal(_) => self.0.cast_last_match(),
|
LetBindingKind::Normal(Pattern::Ident(_)) => {
|
||||||
|
self.0.children().filter_map(SyntaxNode::cast).nth(1)
|
||||||
|
}
|
||||||
|
LetBindingKind::Normal(Pattern::Destructuring(_)) => {
|
||||||
|
self.0.cast_first_match()
|
||||||
|
}
|
||||||
LetBindingKind::Closure(_) => self.0.cast_first_match(),
|
LetBindingKind::Closure(_) => self.0.cast_first_match(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1821,7 +1832,11 @@ impl ForLoop {
|
|||||||
|
|
||||||
/// The expression to iterate over.
|
/// The expression to iterate over.
|
||||||
pub fn iter(&self) -> Expr {
|
pub fn iter(&self) -> Expr {
|
||||||
self.0.cast_first_match().unwrap_or_default()
|
self.0
|
||||||
|
.children()
|
||||||
|
.skip_while(|&c| c.kind() != SyntaxKind::In)
|
||||||
|
.find_map(SyntaxNode::cast)
|
||||||
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The expression to evaluate for each iteration.
|
/// The expression to evaluate for each iteration.
|
||||||
|
@ -230,8 +230,6 @@ pub enum SyntaxKind {
|
|||||||
WhileLoop,
|
WhileLoop,
|
||||||
/// A for loop: `for x in y { z }`.
|
/// A for loop: `for x in y { z }`.
|
||||||
ForLoop,
|
ForLoop,
|
||||||
/// A for loop's destructuring pattern: `x` or `x, y`.
|
|
||||||
ForPattern,
|
|
||||||
/// A module import: `import a, b, c from "utils.typ"`.
|
/// A module import: `import a, b, c from "utils.typ"`.
|
||||||
ModuleImport,
|
ModuleImport,
|
||||||
/// Items to import from a module: `a, b, c`.
|
/// Items to import from a module: `a, b, c`.
|
||||||
@ -244,8 +242,8 @@ pub enum SyntaxKind {
|
|||||||
LoopContinue,
|
LoopContinue,
|
||||||
/// A return from a function: `return`, `return x + 1`.
|
/// A return from a function: `return`, `return x + 1`.
|
||||||
FuncReturn,
|
FuncReturn,
|
||||||
/// A destructuring pattern: `x`, `(x, _, ..y)`.
|
/// A destructuring pattern: `(x, _, ..y)`.
|
||||||
Pattern,
|
Destructuring,
|
||||||
|
|
||||||
/// A line comment: `// ...`.
|
/// A line comment: `// ...`.
|
||||||
LineComment,
|
LineComment,
|
||||||
@ -425,14 +423,13 @@ impl SyntaxKind {
|
|||||||
Self::Conditional => "`if` expression",
|
Self::Conditional => "`if` expression",
|
||||||
Self::WhileLoop => "while-loop expression",
|
Self::WhileLoop => "while-loop expression",
|
||||||
Self::ForLoop => "for-loop expression",
|
Self::ForLoop => "for-loop expression",
|
||||||
Self::ForPattern => "for-loop destructuring pattern",
|
|
||||||
Self::ModuleImport => "`import` expression",
|
Self::ModuleImport => "`import` expression",
|
||||||
Self::ImportItems => "import items",
|
Self::ImportItems => "import items",
|
||||||
Self::ModuleInclude => "`include` expression",
|
Self::ModuleInclude => "`include` expression",
|
||||||
Self::LoopBreak => "`break` expression",
|
Self::LoopBreak => "`break` expression",
|
||||||
Self::LoopContinue => "`continue` expression",
|
Self::LoopContinue => "`continue` expression",
|
||||||
Self::FuncReturn => "`return` expression",
|
Self::FuncReturn => "`return` expression",
|
||||||
Self::Pattern => "destructuring pattern",
|
Self::Destructuring => "destructuring pattern",
|
||||||
Self::LineComment => "line comment",
|
Self::LineComment => "line comment",
|
||||||
Self::BlockComment => "block comment",
|
Self::BlockComment => "block comment",
|
||||||
Self::Error => "syntax error",
|
Self::Error => "syntax error",
|
||||||
|
@ -839,7 +839,7 @@ fn args(p: &mut Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum PatternKind {
|
enum PatternKind {
|
||||||
Normal,
|
Ident,
|
||||||
Destructuring,
|
Destructuring,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,18 +849,16 @@ fn pattern(p: &mut Parser) -> PatternKind {
|
|||||||
if p.at(SyntaxKind::LeftParen) {
|
if p.at(SyntaxKind::LeftParen) {
|
||||||
let kind = collection(p, false);
|
let kind = collection(p, false);
|
||||||
validate_destruct_pattern(p, m);
|
validate_destruct_pattern(p, m);
|
||||||
p.wrap(m, SyntaxKind::Pattern);
|
|
||||||
|
|
||||||
if kind == SyntaxKind::Parenthesized {
|
if kind == SyntaxKind::Parenthesized {
|
||||||
PatternKind::Normal
|
PatternKind::Ident
|
||||||
} else {
|
} else {
|
||||||
|
p.wrap(m, SyntaxKind::Destructuring);
|
||||||
PatternKind::Destructuring
|
PatternKind::Destructuring
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if p.expect(SyntaxKind::Ident) {
|
p.expect(SyntaxKind::Ident);
|
||||||
p.wrap(m, SyntaxKind::Pattern);
|
PatternKind::Ident
|
||||||
}
|
|
||||||
PatternKind::Normal
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +870,7 @@ fn let_binding(p: &mut Parser) {
|
|||||||
let mut closure = false;
|
let mut closure = false;
|
||||||
let mut destructuring = false;
|
let mut destructuring = false;
|
||||||
match pattern(p) {
|
match pattern(p) {
|
||||||
PatternKind::Normal => {
|
PatternKind::Ident => {
|
||||||
closure = p.directly_at(SyntaxKind::LeftParen);
|
closure = p.directly_at(SyntaxKind::LeftParen);
|
||||||
if closure {
|
if closure {
|
||||||
let m3 = p.marker();
|
let m3 = p.marker();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user