Bitcoin includes a scripting language, and its capabilities are far narrower than those of general-purpose contract platforms. The restrictions are choices, and each one buys a specific property.
Scripts specify conditions for spending
Every output is locked by a script describing what must be provided to spend it, and a spender supplies data satisfying that condition.
The common case requires a signature from a particular key, but scripts also express multiple signatures, time locks and hash preimages.
The script runs, produces a true or false result, and the transaction is valid or it is not. There is no partial success and no state left behind afterwards.
Because the outcome is a single boolean, the entire meaning of a script is whether a given set of inputs satisfies it, which is a far smaller thing to reason about than an arbitrary program.
No loops means bounded execution
The language has no facility for repetition, so a script's execution cost can be determined from its contents before it is run.
Any node can therefore reject an expensive script without executing it, and no transaction can consume unbounded resources.
Platforms that permit loops need a metering system to stop runaway execution, which is the problem gas was introduced to solve.
Scripts cannot read the world around them
A script sees the transaction it belongs to and nothing else. It cannot query balances elsewhere, read another output or access external data.
This means validation depends only on the transaction and the outputs it spends, so results are identical regardless of when or where verification happens.
It also rules out entire classes of contract that depend on shared mutable state, such as lending pools and automated market makers, which need to read balances that other transactions are changing.
The restrictions reduce the attack surface
Complex contract platforms have lost substantial sums to bugs in contracts that behaved as written but not as intended.
A language that cannot express complicated behaviour cannot express complicated mistakes, which is a meaningful benefit for a system whose priority is securing stored value.
The cost is that functionality other platforms offer natively has to be built in layers above.
Expressiveness is added carefully
Upgrades have extended what scripts can do, adding relative time locks, more efficient signature schemes and improved ways of committing to spending conditions.
Each addition is scrutinised at length, because a change to validation rules affects every participant and cannot easily be reversed.
The pattern is consistent: capability is added when it enables applications built above the base layer, rather than to make the base layer itself more general.