eval method

  1. @override
Node eval (
  1. Contexts context
)
override

When evaluating a function call, we either find the function in functions 1, in which case we call it, passing the evaluated arguments, if this returns null or we cannot find the function, we simply print it out as it appeared originally 2.

The functions.dart file contains the built-in functions.

The reason why we evaluate the arguments, is in the case where we try to pass a variable to a function, like: saturate(@color). The function should receive the value, not the variable.

Implementation

@override
Node eval(Contexts context) {
  // Turn off math for calc(), and switch back on for evaluating nested functions
  final currentMathContext = context.mathOn;
  context.mathOn = !calc;
  if (calc || context.inCalc) context.enterCalc();

  final args = this.args.map((Node a) => a.eval(context)).toList();
  if (calc || context.inCalc) context.exitCalc();
  context.mathOn = currentMathContext;

  final funcCaller = FunctionCaller(name, context, index, currentFileInfo);

  dynamic _result;
  Node result;

  if (funcCaller.isValid()) {
    try {
      _result = funcCaller.call(args);
    } catch (e) {
      var message = LessError.getMessage(e);
      message = (message.isEmpty) ? '' : ': $message';
      final type = LessError.getType(e);

      final error = LessError.transform(e,
          type: (type?.isNotEmpty ?? false) ? type : 'Runtime',
          index: index,
          filename: currentFileInfo.filename,
          line: LessError.getErrorLine(e),
          column: LessError.getErrorColumn(e))
        ..message = 'error evaluating function `$name`$message';

      throw LessExceptionError(error);
    }

    if (_result != null) {
      // Results that that are not nodes are cast as Anonymous nodes
      // Falsy values or booleans are returned as empty nodes
      result = _result is Node
          ? _result
          : (_result is bool)
              ? Anonymous(null)
              : Anonymous(_result.toString());

      return result
        ..index = _index
        ..currentFileInfo = _fileInfo;
    }
  }

  return Call(name, args, index: index, currentFileInfo: currentFileInfo);

// 3.5.0 beta 20180625
//  Call.prototype.eval = function (context) {
//    /**
//     * Turn off math for calc(), and switch back on for evaluating nested functions
//     */
//    var currentMathContext = context.mathOn;
//    context.mathOn = !this.calc;
//    if (this.calc || context.inCalc) {
//      context.enterCalc();
//    }
//    var args = this.args.map(function (a) { return a.eval(context); });
//    if (this.calc || context.inCalc) {
//      context.exitCalc();
//    }
//    context.mathOn = currentMathContext;
//
//    var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
//
//    if (funcCaller.isValid()) {
//      try {
//        result = funcCaller.call(args);
//      } catch (e) {
//        throw {
//          type: e.type || 'Runtime',
//          message: 'error evaluating function `' + this.name + '`' +
//              (e.message ? ': ' + e.message : ''),
//          index: this.getIndex(),
//          filename: this.fileInfo().filename,
//          line: e.lineNumber,
//          column: e.columnNumber
//        };
//      }
//
//      if (result !== null && result !== undefined) {
//        // Results that that are not nodes are cast as Anonymous nodes
//        // Falsy values or booleans are returned as empty nodes
//        if (!(result instanceof Node)) {
//          if (!result || result === true) {
//            result = new Anonymous(null);
//          }
//          else {
//            result = new Anonymous(result.toString());
//          }
//
//        }
//        result._index = this._index;
//        result._fileInfo = this._fileInfo;
//        return result;
//      }
//
//    }
//
//    return new Call(this.name, args, this.getIndex(), this.fileInfo());
//  };
}