function parse(encoded, expectedType, context) {
  switch (typeof encoded) {
    case 'boolean': {
      if (isType(expectedType, StringType)) {
        return new LiteralExpression(StringType, encoded ? 'true' : 'false');
      }
      if (!includesType(expectedType, BooleanType)) {
        throw new Error(
          `got a boolean, but expected ${typeName(expectedType)}`,
        );
      }
      return new LiteralExpression(BooleanType, encoded);
    }
    case 'number': {
      if (isType(expectedType, SizeType)) {
        return new LiteralExpression(SizeType, toSize(encoded));
      }
      if (isType(expectedType, BooleanType)) {
        return new LiteralExpression(BooleanType, !!encoded);
      }
      if (isType(expectedType, StringType)) {
        return new LiteralExpression(StringType, encoded.toString());
      }
      if (!includesType(expectedType, NumberType)) {
        throw new Error(`got a number, but expected ${typeName(expectedType)}`);
      }
      return new LiteralExpression(NumberType, encoded);
    }
    case 'string': {
      if (isType(expectedType, ColorType)) {
        return new LiteralExpression(ColorType, colorFromString(encoded));
      }
      if (isType(expectedType, BooleanType)) {
        return new LiteralExpression(BooleanType, !!encoded);
      }
      if (!includesType(expectedType, StringType)) {
        throw new Error(`got a string, but expected ${typeName(expectedType)}`);
      }
      return new LiteralExpression(StringType, encoded);
    }
    default: {
      // pass
    }
  }

  if (!Array.isArray(encoded)) {
    throw new Error('expression must be an array or a primitive value');
  }

  if (encoded.length === 0) {
    throw new Error('empty expression');
  }

  if (typeof encoded[0] === 'string') {
    return parseCallExpression(encoded, expectedType, context);
  }

  for (const item of encoded) {
    if (typeof item !== 'number') {
      throw new Error('expected an array of numbers');
    }
  }

  if (isType(expectedType, SizeType)) {
    if (encoded.length !== 2) {
      throw new Error(
        `expected an array of two values for a size, got ${encoded.length}`,
      );
    }
    return new LiteralExpression(SizeType, encoded);
  }

  if (isType(expectedType, ColorType)) {
    if (encoded.length === 3) {
      return new LiteralExpression(ColorType, [...encoded, 1]);
    }
    if (encoded.length === 4) {
      return new LiteralExpression(ColorType, encoded);
    }
    throw new Error(
      `expected an array of 3 or 4 values for a color, got ${encoded.length}`,
    );
  }

  if (!includesType(expectedType, NumberArrayType)) {
    throw new Error(
      `got an array of numbers, but expected ${typeName(expectedType)}`,
    );
  }

  return new LiteralExpression(NumberArrayType, encoded);
}
@param {EncodedExpression} encoded The encoded expression.
@param {number} expectedType The expected type.
@param {ParsingContext} context The parsing context.
@return {Expression} The parsed expression result.