construct method
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);
}