com.google.javascript.jscomp.parsing.parser.codegeneration.ParseTreeFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.google.javascript.jscomp.parsing.parser.codegeneration.ParseTreeFactory.java

Source

/*
 * Copyright 2011 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.javascript.jscomp.parsing.parser.codegeneration;

import com.google.common.collect.ImmutableList;
import com.google.javascript.jscomp.parsing.parser.IdentifierToken;
import com.google.javascript.jscomp.parsing.parser.LiteralToken;
import com.google.javascript.jscomp.parsing.parser.PredefinedName;
import com.google.javascript.jscomp.parsing.parser.Token;
import com.google.javascript.jscomp.parsing.parser.TokenType;
import com.google.javascript.jscomp.parsing.parser.trees.*;

import java.util.Arrays;
import java.util.List;

/**
 * Contains static methods to create common ParseTree fragments.
 *
 * It is a common to statically import the members of this class.
 *
 * TODO: All public methods with "..." should immediately create immutable
 *       list, the rest of code should be fully immutable.
 */
public final class ParseTreeFactory {
    // no instances
    private ParseTreeFactory() {
    }

    // Tokens
    public static Token createOperatorToken(TokenType operator) {
        return new Token(operator, null);
    }

    public static IdentifierToken createIdentifierToken(String identifier) {
        return new IdentifierToken(null, identifier);
    }

    public static Token createPropertyNameToken(String propertyName) {
        // TODO: properties with non identifier names
        return createIdentifierToken(propertyName);
    }

    public static Token createStringLiteralToken(String value) {
        // TODO: escape string literal token
        return new LiteralToken(TokenType.STRING, "\"" + value + "\"", null);
    }

    public static Token createBooleanLiteralToken(boolean value) {
        return new Token(value ? TokenType.TRUE : TokenType.FALSE, null);
    }

    public static Token createNullLiteralToken() {
        return new LiteralToken(TokenType.NULL, "null", null);
    }

    public static Token createNumberLiteralToken(Number value) {
        return new LiteralToken(TokenType.NUMBER, value.toString(), null);
    }

    // Token lists
    public static ImmutableList<String> createEmptyParameters() {
        return ImmutableList.<String>of();
    }

    public static ImmutableList<String> createParameters(IdentifierToken parameter) {
        return ImmutableList.<String>of(parameter.value);
    }

    public static ImmutableList<String> createParameters(FormalParameterListTree parameters) {
        ImmutableList.Builder<String> builder = ImmutableList.<String>builder();

        for (ParseTree parameter : parameters.parameters) {
            if (!parameter.isRestParameter()) {
                // TODO: array and object patterns
                builder.add(parameter.asIdentifierExpression().identifierToken.value);
            }
        }

        return builder.build();
    }

    public static ImmutableList<ParseTree> createStatementList(ParseTree... statements) {
        return ImmutableList.<ParseTree>copyOf(statements);
    }

    public static ImmutableList<ParseTree> createStatementList(List<ParseTree> head, ParseTree tail) {
        ImmutableList.Builder<ParseTree> result = new ImmutableList.Builder<ParseTree>();
        result.addAll(head);
        result.add(tail);
        return result.build();
    }

    private static FormalParameterListTree createParameterList(ImmutableList<String> formalParameters) {

        ImmutableList.Builder<ParseTree> builder = ImmutableList.<ParseTree>builder();

        for (String parameter : formalParameters) {
            builder.add(createIdentifierExpression(parameter));
        }
        return new FormalParameterListTree(null, builder.build());
    }

    public static FormalParameterListTree createParameterList(IdentifierToken parameter) {
        return new FormalParameterListTree(null,
                ImmutableList.<ParseTree>of(createIdentifierExpression(parameter)));
    }

    /**
     * Creates an expression that refers to the {@code index}-th
     * parameter by its predefined name.
     *
     * @see PredefinedName#getParameterName
     */
    public static IdentifierExpressionTree createParameterReference(int index) {
        return createIdentifierExpression(PredefinedName.getParameterName(index));
    }

    private static FormalParameterListTree createParameterList(int numberOfParameters, boolean hasRestParams) {
        ImmutableList.Builder<ParseTree> builder = ImmutableList.<ParseTree>builder();

        for (int index = 0; index < numberOfParameters; index++) {
            String parameterName = PredefinedName.getParameterName(index);
            boolean isRestParameter = index == numberOfParameters - 1 && hasRestParams;
            builder.add(isRestParameter ? createRestParameter(parameterName)
                    : createIdentifierExpression(parameterName));
        }

        return new FormalParameterListTree(null, builder.build());
    }

    public static FormalParameterListTree createParameterList(int numberOfParameters) {
        return createParameterList(numberOfParameters, false);
    }

    public static FormalParameterListTree createParameterListWithRestParams(int numberOfParameters) {
        return createParameterList(numberOfParameters, true);
    }

    public static FormalParameterListTree createParameterList(String... parameters) {
        ImmutableList.Builder<ParseTree> parameterList = new ImmutableList.Builder<ParseTree>();
        for (String parameter : parameters) {
            parameterList.add(createIdentifierExpression(parameter));
        }
        return new FormalParameterListTree(null, parameterList.build());
    }

    public static FormalParameterListTree createEmptyParameterList() {
        return new FormalParameterListTree(null, ImmutableList.<ParseTree>of());
    }

    // Tree Lists
    private static ImmutableList<ParseTree> createEmptyList() {
        return ImmutableList.of();
    }

    // Trees
    public static ArgumentListTree createArgumentList(ImmutableList<ParseTree> list) {
        return new ArgumentListTree(null, list);
    }

    public static ArgumentListTree createArgumentList(ParseTree... list) {
        return new ArgumentListTree(null, ImmutableList.<ParseTree>copyOf(list));
    }

    public static ArgumentListTree createArgumentList(int numberOfArguments) {
        return createArgumentListFromParameterList(createParameterList(numberOfArguments));
    }

    public static ArgumentListTree createArgumentListFromParameterList(
            FormalParameterListTree formalParameterList) {

        ImmutableList.Builder<ParseTree> builder = new ImmutableList.Builder<ParseTree>();

        for (ParseTree parameter : formalParameterList.parameters) {
            if (parameter.isRestParameter()) {
                builder.add(
                        createSpreadExpression(createIdentifierExpression(parameter.asRestParameter().identifier)));
            } else {
                // TODO: implement pattern -> array, object literal translation
                builder.add(parameter);
            }
        }

        return new ArgumentListTree(null, builder.build());
    }

    public static ArgumentListTree createEmptyArgumentList() {
        return new ArgumentListTree(null, createEmptyList());
    }

    public static ArrayLiteralExpressionTree createArrayLiteralExpression(ImmutableList<ParseTree> list) {
        return new ArrayLiteralExpressionTree(null, list);
    }

    public static ArrayLiteralExpressionTree createEmptyArrayLiteralExpression() {
        return createArrayLiteralExpression(createEmptyList());
    }

    public static ArrayPatternTree createArrayPattern(ImmutableList<ParseTree> list) {
        return new ArrayPatternTree(null, list);
    }

    public static BinaryOperatorTree createAssignmentExpression(ParseTree lhs, ParseTree rhs) {
        return new BinaryOperatorTree(null, lhs, createOperatorToken(TokenType.EQUAL), rhs);
    }

    public static BinaryOperatorTree createBinaryOperator(ParseTree left, Token operator, ParseTree right) {
        return new BinaryOperatorTree(null, left, operator, right);
    }

    public static EmptyStatementTree createEmptyStatement() {
        return new EmptyStatementTree(null);
    }

    public static BlockTree createEmptyBlock() {
        return createBlock(createEmptyList());
    }

    public static BlockTree createBlock(ImmutableList<ParseTree> statements) {
        return new BlockTree(null, statements);
    }

    public static BlockTree createBlock(ParseTree... statements) {
        return new BlockTree(null, ImmutableList.<ParseTree>copyOf(statements));
    }

    public static ParseTree createScopedStatements(ImmutableList<ParseTree> statements) {
        return createScopedBlock(createBlock(statements));
    }

    public static ParseTree createScopedStatements(ParseTree... statements) {
        return createScopedBlock(createBlock(statements));
    }

    public static ParseTree createScopedBlock(BlockTree block) {
        return createExpressionStatement(createScopedExpression(block));
    }

    public static CallExpressionTree createScopedExpression(BlockTree block) {
        return createCallCall(createParenExpression(createFunctionExpression(createEmptyParameterList(), block)),
                createThisExpression());
    }

    public static CallExpressionTree createCallExpression(ParseTree operand, ArgumentListTree arguments) {
        return new CallExpressionTree(null, operand, arguments);
    }

    public static CallExpressionTree createCallExpression(ParseTree operand) {
        return createCallExpression(operand, createEmptyArgumentList());
    }

    public static CallExpressionTree createBoundCall(ParseTree function, ParseTree thisTree) {
        return createCallExpression(createMemberExpression(
                function.type == ParseTreeType.FUNCTION_DECLARATION ? createParenExpression(function) : function,
                PredefinedName.BIND), createArgumentList(thisTree));
    }

    public static CallExpressionTree createLookupGetter(String aggregateName, String propertyName) {
        return createCallExpression(
                createMemberExpression(aggregateName, PredefinedName.PROTOTYPE, PredefinedName.LOOKUP_GETTER),
                createArgumentList(createStringLiteral(propertyName)));
    }

    public static BreakStatementTree createBreakStatement() {
        return new BreakStatementTree(null, null);
    }

    // function.call(this, arguments)
    public static CallExpressionTree createCallCall(ParseTree function, ParseTree thisExpression,
            ParseTree... arguments) {
        List<ParseTree> argumentsAsList = Arrays.asList(arguments);
        return createCallCall(function, thisExpression, argumentsAsList);
    }

    public static CallExpressionTree createCallCall(ParseTree function, ParseTree thisExpression,
            List<ParseTree> arguments) {
        ImmutableList.Builder<ParseTree> builder = ImmutableList.<ParseTree>builder();

        builder.add(thisExpression);
        builder.addAll(arguments);

        return createCallExpression(createMemberExpression(function, PredefinedName.CALL),
                createArgumentList(builder.build()));
    }

    public static ParseTree createCallCallStatement(ParseTree function, ParseTree thisExpression,
            ParseTree... arguments) {
        return createExpressionStatement(createCallCall(function, thisExpression, arguments));
    }

    public static CaseClauseTree createCaseClause(ParseTree expression, ImmutableList<ParseTree> statements) {
        return new CaseClauseTree(null, expression, statements);
    }

    public static CatchTree createCatch(IdentifierToken exceptionName, ParseTree catchBody) {
        return new CatchTree(null, exceptionName, catchBody);
    }

    public static ClassDeclarationTree createClassDeclaration(IdentifierToken name, ParseTree superClass,
            ImmutableList<ParseTree> elements) {
        return new ClassDeclarationTree(null, name, false, superClass, elements);
    }

    public static ClassDeclarationTree createClassExpression(IdentifierToken name, ParseTree superClass,
            ImmutableList<ParseTree> elements) {
        return new ClassDeclarationTree(null, name, true, superClass, elements);
    }

    public static CommaExpressionTree createCommaExpression(ImmutableList<ParseTree> expressions) {
        return new CommaExpressionTree(null, expressions);
    }

    public static ConditionalExpressionTree createConditionalExpression(ParseTree condition, ParseTree left,
            ParseTree right) {
        return new ConditionalExpressionTree(null, condition, left, right);
    }

    public static ContinueStatementTree createContinueStatement() {
        return new ContinueStatementTree(null, null);
    }

    public static DefaultClauseTree createDefaultClause(ImmutableList<ParseTree> statements) {
        return new DefaultClauseTree(null, statements);
    }

    public static DefaultParameterTree createDefaultParameter(IdentifierExpressionTree identifier,
            ParseTree expression) {
        return new DefaultParameterTree(null, identifier, expression);
    }

    public static DoWhileStatementTree createDoWhileStatement(ParseTree body, ParseTree condition) {
        return new DoWhileStatementTree(null, body, condition);
    }

    public static ExpressionStatementTree createAssignmentStatement(ParseTree lhs, ParseTree rhs) {
        return createExpressionStatement(createAssignmentExpression(lhs, rhs));
    }

    public static ExpressionStatementTree createCallStatement(ParseTree operand, ArgumentListTree arguments) {
        return createExpressionStatement(createCallExpression(operand, arguments));
    }

    public static ExpressionStatementTree createCallStatement(ParseTree operand) {
        return createExpressionStatement(createCallExpression(operand));
    }

    public static ExpressionStatementTree createExpressionStatement(ParseTree expression) {
        return new ExpressionStatementTree(null, expression);
    }

    public static FinallyTree createFinally(ParseTree block) {
        return new FinallyTree(null, block);
    }

    public static ForOfStatementTree createForEachStatement(VariableDeclarationListTree initializer,
            ParseTree collection, ParseTree body) {
        return new ForOfStatementTree(null, initializer, collection, body);
    }

    public static ForInStatementTree createForInStatement(ParseTree initializer, ParseTree collection,
            ParseTree body) {
        return new ForInStatementTree(null, initializer, collection, body);
    }

    public static ForStatementTree createForStatement(ParseTree variables, ParseTree condition, ParseTree increment,
            ParseTree body) {
        return new ForStatementTree(null, variables, condition, increment, body);
    }

    public static FunctionDeclarationTree createFunctionExpressionFormals(ImmutableList<String> formalParameters,
            BlockTree functionBody) {
        return createFunctionExpression(createParameterList(formalParameters), functionBody);
    }

    public static FunctionDeclarationTree createFunctionExpression(FormalParameterListTree formalParameterList,
            BlockTree functionBody) {
        return new FunctionDeclarationTree(null, null, false, false, FunctionDeclarationTree.Kind.EXPRESSION,
                formalParameterList, functionBody);
    }

    public static FunctionDeclarationTree createFunctionDeclaration(IdentifierToken name,
            FormalParameterListTree formalParameterList, BlockTree functionBody) {
        return new FunctionDeclarationTree(null, name, false, false, FunctionDeclarationTree.Kind.DECLARATION,
                formalParameterList, functionBody);
    }

    public static FunctionDeclarationTree createFunctionDeclaration(String name,
            FormalParameterListTree formalParameterList, BlockTree functionBody) {
        return createFunctionDeclaration(createIdentifierToken(name), formalParameterList, functionBody);
    }

    // [static] get propertyName () { ... }
    public static GetAccessorTree createGetAccessor(String propertyName, boolean isStatic, BlockTree body) {
        return createGetAccessor(createPropertyNameToken(propertyName), isStatic, body);
    }

    // [static] get propertyName () { ... }
    public static GetAccessorTree createGetAccessor(Token propertyName, boolean isStatic, BlockTree body) {
        return new GetAccessorTree(null, propertyName, isStatic, body);
    }

    public static IdentifierExpressionTree createIdentifierExpression(String identifier) {
        return createIdentifierExpression(createIdentifierToken(identifier));
    }

    public static IdentifierExpressionTree createIdentifierExpression(IdentifierToken identifier) {
        return new IdentifierExpressionTree(null, identifier);
    }

    public static IdentifierExpressionTree createUndefinedExpression() {
        return createIdentifierExpression(PredefinedName.UNDEFINED);
    }

    public static IfStatementTree createIfStatement(ParseTree condition, ParseTree ifClause) {
        return createIfStatement(condition, ifClause, null);
    }

    public static IfStatementTree createIfStatement(ParseTree condition, ParseTree ifClause, ParseTree elseClause) {
        return new IfStatementTree(null, condition, ifClause, elseClause);
    }

    public static LabelledStatementTree createLabelledStatement(IdentifierToken name, ParseTree statement) {
        return new LabelledStatementTree(null, name, statement);
    }

    public static ParseTree createStringLiteral(String value) {
        return new LiteralExpressionTree(null, createStringLiteralToken(value));
    }

    public static ParseTree createBooleanLiteral(boolean value) {
        return new LiteralExpressionTree(null, createBooleanLiteralToken(value));
    }

    public static ParseTree createTrueLiteral() {
        return createBooleanLiteral(true);
    }

    public static ParseTree createFalseLiteral() {
        return createBooleanLiteral(false);
    }

    public static ParseTree createNullLiteral() {
        return new LiteralExpressionTree(null, createNullLiteralToken());
    }

    public static ParseTree createNumberLiteral(Number value) {
        return new LiteralExpressionTree(null, createNumberLiteralToken(value));
    }

    public static MemberExpressionTree createMemberExpression(IdentifierExpressionTree operand, String memberName,
            String... memberNames) {
        MemberExpressionTree tree = createMemberExpression(operand, memberName);
        for (String name : memberNames) {
            tree = createMemberExpression(tree, name);
        }

        return tree;
    }

    public static MemberExpressionTree createMemberExpression(String operandName, String memberName,
            String... memberNames) {
        return createMemberExpression(createIdentifierExpression(operandName), memberName, memberNames);
    }

    public static MemberExpressionTree createMemberExpression(ParseTree operand, IdentifierToken memberName) {
        return new MemberExpressionTree(null, operand, memberName);
    }

    public static MemberExpressionTree createMemberExpression(ParseTree operand, String memberName) {
        return createMemberExpression(operand, createIdentifierToken(memberName));
    }

    public static MemberLookupExpressionTree createMemberLookupExpression(ParseTree operand,
            ParseTree memberExpression) {
        return new MemberLookupExpressionTree(null, operand, memberExpression);
    }

    public static MemberExpressionTree createThisExpression(IdentifierToken memberName) {
        return createMemberExpression(createThisExpression(), memberName);
    }

    public static MemberExpressionTree createThisExpression(String memberName) {
        return createMemberExpression(createThisExpression(), memberName);
    }

    public static NewExpressionTree createNewExpression(ParseTree operand, ArgumentListTree arguments) {
        return new NewExpressionTree(null, operand, arguments);
    }

    public static ParseTree createObjectFreeze(ParseTree value) {
        // Object.freeze(value)
        return createCallExpression(createMemberExpression(PredefinedName.OBJECT, PredefinedName.FREEZE),
                createArgumentList(value));
    }

    public static ObjectLiteralExpressionTree createObjectLiteralExpression(ParseTree... propertyNameAndValues) {
        return createObjectLiteralExpression(ImmutableList.<ParseTree>copyOf(propertyNameAndValues));
    }

    public static ObjectLiteralExpressionTree createObjectLiteralExpression(
            ImmutableList<ParseTree> propertyNameAndValues) {
        return new ObjectLiteralExpressionTree(null, propertyNameAndValues);
    }

    public static ObjectPatternTree createObjectPattern(ImmutableList<ParseTree> list) {
        return new ObjectPatternTree(null, list);
    }

    public static ObjectPatternFieldTree createObjectPatternField(IdentifierToken identifier, ParseTree element) {
        return new ObjectPatternFieldTree(null, identifier, element);
    }

    public static ParenExpressionTree createParenExpression(ParseTree expression) {
        return new ParenExpressionTree(null, expression);
    }

    public static PostfixExpressionTree createPostfixExpression(ParseTree operand, Token operator) {
        return new PostfixExpressionTree(null, operand, operator);
    }

    public static ProgramTree createProgramTree(ImmutableList<ParseTree> sourceElements) {
        return new ProgramTree(null, sourceElements, ImmutableList.<Comment>of());
    }

    public static PropertyNameAssignmentTree createPropertyNameAssignment(String identifier, ParseTree value) {
        return createPropertyNameAssignment(createIdentifierToken(identifier), value);
    }

    public static PropertyNameAssignmentTree createPropertyNameAssignment(Token propertyName, ParseTree value) {
        return new PropertyNameAssignmentTree(null, propertyName, value);
    }

    public static RestParameterTree createRestParameter(String identifier) {
        return createRestParameter(new IdentifierToken(null, identifier));
    }

    public static RestParameterTree createRestParameter(IdentifierToken identifier) {
        return new RestParameterTree(null, identifier);
    }

    public static ReturnStatementTree createReturnStatement(ParseTree expression) {
        return new ReturnStatementTree(null, expression);
    }

    public static YieldExpressionTree createYieldStatement(ParseTree expression) {
        return new YieldExpressionTree(null, false, expression);
    }

    public static SetAccessorTree createSetAccessor(String propertyName, boolean isStatic,
            IdentifierToken parameter, BlockTree body) {
        return createSetAccessor(createPropertyNameToken(propertyName), isStatic, parameter, body);
    }

    public static SetAccessorTree createSetAccessor(String propertyName, boolean isStatic, String parameter,
            BlockTree body) {
        return createSetAccessor(propertyName, isStatic, createIdentifierToken(parameter), body);
    }

    public static SetAccessorTree createSetAccessor(Token propertyName, boolean isStatic, IdentifierToken parameter,
            BlockTree body) {
        return new SetAccessorTree(null, propertyName, isStatic, parameter, body);
    }

    public static SpreadExpressionTree createSpreadExpression(ParseTree expression) {
        return new SpreadExpressionTree(null, expression);
    }

    public static SpreadPatternElementTree createSpreadPatternElement(ParseTree lvalue) {
        return new SpreadPatternElementTree(null, lvalue);
    }

    public static SwitchStatementTree createSwitchStatement(ParseTree expression,
            ImmutableList<ParseTree> caseClauses) {
        return new SwitchStatementTree(null, expression, caseClauses);
    }

    public static ThisExpressionTree createThisExpression() {
        return new ThisExpressionTree(null);
    }

    public static ThrowStatementTree createThrowStatement(ParseTree value) {
        return new ThrowStatementTree(null, value);
    }

    public static TryStatementTree createTryFinallyStatement(ParseTree body, ParseTree finallyBlock) {
        return createTryStatement(body, null, finallyBlock);
    }

    public static TryStatementTree createTryStatement(ParseTree body, ParseTree catchBlock,
            ParseTree finallyBlock) {
        return new TryStatementTree(null, body, catchBlock, finallyBlock);
    }

    public static UnaryExpressionTree createUnaryExpression(Token operator, ParseTree operand) {
        return new UnaryExpressionTree(null, operator, operand);
    }

    public static VariableDeclarationListTree createVariableDeclarationList(TokenType binding,
            IdentifierToken identifier, ParseTree initializer) {

        return createVariableDeclarationList(binding,
                ImmutableList.<VariableDeclarationTree>of(createVariableDeclaration(identifier, initializer)));
    }

    public static VariableDeclarationListTree createVariableDeclarationList(TokenType binding, String identifier,
            ParseTree initializer) {
        return createVariableDeclarationList(binding, createIdentifierToken(identifier), initializer);
    }

    public static VariableDeclarationListTree createVariableDeclarationList(TokenType binding,
            ImmutableList<VariableDeclarationTree> declarations) {
        return new VariableDeclarationListTree(null, binding, declarations);
    }

    public static VariableDeclarationTree createVariableDeclaration(String identifier, ParseTree initializer) {
        return createVariableDeclaration(createIdentifierExpression(identifier), initializer);
    }

    public static VariableDeclarationTree createVariableDeclaration(ParseTree lvalue, ParseTree initializer) {
        return new VariableDeclarationTree(null, lvalue, initializer);
    }

    public static VariableDeclarationTree createVariableDeclaration(IdentifierToken name, ParseTree initializer) {
        return new VariableDeclarationTree(null, createIdentifierExpression(name), initializer);
    }

    public static VariableStatementTree createVariableStatement(TokenType binding, IdentifierToken identifier,
            ParseTree initializer) {
        VariableDeclarationListTree list = createVariableDeclarationList(binding, identifier, initializer);
        return createVariableStatement(list);
    }

    public static VariableStatementTree createVariableStatement(TokenType binding, String identifier,
            ParseTree initializer) {
        VariableDeclarationListTree list = createVariableDeclarationList(binding, identifier, initializer);
        return createVariableStatement(list);
    }

    public static VariableStatementTree createVariableStatement(VariableDeclarationListTree list) {
        return new VariableStatementTree(null, list);
    }

    public static WhileStatementTree createWhileStatement(ParseTree condition, ParseTree body) {
        return new WhileStatementTree(null, condition, body);
    }

    public static WithStatementTree createWithStatement(ParseTree expression, ParseTree body) {
        return new WithStatementTree(null, expression, body);
    }

    public static ExpressionStatementTree createAssignStateStatement(int state) {
        return createAssignmentStatement(createIdentifierExpression(PredefinedName.STATE),
                createNumberLiteral(state));
    }
}