(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./lessScanner", "./cssScanner", "./cssParser", "./cssNodes", "./cssErrors"], factory);
    }
})(function (require, exports) {
    /*---------------------------------------------------------------------------------------------
     *  Copyright (c) Microsoft Corporation. All rights reserved.
     *  Licensed under the MIT License. See License.txt in the project root for license information.
     *--------------------------------------------------------------------------------------------*/
    'use strict';
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.LESSParser = void 0;
    const lessScanner = require("./lessScanner");
    const cssScanner_1 = require("./cssScanner");
    const cssParser = require("./cssParser");
    const nodes = require("./cssNodes");
    const cssErrors_1 = require("./cssErrors");
    /// <summary>
    /// A parser for LESS
    /// http://lesscss.org/
    /// </summary>
    class LESSParser extends cssParser.Parser {
        constructor() {
            super(new lessScanner.LESSScanner());
        }
        _parseStylesheetStatement(isNested = false) {
            if (this.peek(cssScanner_1.TokenType.AtKeyword)) {
                return this._parseVariableDeclaration()
                    || this._parsePlugin()
                    || super._parseStylesheetAtStatement(isNested);
            }
            return this._tryParseMixinDeclaration()
                || this._tryParseMixinReference()
                || this._parseFunction()
                || this._parseRuleset(true);
        }
        _parseImport() {
            if (!this.peekKeyword('@import') && !this.peekKeyword('@import-once') /* deprecated in less 1.4.1 */) {
                return null;
            }
            const node = this.create(nodes.Import);
            this.consumeToken();
            // less 1.4.1: @import (css) "lib"
            if (this.accept(cssScanner_1.TokenType.ParenthesisL)) {
                if (!this.accept(cssScanner_1.TokenType.Ident)) {
                    return this.finish(node, cssErrors_1.ParseError.IdentifierExpected, [cssScanner_1.TokenType.SemiColon]);
                }
                do {
                    if (!this.accept(cssScanner_1.TokenType.Comma)) {
                        break;
                    }
                } while (this.accept(cssScanner_1.TokenType.Ident));
                if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                    return this.finish(node, cssErrors_1.ParseError.RightParenthesisExpected, [cssScanner_1.TokenType.SemiColon]);
                }
            }
            if (!node.addChild(this._parseURILiteral()) && !node.addChild(this._parseStringLiteral())) {
                return this.finish(node, cssErrors_1.ParseError.URIOrStringExpected, [cssScanner_1.TokenType.SemiColon]);
            }
            if (!this.peek(cssScanner_1.TokenType.SemiColon) && !this.peek(cssScanner_1.TokenType.EOF)) {
                node.setMedialist(this._parseMediaQueryList());
            }
            return this.finish(node);
        }
        _parsePlugin() {
            if (!this.peekKeyword('@plugin')) {
                return null;
            }
            const node = this.createNode(nodes.NodeType.Plugin);
            this.consumeToken(); // @import
            if (!node.addChild(this._parseStringLiteral())) {
                return this.finish(node, cssErrors_1.ParseError.StringLiteralExpected);
            }
            if (!this.accept(cssScanner_1.TokenType.SemiColon)) {
                return this.finish(node, cssErrors_1.ParseError.SemiColonExpected);
            }
            return this.finish(node);
        }
        _parseMediaQuery() {
            const node = super._parseMediaQuery();
            if (!node) {
                const node = this.create(nodes.MediaQuery);
                if (node.addChild(this._parseVariable())) {
                    return this.finish(node);
                }
                return null;
            }
            return node;
        }
        _parseMediaDeclaration(isNested = false) {
            return this._tryParseRuleset(isNested)
                || this._tryToParseDeclaration()
                || this._tryParseMixinDeclaration()
                || this._tryParseMixinReference()
                || this._parseDetachedRuleSetMixin()
                || this._parseStylesheetStatement(isNested);
        }
        _parseMediaFeatureName() {
            return this._parseIdent() || this._parseVariable();
        }
        _parseVariableDeclaration(panic = []) {
            const node = this.create(nodes.VariableDeclaration);
            const mark = this.mark();
            if (!node.setVariable(this._parseVariable(true))) {
                return null;
            }
            if (this.accept(cssScanner_1.TokenType.Colon)) {
                if (this.prevToken) {
                    node.colonPosition = this.prevToken.offset;
                }
                if (node.setValue(this._parseDetachedRuleSet())) {
                    node.needsSemicolon = false;
                }
                else if (!node.setValue(this._parseExpr())) {
                    return this.finish(node, cssErrors_1.ParseError.VariableValueExpected, [], panic);
                }
                node.addChild(this._parsePrio());
            }
            else {
                this.restoreAtMark(mark);
                return null; // at keyword, but no ':', not a variable declaration but some at keyword
            }
            if (this.peek(cssScanner_1.TokenType.SemiColon)) {
                node.semicolonPosition = this.token.offset; // not part of the declaration, but useful information for code assist
            }
            return this.finish(node);
        }
        _parseDetachedRuleSet() {
            let mark = this.mark();
            // "Anonymous mixin" used in each() and possibly a generic type in the future
            if (this.peekDelim('#') || this.peekDelim('.')) {
                this.consumeToken();
                if (!this.hasWhitespace() && this.accept(cssScanner_1.TokenType.ParenthesisL)) {
                    let node = this.create(nodes.MixinDeclaration);
                    if (node.getParameters().addChild(this._parseMixinParameter())) {
                        while (this.accept(cssScanner_1.TokenType.Comma) || this.accept(cssScanner_1.TokenType.SemiColon)) {
                            if (this.peek(cssScanner_1.TokenType.ParenthesisR)) {
                                break;
                            }
                            if (!node.getParameters().addChild(this._parseMixinParameter())) {
                                this.markError(node, cssErrors_1.ParseError.IdentifierExpected, [], [cssScanner_1.TokenType.ParenthesisR]);
                            }
                        }
                    }
                    if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                        this.restoreAtMark(mark);
                        return null;
                    }
                }
                else {
                    this.restoreAtMark(mark);
                    return null;
                }
            }
            if (!this.peek(cssScanner_1.TokenType.CurlyL)) {
                return null;
            }
            const content = this.create(nodes.BodyDeclaration);
            this._parseBody(content, this._parseDetachedRuleSetBody.bind(this));
            return this.finish(content);
        }
        _parseDetachedRuleSetBody() {
            return this._tryParseKeyframeSelector() || this._parseRuleSetDeclaration();
        }
        _addLookupChildren(node) {
            if (!node.addChild(this._parseLookupValue())) {
                return false;
            }
            let expectsValue = false;
            while (true) {
                if (this.peek(cssScanner_1.TokenType.BracketL)) {
                    expectsValue = true;
                }
                if (!node.addChild(this._parseLookupValue())) {
                    break;
                }
                expectsValue = false;
            }
            return !expectsValue;
        }
        _parseLookupValue() {
            const node = this.create(nodes.Node);
            const mark = this.mark();
            if (!this.accept(cssScanner_1.TokenType.BracketL)) {
                this.restoreAtMark(mark);
                return null;
            }
            if (((node.addChild(this._parseVariable(false, true)) ||
                node.addChild(this._parsePropertyIdentifier())) &&
                this.accept(cssScanner_1.TokenType.BracketR)) || this.accept(cssScanner_1.TokenType.BracketR)) {
                return node;
            }
            this.restoreAtMark(mark);
            return null;
        }
        _parseVariable(declaration = false, insideLookup = false) {
            const isPropertyReference = !declaration && this.peekDelim('$');
            if (!this.peekDelim('@') && !isPropertyReference && !this.peek(cssScanner_1.TokenType.AtKeyword)) {
                return null;
            }
            const node = this.create(nodes.Variable);
            const mark = this.mark();
            while (this.acceptDelim('@') || (!declaration && this.acceptDelim('$'))) {
                if (this.hasWhitespace()) {
                    this.restoreAtMark(mark);
                    return null;
                }
            }
            if (!this.accept(cssScanner_1.TokenType.AtKeyword) && !this.accept(cssScanner_1.TokenType.Ident)) {
                this.restoreAtMark(mark);
                return null;
            }
            if (!insideLookup && this.peek(cssScanner_1.TokenType.BracketL)) {
                if (!this._addLookupChildren(node)) {
                    this.restoreAtMark(mark);
                    return null;
                }
            }
            return node;
        }
        _parseTermExpression() {
            return this._parseVariable() ||
                this._parseEscaped() ||
                super._parseTermExpression() || // preference for colors before mixin references
                this._tryParseMixinReference(false);
        }
        _parseEscaped() {
            if (this.peek(cssScanner_1.TokenType.EscapedJavaScript) ||
                this.peek(cssScanner_1.TokenType.BadEscapedJavaScript)) {
                const node = this.createNode(nodes.NodeType.EscapedValue);
                this.consumeToken();
                return this.finish(node);
            }
            if (this.peekDelim('~')) {
                const node = this.createNode(nodes.NodeType.EscapedValue);
                this.consumeToken();
                if (this.accept(cssScanner_1.TokenType.String) || this.accept(cssScanner_1.TokenType.EscapedJavaScript)) {
                    return this.finish(node);
                }
                else {
                    return this.finish(node, cssErrors_1.ParseError.TermExpected);
                }
            }
            return null;
        }
        _parseOperator() {
            const node = this._parseGuardOperator();
            if (node) {
                return node;
            }
            else {
                return super._parseOperator();
            }
        }
        _parseGuardOperator() {
            if (this.peekDelim('>')) {
                const node = this.createNode(nodes.NodeType.Operator);
                this.consumeToken();
                this.acceptDelim('=');
                return node;
            }
            else if (this.peekDelim('=')) {
                const node = this.createNode(nodes.NodeType.Operator);
                this.consumeToken();
                this.acceptDelim('<');
                return node;
            }
            else if (this.peekDelim('<')) {
                const node = this.createNode(nodes.NodeType.Operator);
                this.consumeToken();
                this.acceptDelim('=');
                return node;
            }
            return null;
        }
        _parseRuleSetDeclaration() {
            if (this.peek(cssScanner_1.TokenType.AtKeyword)) {
                return this._parseKeyframe()
                    || this._parseMedia(true)
                    || this._parseImport()
                    || this._parseSupports(true) // @supports
                    || this._parseLayer() // @layer
                    || this._parsePropertyAtRule() // @property
                    || this._parseDetachedRuleSetMixin() // less detached ruleset mixin
                    || this._parseVariableDeclaration() // Variable declarations
                    || super._parseRuleSetDeclarationAtStatement();
            }
            return this._tryParseMixinDeclaration()
                || this._tryParseRuleset(true) // nested ruleset
                || this._tryParseMixinReference() // less mixin reference
                || this._parseFunction()
                || this._parseExtend() // less extend declaration
                || super._parseRuleSetDeclaration(); // try css ruleset declaration as the last option
        }
        _parseKeyframeIdent() {
            return this._parseIdent([nodes.ReferenceType.Keyframe]) || this._parseVariable();
        }
        _parseKeyframeSelector() {
            return this._parseDetachedRuleSetMixin() // less detached ruleset mixin
                || super._parseKeyframeSelector();
        }
        _parseSimpleSelectorBody() {
            return this._parseSelectorCombinator() || super._parseSimpleSelectorBody();
        }
        _parseSelector(isNested) {
            // CSS Guards
            const node = this.create(nodes.Selector);
            let hasContent = false;
            if (isNested) {
                // nested selectors can start with a combinator
                hasContent = node.addChild(this._parseCombinator());
            }
            while (node.addChild(this._parseSimpleSelector())) {
                hasContent = true;
                const mark = this.mark();
                if (node.addChild(this._parseGuard()) && this.peek(cssScanner_1.TokenType.CurlyL)) {
                    break;
                }
                this.restoreAtMark(mark);
                node.addChild(this._parseCombinator()); // optional
            }
            return hasContent ? this.finish(node) : null;
        }
        _parseSelectorCombinator() {
            if (this.peekDelim('&')) {
                const node = this.createNode(nodes.NodeType.SelectorCombinator);
                this.consumeToken();
                while (!this.hasWhitespace() && (this.acceptDelim('-') || this.accept(cssScanner_1.TokenType.Num) || this.accept(cssScanner_1.TokenType.Dimension) || node.addChild(this._parseIdent()) || this.acceptDelim('&'))) {
                    //  support &-foo
                }
                return this.finish(node);
            }
            return null;
        }
        _parseSelectorIdent() {
            if (!this.peekInterpolatedIdent()) {
                return null;
            }
            const node = this.createNode(nodes.NodeType.SelectorInterpolation);
            const hasContent = this._acceptInterpolatedIdent(node);
            return hasContent ? this.finish(node) : null;
        }
        _parsePropertyIdentifier(inLookup = false) {
            const propertyRegex = /^[\w-]+/;
            if (!this.peekInterpolatedIdent() && !this.peekRegExp(this.token.type, propertyRegex)) {
                return null;
            }
            const mark = this.mark();
            const node = this.create(nodes.Identifier);
            node.isCustomProperty = this.acceptDelim('-') && this.acceptDelim('-');
            let childAdded = false;
            if (!inLookup) {
                if (node.isCustomProperty) {
                    childAdded = this._acceptInterpolatedIdent(node);
                }
                else {
                    childAdded = this._acceptInterpolatedIdent(node, propertyRegex);
                }
            }
            else {
                if (node.isCustomProperty) {
                    childAdded = node.addChild(this._parseIdent());
                }
                else {
                    childAdded = node.addChild(this._parseRegexp(propertyRegex));
                }
            }
            if (!childAdded) {
                this.restoreAtMark(mark);
                return null;
            }
            if (!inLookup && !this.hasWhitespace()) {
                this.acceptDelim('+');
                if (!this.hasWhitespace()) {
                    this.acceptIdent('_');
                }
            }
            return this.finish(node);
        }
        peekInterpolatedIdent() {
            return this.peek(cssScanner_1.TokenType.Ident) ||
                this.peekDelim('@') ||
                this.peekDelim('$') ||
                this.peekDelim('-');
        }
        _acceptInterpolatedIdent(node, identRegex) {
            let hasContent = false;
            const indentInterpolation = () => {
                const pos = this.mark();
                if (this.acceptDelim('-')) {
                    if (!this.hasWhitespace()) {
                        this.acceptDelim('-');
                    }
                    if (this.hasWhitespace()) {
                        this.restoreAtMark(pos);
                        return null;
                    }
                }
                return this._parseInterpolation();
            };
            const accept = identRegex ?
                () => this.acceptRegexp(identRegex) :
                () => this.accept(cssScanner_1.TokenType.Ident);
            while (accept() ||
                node.addChild(this._parseInterpolation() ||
                    this.try(indentInterpolation))) {
                hasContent = true;
                if (this.hasWhitespace()) {
                    break;
                }
            }
            return hasContent;
        }
        _parseInterpolation() {
            // @{name} Variable or
            // ${name} Property
            const mark = this.mark();
            if (this.peekDelim('@') || this.peekDelim('$')) {
                const node = this.createNode(nodes.NodeType.Interpolation);
                this.consumeToken();
                if (this.hasWhitespace() || !this.accept(cssScanner_1.TokenType.CurlyL)) {
                    this.restoreAtMark(mark);
                    return null;
                }
                if (!node.addChild(this._parseIdent())) {
                    return this.finish(node, cssErrors_1.ParseError.IdentifierExpected);
                }
                if (!this.accept(cssScanner_1.TokenType.CurlyR)) {
                    return this.finish(node, cssErrors_1.ParseError.RightCurlyExpected);
                }
                return this.finish(node);
            }
            return null;
        }
        _tryParseMixinDeclaration() {
            const mark = this.mark();
            const node = this.create(nodes.MixinDeclaration);
            if (!node.setIdentifier(this._parseMixinDeclarationIdentifier()) || !this.accept(cssScanner_1.TokenType.ParenthesisL)) {
                this.restoreAtMark(mark);
                return null;
            }
            if (node.getParameters().addChild(this._parseMixinParameter())) {
                while (this.accept(cssScanner_1.TokenType.Comma) || this.accept(cssScanner_1.TokenType.SemiColon)) {
                    if (this.peek(cssScanner_1.TokenType.ParenthesisR)) {
                        break;
                    }
                    if (!node.getParameters().addChild(this._parseMixinParameter())) {
                        this.markError(node, cssErrors_1.ParseError.IdentifierExpected, [], [cssScanner_1.TokenType.ParenthesisR]);
                    }
                }
            }
            if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                this.restoreAtMark(mark);
                return null;
            }
            node.setGuard(this._parseGuard());
            if (!this.peek(cssScanner_1.TokenType.CurlyL)) {
                this.restoreAtMark(mark);
                return null;
            }
            return this._parseBody(node, this._parseMixInBodyDeclaration.bind(this));
        }
        _parseMixInBodyDeclaration() {
            return this._parseFontFace() || this._parseRuleSetDeclaration();
        }
        _parseMixinDeclarationIdentifier() {
            let identifier;
            if (this.peekDelim('#') || this.peekDelim('.')) {
                identifier = this.create(nodes.Identifier);
                this.consumeToken(); // # or .
                if (this.hasWhitespace() || !identifier.addChild(this._parseIdent())) {
                    return null;
                }
            }
            else if (this.peek(cssScanner_1.TokenType.Hash)) {
                identifier = this.create(nodes.Identifier);
                this.consumeToken(); // TokenType.Hash
            }
            else {
                return null;
            }
            identifier.referenceTypes = [nodes.ReferenceType.Mixin];
            return this.finish(identifier);
        }
        _parsePseudo() {
            if (!this.peek(cssScanner_1.TokenType.Colon)) {
                return null;
            }
            const mark = this.mark();
            const node = this.create(nodes.ExtendsReference);
            this.consumeToken(); // :
            if (this.acceptIdent('extend')) {
                return this._completeExtends(node);
            }
            this.restoreAtMark(mark);
            return super._parsePseudo();
        }
        _parseExtend() {
            if (!this.peekDelim('&')) {
                return null;
            }
            const mark = this.mark();
            const node = this.create(nodes.ExtendsReference);
            this.consumeToken(); // &
            if (this.hasWhitespace() || !this.accept(cssScanner_1.TokenType.Colon) || !this.acceptIdent('extend')) {
                this.restoreAtMark(mark);
                return null;
            }
            return this._completeExtends(node);
        }
        _completeExtends(node) {
            if (!this.accept(cssScanner_1.TokenType.ParenthesisL)) {
                return this.finish(node, cssErrors_1.ParseError.LeftParenthesisExpected);
            }
            const selectors = node.getSelectors();
            if (!selectors.addChild(this._parseSelector(true))) {
                return this.finish(node, cssErrors_1.ParseError.SelectorExpected);
            }
            while (this.accept(cssScanner_1.TokenType.Comma)) {
                if (!selectors.addChild(this._parseSelector(true))) {
                    return this.finish(node, cssErrors_1.ParseError.SelectorExpected);
                }
            }
            if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                return this.finish(node, cssErrors_1.ParseError.RightParenthesisExpected);
            }
            return this.finish(node);
        }
        _parseDetachedRuleSetMixin() {
            if (!this.peek(cssScanner_1.TokenType.AtKeyword)) {
                return null;
            }
            const mark = this.mark();
            const node = this.create(nodes.MixinReference);
            if (node.addChild(this._parseVariable(true)) && (this.hasWhitespace() || !this.accept(cssScanner_1.TokenType.ParenthesisL))) {
                this.restoreAtMark(mark);
                return null;
            }
            if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                return this.finish(node, cssErrors_1.ParseError.RightParenthesisExpected);
            }
            return this.finish(node);
        }
        _tryParseMixinReference(atRoot = true) {
            const mark = this.mark();
            const node = this.create(nodes.MixinReference);
            let identifier = this._parseMixinDeclarationIdentifier();
            while (identifier) {
                this.acceptDelim('>');
                const nextId = this._parseMixinDeclarationIdentifier();
                if (nextId) {
                    node.getNamespaces().addChild(identifier);
                    identifier = nextId;
                }
                else {
                    break;
                }
            }
            if (!node.setIdentifier(identifier)) {
                this.restoreAtMark(mark);
                return null;
            }
            let hasArguments = false;
            if (this.accept(cssScanner_1.TokenType.ParenthesisL)) {
                hasArguments = true;
                if (node.getArguments().addChild(this._parseMixinArgument())) {
                    while (this.accept(cssScanner_1.TokenType.Comma) || this.accept(cssScanner_1.TokenType.SemiColon)) {
                        if (this.peek(cssScanner_1.TokenType.ParenthesisR)) {
                            break;
                        }
                        if (!node.getArguments().addChild(this._parseMixinArgument())) {
                            return this.finish(node, cssErrors_1.ParseError.ExpressionExpected);
                        }
                    }
                }
                if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                    return this.finish(node, cssErrors_1.ParseError.RightParenthesisExpected);
                }
                identifier.referenceTypes = [nodes.ReferenceType.Mixin];
            }
            else {
                identifier.referenceTypes = [nodes.ReferenceType.Mixin, nodes.ReferenceType.Rule];
            }
            if (this.peek(cssScanner_1.TokenType.BracketL)) {
                if (!atRoot) {
                    this._addLookupChildren(node);
                }
            }
            else {
                node.addChild(this._parsePrio());
            }
            if (!hasArguments && !this.peek(cssScanner_1.TokenType.SemiColon) && !this.peek(cssScanner_1.TokenType.CurlyR) && !this.peek(cssScanner_1.TokenType.EOF)) {
                this.restoreAtMark(mark);
                return null;
            }
            return this.finish(node);
        }
        _parseMixinArgument() {
            // [variableName ':'] expression | variableName '...'
            const node = this.create(nodes.FunctionArgument);
            const pos = this.mark();
            const argument = this._parseVariable();
            if (argument) {
                if (!this.accept(cssScanner_1.TokenType.Colon)) {
                    this.restoreAtMark(pos);
                }
                else {
                    node.setIdentifier(argument);
                }
            }
            if (node.setValue(this._parseDetachedRuleSet() || this._parseExpr(true))) {
                return this.finish(node);
            }
            this.restoreAtMark(pos);
            return null;
        }
        _parseMixinParameter() {
            const node = this.create(nodes.FunctionParameter);
            // special rest variable: @rest...
            if (this.peekKeyword('@rest')) {
                const restNode = this.create(nodes.Node);
                this.consumeToken();
                if (!this.accept(lessScanner.Ellipsis)) {
                    return this.finish(node, cssErrors_1.ParseError.DotExpected, [], [cssScanner_1.TokenType.Comma, cssScanner_1.TokenType.ParenthesisR]);
                }
                node.setIdentifier(this.finish(restNode));
                return this.finish(node);
            }
            // special const args: ...
            if (this.peek(lessScanner.Ellipsis)) {
                const varargsNode = this.create(nodes.Node);
                this.consumeToken();
                node.setIdentifier(this.finish(varargsNode));
                return this.finish(node);
            }
            let hasContent = false;
            // default variable declaration: @param: 12 or @name
            if (node.setIdentifier(this._parseVariable())) {
                this.accept(cssScanner_1.TokenType.Colon);
                hasContent = true;
            }
            if (!node.setDefaultValue(this._parseDetachedRuleSet() || this._parseExpr(true)) && !hasContent) {
                return null;
            }
            return this.finish(node);
        }
        _parseGuard() {
            if (!this.peekIdent('when')) {
                return null;
            }
            const node = this.create(nodes.LessGuard);
            this.consumeToken(); // when
            node.isNegated = this.acceptIdent('not');
            if (!node.getConditions().addChild(this._parseGuardCondition())) {
                return this.finish(node, cssErrors_1.ParseError.ConditionExpected);
            }
            while (this.acceptIdent('and') || this.accept(cssScanner_1.TokenType.Comma)) {
                if (!node.getConditions().addChild(this._parseGuardCondition())) {
                    return this.finish(node, cssErrors_1.ParseError.ConditionExpected);
                }
            }
            return this.finish(node);
        }
        _parseGuardCondition() {
            if (!this.peek(cssScanner_1.TokenType.ParenthesisL)) {
                return null;
            }
            const node = this.create(nodes.GuardCondition);
            this.consumeToken(); // ParenthesisL
            if (!node.addChild(this._parseExpr())) {
                // empty (?)
            }
            if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                return this.finish(node, cssErrors_1.ParseError.RightParenthesisExpected);
            }
            return this.finish(node);
        }
        _parseFunction() {
            const pos = this.mark();
            const node = this.create(nodes.Function);
            if (!node.setIdentifier(this._parseFunctionIdentifier())) {
                return null;
            }
            if (this.hasWhitespace() || !this.accept(cssScanner_1.TokenType.ParenthesisL)) {
                this.restoreAtMark(pos);
                return null;
            }
            if (node.getArguments().addChild(this._parseMixinArgument())) {
                while (this.accept(cssScanner_1.TokenType.Comma) || this.accept(cssScanner_1.TokenType.SemiColon)) {
                    if (this.peek(cssScanner_1.TokenType.ParenthesisR)) {
                        break;
                    }
                    if (!node.getArguments().addChild(this._parseMixinArgument())) {
                        return this.finish(node, cssErrors_1.ParseError.ExpressionExpected);
                    }
                }
            }
            if (!this.accept(cssScanner_1.TokenType.ParenthesisR)) {
                return this.finish(node, cssErrors_1.ParseError.RightParenthesisExpected);
            }
            return this.finish(node);
        }
        _parseFunctionIdentifier() {
            if (this.peekDelim('%')) {
                const node = this.create(nodes.Identifier);
                node.referenceTypes = [nodes.ReferenceType.Function];
                this.consumeToken();
                return this.finish(node);
            }
            return super._parseFunctionIdentifier();
        }
        _parseURLArgument() {
            const pos = this.mark();
            const node = super._parseURLArgument();
            if (!node || !this.peek(cssScanner_1.TokenType.ParenthesisR)) {
                this.restoreAtMark(pos);
                const node = this.create(nodes.Node);
                node.addChild(this._parseBinaryExpr());
                return this.finish(node);
            }
            return node;
        }
    }
    exports.LESSParser = LESSParser;
});
