args method

MixinReturner args(
  1. {bool isCall = false}
)

Search for arguments in a Mixin Definition. So, in:

def-font(@name) {
  font-family: @name;
 }

@name is the args we are looking for.

Supports , or ; as arguments separator.

Implementation

MixinReturner args({bool isCall = false}) {
  Node arg;
  final argsComma = <MixinArgs>[];
  final argsSemiColon = <MixinArgs>[];
  var expand = false; // &1 {.m3(@x...)}
  var expressionContainsNamed = false;
  var expressions = <Node>[];
  var hasSep = true;
  String name;
  String nameLoop;
  var isSemiColonSeperated = false;
  final returner = MixinReturner();
  Node value;

  parserInput.save();

  while (true) {
    if (isCall) {
      arg = parsers.detachedRuleset() ?? parsers.expression();
    } else {
      parserInput.commentStore.length = 0;
      if (parserInput.$str('...') != null) {
        returner.variadic = true;
        if (parserInput.$char(';') != null && !isSemiColonSeperated) {
          isSemiColonSeperated = true;
        }
        if (isSemiColonSeperated) {
          argsSemiColon.add(MixinArgs(variadic: true));
        } else {
          argsComma.add(MixinArgs(variadic: true));
        }
        break;
      }
      arg = entities.variable() ??
          entities.property() ??
          entities.literal() ??
          entities.keyword() ??
          call(inValue: true);
    }

    if (arg == null || !hasSep) break;

    nameLoop = null;
    arg.throwAwayComments();
    value = arg;
    Node val;

    if (isCall) {
      // Variable
      if (arg.value != null && arg.value.length == 1) val = arg.value[0];
    } else {
      val = arg;
    }

    if (val != null && (val is Variable || val is Property)) {
      if (parserInput.$char(':') != null) {
        if (expressions.isNotEmpty) {
          if (isSemiColonSeperated) {
            parserInput.error('Cannot mix ; and , as delimiter types');
          }
          expressionContainsNamed = true;
        }

        value = parsers.detachedRuleset() ?? parsers.expression();

        if (value == null) {
          if (isCall) {
            parserInput
                .error('could not understand value for named argument');
          } else {
            parserInput.restore();
            returner.args = <MixinArgs>[];
            return returner;
          }
        }
        nameLoop = (name = val.name);
      } else if (parserInput.$str('...') != null) {
        if (!isCall) {
          returner.variadic = true;
          if (parserInput.$char(';') != null && !isSemiColonSeperated) {
            isSemiColonSeperated = true;
          }
          if (isSemiColonSeperated) {
            argsSemiColon.add(MixinArgs(name: arg.name, variadic: true));
          } else {
            argsComma.add(MixinArgs(name: arg.name, variadic: true));
          }
          break;
        } else {
          expand = true;
        }
      } else if (!isCall) {
        name = nameLoop = val.name;
        value = null;
      }
    }

    if (value != null) expressions.add(value);

    argsComma.add(MixinArgs(name: nameLoop, value: value, expand: expand));

    if (parserInput.$char(',') != null) {
      hasSep = true;
      continue;
    }

    hasSep = parserInput.$char(';') == ';';

    if (hasSep || isSemiColonSeperated) {
      if (expressionContainsNamed) {
        parserInput.error('Cannot mix ; and , as delimiter types');
      }

      isSemiColonSeperated = true;

      if (expressions.isNotEmpty) value = Value(expressions);
      argsSemiColon.add(MixinArgs(name: name, value: value, expand: expand));

      name = null;
      expressions = <Node>[];
      expressionContainsNamed = false;
    }
  }

  parserInput.forget();
  returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
  return returner;

// 3.5.0.beta.6 20180704
//  args: function (isCall) {
//      var entities = parsers.entities,
//          returner = { args:null, variadic: false },
//          expressions = [], argsSemiColon = [], argsComma = [],
//          isSemiColonSeparated, expressionContainsNamed, name, nameLoop,
//          value, arg, expand, hasSep = true;
//
//      parserInput.save();
//
//      while (true) {
//          if (isCall) {
//              arg = parsers.detachedRuleset() || parsers.expression();
//          } else {
//              parserInput.commentStore.length = 0;
//              if (parserInput.$str('...')) {
//                  returner.variadic = true;
//                  if (parserInput.$char(';') && !isSemiColonSeparated) {
//                      isSemiColonSeparated = true;
//                  }
//                  (isSemiColonSeparated ? argsSemiColon : argsComma)
//                      .push({ variadic: true });
//                  break;
//              }
//              arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true);
//          }
//
//          if (!arg || !hasSep) {
//              break;
//          }
//
//          nameLoop = null;
//          if (arg.throwAwayComments) {
//              arg.throwAwayComments();
//          }
//          value = arg;
//          var val = null;
//
//          if (isCall) {
//              // Variable
//              if (arg.value && arg.value.length == 1) {
//                  val = arg.value[0];
//              }
//          } else {
//              val = arg;
//          }
//
//          if (val && (val instanceof tree.Variable || val instanceof tree.Property)) {
//              if (parserInput.$char(':')) {
//                  if (expressions.length > 0) {
//                      if (isSemiColonSeparated) {
//                          error('Cannot mix ; and , as delimiter types');
//                      }
//                      expressionContainsNamed = true;
//                  }
//
//                  value = parsers.detachedRuleset() || parsers.expression();
//
//                  if (!value) {
//                      if (isCall) {
//                          error('could not understand value for named argument');
//                      } else {
//                          parserInput.restore();
//                          returner.args = [];
//                          return returner;
//                      }
//                  }
//                  nameLoop = (name = val.name);
//              } else if (parserInput.$str('...')) {
//                  if (!isCall) {
//                      returner.variadic = true;
//                      if (parserInput.$char(';') && !isSemiColonSeparated) {
//                          isSemiColonSeparated = true;
//                      }
//                      (isSemiColonSeparated ? argsSemiColon : argsComma)
//                          .push({ name: arg.name, variadic: true });
//                      break;
//                  } else {
//                      expand = true;
//                  }
//              } else if (!isCall) {
//                  name = nameLoop = val.name;
//                  value = null;
//              }
//          }
//
//          if (value) {
//              expressions.push(value);
//          }
//
//          argsComma.push({ name:nameLoop, value:value, expand:expand });
//
//          if (parserInput.$char(',')) {
//              hasSep = true;
//              continue;
//          }
//          hasSep = parserInput.$char(';') === ';';
//
//          if (hasSep || isSemiColonSeparated) {
//
//              if (expressionContainsNamed) {
//                  error('Cannot mix ; and , as delimiter types');
//              }
//
//              isSemiColonSeparated = true;
//
//              if (expressions.length > 1) {
//                  value = new(tree.Value)(expressions);
//              }
//              argsSemiColon.push({ name:name, value:value, expand:expand });
//
//              name = null;
//              expressions = [];
//              expressionContainsNamed = false;
//          }
//      }
//
//      parserInput.forget();
//      returner.args = isSemiColonSeparated ? argsSemiColon : argsComma;
//      return returner;
//  },
}