fromJson_Gate = (json, context=new CustomGateSet()) => {
    let props = fromJson_Gate_props(json);

    try {
        if (props.matrix !== undefined) {
            return fromJson_Gate_Matrix(props);
        }

        if (props.circuit !== undefined) {
            return fromJson_Gate_Circuit(props, context);
        }

        // Operation not provided. Try to match by id.
        let match = Gates.findKnownGateById(props.id, context);
        if (match === undefined) {
            throw new DetailedError(`No gate with the id '${props.id}'.`, {json});
        }
        if (props.param !== undefined) {
            if (match.param === undefined) {
                throw new DetailedError("Arg for gate without arg.", {json});
            }
            match = match.withParam(props.param);
        }
        return match;

    } catch (ex) {
        notifyAboutRecoveryFromUnexpectedError(
            "Defaulted to a do-nothing 'parse error' gate. Failed to understand the json defining a gate.",
            {gate_json: json},
            ex);
        return new GateBuilder().
            setSerializedIdAndSymbol(props.id).
            setTitle("Parse Error").
            setBlurb(describe(ex)).
            promiseHasNoNetEffectOnStateVector().
            setExtraDisableReasonFinder(() => "parse\nerror").
            setTag(json).
            gate;
    }
}
@param {!object} json
@param {!CustomGateSet=} context
@returns {!Gate}
@throws {Error}