Upsampling before performing pulse shaping I know what an upsampler does. We insert L-1 zeros between the samples. As a result, it creates spectral repetitions. What if we have a symbol impulse stream and then we apply a Root Raised Cosine Filter, this would automatically perform pulse shaping. Why do we need to upsample that symbol stream to cause interpolation? The Pulse shaping filter is doing that.

Please explain intuitively if possible because I have been stuck on this topic for a while. Thank you in advance!
The reason is that you want to space the raised-cosine pulses by the symbol interval, $T_p$. Consider the signal you want to create: $$s(t) = \sum_k a_k p(t-kT_p),$$ where $p(t)$ is  your prototype raised-cosine pulse, and $a_k$ are the symbols. Notice that pulses are spaced $T_p$ seconds.

To re-create this with a filter, you can write the equation for the signal as follows: $$s(t)=\sum_k p(t) \ast a_k\delta(t-kT_p),$$ where $p(t)$ is interpreted as the filter's impulse response. Notice that the impulses are spaced $T_p$ seconds, and this results in the raised-cosine pulses being spaced by the same amount.

If you want to simulate this process in discrete-time in Matlab or similar tools, then you can create a vector p for $p(t)$, and a vector d for $a_k\delta(t-kT_p)$. Let's say your symbols are stored in vector a. Then, you can create d by upsampling a in such a way that there are $T_p$ seconds between symbols:

d = [ a[1], 0, ..., 0, a[2], 0, ..., 0, a[3], 0, .... ]


You need to insert as many 0s as necessary, according to your sampling frequency, to have $T_p$ seconds between symbols.

Then, you can generate the vector s corresponding to $s(t)$ with s=conv(p,d).