Not sure what you're after, but here's a way to get the desired behavior:
test[x0_] :=
Thread[ToExpression[#, StandardForm, Hold] & /@ x0, Hold] /.
Hold[exprs_] :>
Module @@ Hold[{a = 111, b = 222, x = x0}, exprs; Print[a, " ", b, " ", x]]
test[xxx]
(* 3 4 {a=3,b=a+1} *)
From the documentation for Module[{x, y, ...}, expr]
:
Before evaluating expr
, Module
substitutes new symbols for each of the local variables that appear anywhere in exp
r except as local variables in scoping constructs.
I would stress that the substitution is lexical; that is, the variables must literally appear in the unevaluated expr
, which does not happen in the original code.