Adding to the @lakier's answer and information you provided in its comment. State files are simply data structure generators, and salt use renderer pipes to decide how to produce data structures.
The default is jinja to yaml, which means jinja finish its jobs and the result is piped to yaml which then does its job, its represented as jinja | yaml. You can use this pipe to compose renderers and connect multiple renderers in a series as per your liking.
Here is a full list of renderers that you can use for reference to compose and create custom renderer, for instance, #!jinja|py
There is also a renderer function in slsutil execution module which can be used to write sls in python syntax, or any syntax you want, and pull it into jinja,
Example,
map.sls
#!py
def run():
apache = __salt__.grains.filter_by({
...normal map here but as a python dict...
}, merge=__salt__.pillar.get('apache:lookup'))
return apache
it can be accessed from any other sls file. The following is a usage example in Jinja,
{% set apache = salt.slsutil.renderer('map.sls') %}
You can also render directly from command-line using slsutil,
salt '*' slsutil.renderer /path/to/file
salt '*' slsutil.renderer /path/to/file.jinja 'jinja'
salt '*' slsutil.renderer /path/to/file.sls 'jinja|yaml'
salt '*' slsutil.renderer string='Inline template! {{ saltenv }}'
salt '*' slsutil.renderer string='Hello, {{ name }}.' name='world'