construct method

Expression construct(
  1. ExpressionType type,
  2. ExpressionToken token
)

A constructor of type, folded when its parts are constant.

Implementation

Expression construct(ExpressionType type, ExpressionToken token) {
  final parts = arguments();
  var components = 0;
  for (final part in parts) {
    if (!part.type.isNumeric) {
      fail(
        'a ${part.type} is not a number and cannot go in a $type.',
        where: token,
      );
    }
    components += part.type.components;
  }
  final dimension = parts.isEmpty
      ? Dimension.none
      : parts.first.type.dimension;
  if (parts.any((part) => part.type.dimension != dimension)) {
    fail(
      'the parts of a $type measure different things: '
      '${parts.map((part) => part.type.dimension).toSet().join(', ')}.',
      where: token,
    );
  }
  final typed = type.withDimension(dimension);
  // GLSL's own rule for the one-argument case: `vec3(1.0)` is every
  // component. Anything else has to add up exactly.
  if (parts.length == 1 && parts.single.type.components == 1) {
    final only = parts.single;
    if (only is ExpressionConstant) {
      return ExpressionConstant(
        List<double>.filled(type.components, only.value.single),
        typed,
      );
    }
    return ExpressionConstruct(
      List<Expression>.filled(type.components, only),
      typed,
    );
  }
  if (components != type.components) {
    fail(
      'a $type takes ${type.components} components and these add up to '
      '$components.',
      where: token,
    );
  }
  if (parts.every((p) => p is ExpressionConstant)) {
    return ExpressionConstant(<double>[
      for (final part in parts) ...(part as ExpressionConstant).value,
    ], typed);
  }
  return ExpressionConstruct(parts, typed);
}