Skip to main content

php_ast/ast/
stmts.rs

1#[cfg(feature = "serde")]
2use serde::Serialize;
3
4use crate::Span;
5
6use super::{
7    ArenaVec, Attribute, ClassDecl, Comment, EnumDecl, Expr, FunctionDecl, Ident, InterfaceDecl,
8    Name, TraitDecl,
9};
10
11#[cfg(feature = "serde")]
12fn is_false(b: &bool) -> bool {
13    !b
14}
15
16/// A statement node.
17#[derive(Debug)]
18#[cfg_attr(feature = "serde", derive(Serialize))]
19pub struct Stmt<'arena, 'src> {
20    /// Statement kind.
21    pub kind: StmtKind<'arena, 'src>,
22    /// Source range of this node.
23    pub span: Span,
24    /// The immediately preceding `/** */` doc-block, if any.
25    ///
26    /// Only `/** */` (doc-block) comments are attached here; `//`, `#`, and
27    /// `/* */` comments remain in `ParseResult::comments`.  When present,
28    /// this comment is **removed** from `ParseResult::comments` — the two
29    /// collections are disjoint.  A doc-block that has no following statement
30    /// before the enclosing `}` or EOF is not attached and stays in
31    /// `ParseResult::comments`.
32    ///
33    /// For declaration statements (`function`, `class`, `interface`, …) the
34    /// doc-block is attached to the *inner* declaration node (e.g.
35    /// [`FunctionDecl::doc_comment`]) and this field will always be `None`.
36    ///
37    /// Stored as a pointer into the arena rather than inline so that the
38    /// `None` case (the vast majority of statements) costs only 8 bytes
39    /// instead of the 32 bytes an inline `Option<Comment>` would require.
40    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
41    pub doc_comment: Option<&'arena Comment<'src>>,
42}
43
44impl<'arena, 'src> Stmt<'arena, 'src> {
45    /// The leading `/** */` doc-block for this statement, regardless of where
46    /// it is stored.
47    ///
48    /// For non-declaration statements (`foreach`, `if`, assignments, …) the
49    /// comment lives on [`Stmt::doc_comment`] and is returned directly.
50    ///
51    /// For declaration statements the comment is stored on the inner
52    /// declaration node — this method checks each variant so callers do not
53    /// need to match on [`StmtKind`]:
54    ///
55    /// | `StmtKind` variant | source field |
56    /// |--------------------|--------------|
57    /// | `Function`         | [`FunctionDecl::doc_comment`] |
58    /// | `Class`            | [`ClassDecl::doc_comment`] |
59    /// | `Interface`        | [`InterfaceDecl::doc_comment`] |
60    /// | `Trait`            | [`TraitDecl::doc_comment`] |
61    /// | `Enum`             | [`EnumDecl::doc_comment`] |
62    /// | `Const`            | first [`ConstItem::doc_comment`] |
63    ///
64    /// Returns `None` when no doc-block precedes the statement.
65    pub fn leading_doc_comment(&self) -> Option<&Comment<'src>> {
66        if let Some(doc) = self.doc_comment {
67            return Some(doc);
68        }
69        match &self.kind {
70            StmtKind::Function(f) => f.doc_comment.as_ref(),
71            StmtKind::Class(c) => c.doc_comment.as_ref(),
72            StmtKind::Interface(i) => i.doc_comment.as_ref(),
73            StmtKind::Trait(t) => t.doc_comment.as_ref(),
74            StmtKind::Enum(e) => e.doc_comment.as_ref(),
75            StmtKind::Const(items) => items.first().and_then(|i| i.doc_comment.as_ref()),
76            _ => None,
77        }
78    }
79}
80
81/// A brace-delimited statement block. Used both as a standalone block
82/// statement ([`StmtKind::Block`]) and as the body of constructs that are
83/// *always* braced (functions, methods, closures, `try`/`catch`/`finally`,
84/// braced namespaces, property-hook blocks) — those positions hold a
85/// `&Block` so the "it's a block" invariant is enforced by the type.
86#[derive(Debug)]
87#[cfg_attr(feature = "serde", derive(Serialize))]
88#[cfg_attr(feature = "serde", serde(transparent))]
89pub struct Block<'arena, 'src> {
90    /// Statements in the block.
91    pub stmts: ArenaVec<'arena, Stmt<'arena, 'src>>,
92    /// Span covering `{`..`}` (or the keyword-delimited region for the
93    /// alternative-syntax blocks reachable only via [`StmtKind::Block`]).
94    #[cfg_attr(feature = "serde", serde(skip))]
95    pub span: Span,
96}
97
98/// The kinds of statement.
99#[derive(Debug)]
100#[cfg_attr(feature = "serde", derive(Serialize))]
101#[non_exhaustive]
102pub enum StmtKind<'arena, 'src> {
103    /// Expression statement (e.g. `foo();`)
104    Expression(&'arena Expr<'arena, 'src>),
105
106    /// Echo statement: `echo expr1, expr2;`
107    Echo(ArenaVec<'arena, Expr<'arena, 'src>>),
108
109    /// Return statement: `return expr;`
110    Return(Option<&'arena Expr<'arena, 'src>>),
111
112    /// Block statement: `{ stmts }`
113    Block(&'arena Block<'arena, 'src>),
114
115    /// If statement
116    If(&'arena IfStmt<'arena, 'src>),
117
118    /// While loop
119    While(&'arena WhileStmt<'arena, 'src>),
120
121    /// For loop
122    For(&'arena ForStmt<'arena, 'src>),
123
124    /// Foreach loop
125    Foreach(&'arena ForeachStmt<'arena, 'src>),
126
127    /// Do-while loop
128    DoWhile(&'arena DoWhileStmt<'arena, 'src>),
129
130    /// Function declaration
131    Function(&'arena FunctionDecl<'arena, 'src>),
132
133    /// Break statement
134    Break(Option<&'arena Expr<'arena, 'src>>),
135
136    /// Continue statement
137    Continue(Option<&'arena Expr<'arena, 'src>>),
138
139    /// Switch statement
140    Switch(&'arena SwitchStmt<'arena, 'src>),
141
142    /// Goto statement
143    Goto(Ident<'src>),
144
145    /// Label statement
146    Label(Ident<'src>),
147
148    /// Declare statement
149    Declare(&'arena DeclareStmt<'arena, 'src>),
150
151    /// Unset statement
152    Unset(ArenaVec<'arena, Expr<'arena, 'src>>),
153
154    /// Throw statement (also can be expression in PHP 8)
155    Throw(&'arena Expr<'arena, 'src>),
156
157    /// Try/catch/finally
158    TryCatch(&'arena TryCatchStmt<'arena, 'src>),
159
160    /// Global declaration
161    Global(ArenaVec<'arena, Expr<'arena, 'src>>),
162
163    /// Class declaration
164    Class(&'arena ClassDecl<'arena, 'src>),
165
166    /// Interface declaration
167    Interface(&'arena InterfaceDecl<'arena, 'src>),
168
169    /// Trait declaration
170    Trait(&'arena TraitDecl<'arena, 'src>),
171
172    /// Enum declaration
173    Enum(&'arena EnumDecl<'arena, 'src>),
174
175    /// Namespace declaration
176    Namespace(&'arena NamespaceDecl<'arena, 'src>),
177
178    /// Use declaration
179    Use(&'arena UseDecl<'arena, 'src>),
180
181    /// Top-level constant: `const FOO = expr;`
182    Const(ArenaVec<'arena, ConstItem<'arena, 'src>>),
183
184    /// Static variable declaration: `static $x = 1;`
185    StaticVar(ArenaVec<'arena, StaticVar<'arena, 'src>>),
186
187    /// __halt_compiler(); with remaining data
188    HaltCompiler(&'src str),
189
190    /// Nop (empty statement `;`)
191    Nop,
192
193    /// Inline HTML
194    InlineHtml(&'src str),
195
196    /// Error placeholder — parser always produces a tree
197    Error,
198}
199
200/// An `if` statement with optional `elseif`/`else` branches.
201#[derive(Debug)]
202#[cfg_attr(feature = "serde", derive(Serialize))]
203#[non_exhaustive]
204pub struct IfStmt<'arena, 'src> {
205    /// `if` condition.
206    pub condition: Expr<'arena, 'src>,
207    /// Statement run when the condition holds.
208    pub then_branch: &'arena Stmt<'arena, 'src>,
209    /// `elseif` branches in order.
210    pub elseif_branches: ArenaVec<'arena, ElseIfBranch<'arena, 'src>>,
211    /// `else` statement, if any.
212    pub else_branch: Option<&'arena Stmt<'arena, 'src>>,
213    /// The `else` keyword; `None` when there is no else branch. Printer layout detail, outside semver; not serialized.
214    #[cfg_attr(feature = "serde", serde(skip))]
215    #[doc(hidden)]
216    pub else_kw_span: Option<Span>,
217    /// `true` when written in alternative syntax (`: ... endX;`).
218    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
219    pub uses_alternative: bool,
220}
221
222impl<'arena, 'src> IfStmt<'arena, 'src> {
223    /// Builds a `IfStmt` from its identifying fields with every other field empty. Set
224    /// the rest by assignment, as with `Param::new`.
225    pub fn new(
226        arena: &'arena bumpalo::Bump,
227        condition: Expr<'arena, 'src>,
228        then_branch: &'arena Stmt<'arena, 'src>,
229    ) -> Self {
230        Self {
231            condition,
232            then_branch,
233            elseif_branches: ArenaVec::new_in(arena),
234            else_branch: None,
235            else_kw_span: None,
236            uses_alternative: false,
237        }
238    }
239}
240
241/// An `elseif` branch. `else if` parses as an `else` whose body is an `if` statement.
242#[derive(Debug)]
243#[cfg_attr(feature = "serde", derive(Serialize))]
244pub struct ElseIfBranch<'arena, 'src> {
245    /// Condition expression.
246    pub condition: Expr<'arena, 'src>,
247    /// Statement run when this branch matches.
248    pub body: Stmt<'arena, 'src>,
249    /// Source range of this node.
250    pub span: Span,
251}
252
253/// A `while` loop.
254#[derive(Debug)]
255#[cfg_attr(feature = "serde", derive(Serialize))]
256#[non_exhaustive]
257pub struct WhileStmt<'arena, 'src> {
258    /// Condition expression.
259    pub condition: Expr<'arena, 'src>,
260    /// Loop body.
261    pub body: &'arena Stmt<'arena, 'src>,
262    /// `true` when written in alternative syntax (`: ... endX;`).
263    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
264    pub uses_alternative: bool,
265}
266
267impl<'arena, 'src> WhileStmt<'arena, 'src> {
268    /// Builds a `WhileStmt` from its identifying fields with every other field empty. Set
269    /// the rest by assignment, as with `Param::new`.
270    pub fn new(condition: Expr<'arena, 'src>, body: &'arena Stmt<'arena, 'src>) -> Self {
271        Self {
272            condition,
273            body,
274            uses_alternative: false,
275        }
276    }
277}
278
279/// A `for` loop.
280#[derive(Debug)]
281#[cfg_attr(feature = "serde", derive(Serialize))]
282#[non_exhaustive]
283pub struct ForStmt<'arena, 'src> {
284    /// Initializer expressions.
285    pub init: ArenaVec<'arena, Expr<'arena, 'src>>,
286    /// Condition expressions.
287    pub condition: ArenaVec<'arena, Expr<'arena, 'src>>,
288    /// Update expressions.
289    pub update: ArenaVec<'arena, Expr<'arena, 'src>>,
290    /// Loop body.
291    pub body: &'arena Stmt<'arena, 'src>,
292    /// `true` when written in alternative syntax (`: ... endX;`).
293    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
294    pub uses_alternative: bool,
295}
296
297impl<'arena, 'src> ForStmt<'arena, 'src> {
298    /// Builds a `ForStmt` from its identifying fields with every other field empty. Set
299    /// the rest by assignment, as with `Param::new`.
300    pub fn new(arena: &'arena bumpalo::Bump, body: &'arena Stmt<'arena, 'src>) -> Self {
301        Self {
302            init: ArenaVec::new_in(arena),
303            condition: ArenaVec::new_in(arena),
304            update: ArenaVec::new_in(arena),
305            body,
306            uses_alternative: false,
307        }
308    }
309}
310
311/// A `foreach` loop.
312#[derive(Debug)]
313#[cfg_attr(feature = "serde", derive(Serialize))]
314#[non_exhaustive]
315pub struct ForeachStmt<'arena, 'src> {
316    /// Expression being iterated.
317    pub expr: Expr<'arena, 'src>,
318    /// Key target in `$k => $v`.
319    pub key: Option<Expr<'arena, 'src>>,
320    /// Value target.
321    pub value: Expr<'arena, 'src>,
322    /// `true` when the value is taken by reference: `foreach ($a as &$v)`.
323    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
324    pub by_ref: bool,
325    /// The `&` of a by-reference value; `None` when `by_ref` is `false`.
326    #[cfg_attr(
327        feature = "serde",
328        serde(default, skip_serializing_if = "Option::is_none")
329    )]
330    pub by_ref_span: Option<Span>,
331    /// Loop body.
332    pub body: &'arena Stmt<'arena, 'src>,
333    /// `true` when written in alternative syntax (`: ... endX;`).
334    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
335    pub uses_alternative: bool,
336}
337
338impl<'arena, 'src> ForeachStmt<'arena, 'src> {
339    /// Builds a `ForeachStmt` from its identifying fields with every other field empty. Set
340    /// the rest by assignment, as with `Param::new`.
341    pub fn new(
342        expr: Expr<'arena, 'src>,
343        value: Expr<'arena, 'src>,
344        body: &'arena Stmt<'arena, 'src>,
345    ) -> Self {
346        Self {
347            expr,
348            key: None,
349            value,
350            by_ref: false,
351            by_ref_span: None,
352            body,
353            uses_alternative: false,
354        }
355    }
356}
357
358/// A `do ... while` loop.
359#[derive(Debug)]
360#[cfg_attr(feature = "serde", derive(Serialize))]
361#[non_exhaustive]
362pub struct DoWhileStmt<'arena, 'src> {
363    /// Loop body.
364    pub body: &'arena Stmt<'arena, 'src>,
365    /// Condition checked after each iteration.
366    pub condition: Expr<'arena, 'src>,
367}
368
369impl<'arena, 'src> DoWhileStmt<'arena, 'src> {
370    /// Builds a `DoWhileStmt` from its identifying fields with every other field empty. Set
371    /// the rest by assignment, as with `Param::new`.
372    pub fn new(body: &'arena Stmt<'arena, 'src>, condition: Expr<'arena, 'src>) -> Self {
373        Self { body, condition }
374    }
375}
376
377/// The case list of a `switch`.
378#[derive(Debug)]
379#[cfg_attr(feature = "serde", derive(Serialize))]
380pub struct SwitchBody<'arena, 'src> {
381    /// Cases in source order.
382    pub cases: ArenaVec<'arena, SwitchCase<'arena, 'src>>,
383    /// Source range of this node.
384    #[cfg_attr(feature = "serde", serde(skip))]
385    pub span: Span,
386}
387
388/// A `switch` statement.
389#[derive(Debug)]
390#[cfg_attr(feature = "serde", derive(Serialize))]
391#[non_exhaustive]
392pub struct SwitchStmt<'arena, 'src> {
393    /// Subject expression.
394    pub expr: Expr<'arena, 'src>,
395    /// Case list, flattened on serialization.
396    #[cfg_attr(feature = "serde", serde(flatten))]
397    pub body: SwitchBody<'arena, 'src>,
398    /// `true` when written in alternative syntax (`: ... endX;`).
399    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
400    pub uses_alternative: bool,
401}
402
403impl<'arena, 'src> SwitchStmt<'arena, 'src> {
404    /// Builds a `SwitchStmt` from its identifying fields with every other field empty. Set
405    /// the rest by assignment, as with `Param::new`.
406    pub fn new(expr: Expr<'arena, 'src>, body: SwitchBody<'arena, 'src>) -> Self {
407        Self {
408            expr,
409            body,
410            uses_alternative: false,
411        }
412    }
413}
414
415/// A `case` or `default` clause.
416#[derive(Debug)]
417#[cfg_attr(feature = "serde", derive(Serialize))]
418pub struct SwitchCase<'arena, 'src> {
419    /// Case expression; `None` for `default`.
420    pub value: Option<Expr<'arena, 'src>>,
421    /// Statements under this case.
422    pub body: ArenaVec<'arena, Stmt<'arena, 'src>>,
423    /// Source range of this node.
424    pub span: Span,
425}
426
427/// A `try` statement with `catch` and `finally` clauses.
428#[derive(Debug)]
429#[cfg_attr(feature = "serde", derive(Serialize))]
430#[non_exhaustive]
431pub struct TryCatchStmt<'arena, 'src> {
432    /// `try` block.
433    pub body: &'arena Block<'arena, 'src>,
434    /// `catch` clauses in order.
435    pub catches: ArenaVec<'arena, CatchClause<'arena, 'src>>,
436    /// `finally` block, if any.
437    pub finally: Option<&'arena Block<'arena, 'src>>,
438    /// The `finally` keyword; `None` when there is no finally clause. Printer layout detail, outside semver; not serialized.
439    #[cfg_attr(feature = "serde", serde(skip))]
440    #[doc(hidden)]
441    pub finally_kw_span: Option<Span>,
442}
443
444impl<'arena, 'src> TryCatchStmt<'arena, 'src> {
445    /// Builds a `TryCatchStmt` from its identifying fields with every other field empty. Set
446    /// the rest by assignment, as with `Param::new`.
447    pub fn new(arena: &'arena bumpalo::Bump, body: &'arena Block<'arena, 'src>) -> Self {
448        Self {
449            body,
450            catches: ArenaVec::new_in(arena),
451            finally: None,
452            finally_kw_span: None,
453        }
454    }
455}
456
457/// A `catch (Type $e) { ... }` clause.
458#[derive(Debug)]
459#[cfg_attr(feature = "serde", derive(Serialize))]
460#[non_exhaustive]
461pub struct CatchClause<'arena, 'src> {
462    /// Caught exception types (`A|B`).
463    pub types: ArenaVec<'arena, Name<'arena, 'src>>,
464    /// Bound variable name; `None` if omitted (PHP 8.0+).
465    pub var: Option<Ident<'src>>,
466    /// `catch` block.
467    pub body: &'arena Block<'arena, 'src>,
468    /// Source range of this node.
469    pub span: Span,
470}
471
472impl<'arena, 'src> CatchClause<'arena, 'src> {
473    /// Builds a `CatchClause` from its identifying fields with every other field empty. Set
474    /// the rest by assignment, as with `Param::new`.
475    pub fn new(
476        arena: &'arena bumpalo::Bump,
477        body: &'arena Block<'arena, 'src>,
478        span: Span,
479    ) -> Self {
480        Self {
481            types: ArenaVec::new_in(arena),
482            var: None,
483            body,
484            span,
485        }
486    }
487}
488
489/// A `namespace` declaration.
490#[derive(Debug)]
491#[cfg_attr(feature = "serde", derive(Serialize))]
492#[non_exhaustive]
493pub struct NamespaceDecl<'arena, 'src> {
494    /// Namespace name; `None` for the global namespace.
495    pub name: Option<Name<'arena, 'src>>,
496    /// Braced or simple form.
497    pub body: NamespaceBody<'arena, 'src>,
498}
499
500impl<'arena, 'src> NamespaceDecl<'arena, 'src> {
501    /// Builds a `NamespaceDecl` from its identifying fields with every other field empty. Set
502    /// the rest by assignment, as with `Param::new`.
503    pub fn new(name: Option<Name<'arena, 'src>>, body: NamespaceBody<'arena, 'src>) -> Self {
504        Self { name, body }
505    }
506}
507
508/// Whether a namespace is braced or simple.
509#[derive(Debug)]
510#[cfg_attr(feature = "serde", derive(Serialize))]
511#[non_exhaustive]
512pub enum NamespaceBody<'arena, 'src> {
513    /// `namespace Foo { … }` — braced form; the statements are scoped to this namespace.
514    Braced(&'arena Block<'arena, 'src>),
515    /// `namespace Foo;` — simple form; all subsequent statements until the next `namespace` or EOF are in scope.
516    Simple,
517}
518
519/// A `declare(...)` statement.
520#[derive(Debug)]
521#[cfg_attr(feature = "serde", derive(Serialize))]
522#[non_exhaustive]
523pub struct DeclareStmt<'arena, 'src> {
524    /// `name = value` directives.
525    pub directives: ArenaVec<'arena, (&'src str, Expr<'arena, 'src>)>,
526    /// Statement scoped by the directive, if any.
527    pub body: Option<&'arena Stmt<'arena, 'src>>,
528    /// `true` when written in alternative syntax (`: ... endX;`).
529    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
530    pub uses_alternative: bool,
531}
532
533impl<'arena, 'src> DeclareStmt<'arena, 'src> {
534    /// Builds a `DeclareStmt` from its identifying fields with every other field empty. Set
535    /// the rest by assignment, as with `Param::new`.
536    pub fn new(directives: ArenaVec<'arena, (&'src str, Expr<'arena, 'src>)>) -> Self {
537        Self {
538            directives,
539            body: None,
540            uses_alternative: false,
541        }
542    }
543}
544
545/// A `use` import statement.
546#[derive(Debug)]
547#[cfg_attr(feature = "serde", derive(Serialize))]
548#[non_exhaustive]
549pub struct UseDecl<'arena, 'src> {
550    /// Whether importing classes, functions or constants.
551    pub kind: UseKind,
552    /// Imported names.
553    pub uses: ArenaVec<'arena, UseItem<'arena, 'src>>,
554}
555
556impl<'arena, 'src> UseDecl<'arena, 'src> {
557    /// Builds a `UseDecl` from its identifying fields with every other field empty. Set
558    /// the rest by assignment, as with `Param::new`.
559    pub fn new(kind: UseKind, uses: ArenaVec<'arena, UseItem<'arena, 'src>>) -> Self {
560        Self { kind, uses }
561    }
562}
563
564/// What a `use` import brings in.
565#[derive(Debug, Clone, Copy, PartialEq, Eq)]
566#[cfg_attr(feature = "serde", derive(Serialize))]
567#[non_exhaustive]
568pub enum UseKind {
569    /// `use Foo\Bar` — imports a class, interface, trait, or enum.
570    Normal,
571    /// `use function Foo\bar` — imports a function.
572    Function,
573    /// `use const Foo\BAR` — imports a constant.
574    Const,
575}
576
577/// One imported name in a `use` statement.
578#[derive(Debug)]
579#[cfg_attr(feature = "serde", derive(Serialize))]
580pub struct UseItem<'arena, 'src> {
581    /// Imported name.
582    pub name: Name<'arena, 'src>,
583    /// Alias after `as`, if any.
584    pub alias: Option<Ident<'src>>,
585    /// Per-item kind in a mixed group `use Foo\{function bar}`.
586    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
587    pub kind: Option<UseKind>,
588    /// Source range of this node.
589    pub span: Span,
590}
591
592/// One `NAME = value` item of a top-level `const` statement.
593#[derive(Debug)]
594#[cfg_attr(feature = "serde", derive(Serialize))]
595pub struct ConstItem<'arena, 'src> {
596    /// Constant name.
597    pub name: Ident<'src>,
598    /// Constant value expression.
599    pub value: Expr<'arena, 'src>,
600    /// `#[...]` attributes applied to this node.
601    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
602    /// Source range of this node.
603    pub span: Span,
604    /// Preceding `/** */` doc-block, if any.
605    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
606    pub doc_comment: Option<Comment<'src>>,
607}
608
609/// One variable of a `static $x = 1;` statement.
610#[derive(Debug)]
611#[cfg_attr(feature = "serde", derive(Serialize))]
612pub struct StaticVar<'arena, 'src> {
613    /// Variable name without `$`.
614    pub name: Ident<'src>,
615    /// Initial value, if any.
616    pub default: Option<Expr<'arena, 'src>>,
617    /// Source range of this node.
618    pub span: Span,
619}