Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 8085)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 8086)
@@ -12,22 +12,23 @@
 import java.util.List;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.mappaint.Keyword;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
+import org.openstreetmap.josm.gui.mappaint.mapcss.LiteralExpression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSException;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule.Declaration;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
-import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory;
-import org.openstreetmap.josm.gui.mappaint.mapcss.LiteralExpression;
-import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSException;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Subpart;
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.Pair;
-import org.openstreetmap.josm.Main;
 
 /**
@@ -553,5 +554,5 @@
     Pair<Integer, Integer> r = null;
     List<Condition> conditions = new ArrayList<Condition>();
-    String sub = null;
+    Subpart sub = null;
 }
 {
@@ -708,11 +709,18 @@
 }
 
-String subpart() :
+Subpart subpart() :
 {
     String s;
+    Expression e;
 }
 {
     <DCOLON>
-    ( s=ident() { return s; } | <STAR> { return "*"; } )
+    (
+        s=ident() { return new Subpart.StringSubpart(s); }
+    |
+        <STAR> { return new Subpart.StringSubpart("*"); }
+    |
+        <LPAR> e=expression() <RPAR> { return new Subpart.ExpressionSubpart(e); }
+    )
 }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 8085)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 8086)
@@ -374,5 +374,6 @@
                         continue;
                     }
-                    env.layer = gs.getSubpart();
+                    env.layer = null;
+                    env.layer = gs.getSubpart().getId(env);
                     r.execute(env);
                 }
@@ -455,5 +456,6 @@
         for (MapCSSRule r : matchingRuleIndex.getRuleCandidates(osm)) {
             env.clearSelectorMatchingInformation();
-            env.layer = r.selector.getSubpart();
+            env.layer = null;
+            String sub = env.layer = r.selector.getSubpart().getId(env);
             if (r.selector.matches(env)) { // as side effect env.parent will be set (if s is a child selector)
                 Selector s = r.selector;
@@ -467,9 +469,5 @@
                 if (r.declaration.idx == lastDeclUsed) continue; // don't apply one declaration more than once
                 lastDeclUsed = r.declaration.idx;
-                String sub = s.getSubpart();
-                if (sub == null) {
-                    sub = "default";
-                }
-                else if ("*".equals(sub)) {
+                if ("*".equals(sub)) {
                     for (Entry<String, Cascade> entry : mc.getLayers()) {
                         env.layer = entry.getKey();
@@ -487,17 +485,24 @@
 
     public boolean evalMediaExpression(String feature, Object val) {
-        if ("user-agent".equals(feature)) {
-            String s = Cascade.convertTo(val, String.class);
-            if ("josm".equals(s)) return true;
-        }
-        if ("min-josm-version".equals(feature)) {
-            Float v = Cascade.convertTo(val, Float.class);
-            if (v != null) return Math.round(v) <= Version.getInstance().getVersion();
-        }
-        if ("max-josm-version".equals(feature)) {
-            Float v = Cascade.convertTo(val, Float.class);
-            if (v != null) return Math.round(v) >= Version.getInstance().getVersion();
-        }
-        return false;
+        if (feature == null) return false;
+        switch (feature) {
+            case "user-agent":
+            {
+                String s = Cascade.convertTo(val, String.class);
+                return "josm".equals(s);
+            }
+            case "min-josm-version":
+            {
+                Float v = Cascade.convertTo(val, Float.class);
+                return v != null && Math.round(v) <= Version.getInstance().getVersion();
+            }
+            case "max-josm-version":
+            {
+                Float v = Cascade.convertTo(val, Float.class);
+                return v != null && Math.round(v) >= Version.getInstance().getVersion();
+            }
+            default:
+                return false;
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 8085)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 8086)
@@ -50,5 +50,5 @@
     boolean matches(Environment env);
 
-    String getSubpart();
+    Subpart getSubpart();
 
     Range getRange();
@@ -372,5 +372,5 @@
 
         @Override
-        public String getSubpart() {
+        public Subpart getSubpart() {
             return right.getSubpart();
         }
@@ -453,5 +453,5 @@
 
         @Override
-        public String getSubpart() {
+        public Subpart getSubpart() {
             throw new UnsupportedOperationException("Not supported yet.");
         }
@@ -475,5 +475,5 @@
     public static class GeneralSelector extends OptimizedGeneralSelector {
 
-        public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
+        public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, Subpart subpart) {
             super(base, zoom, conds, subpart);
         }
@@ -497,7 +497,7 @@
         public final String base;
         public final Range range;
-        public final String subpart;
-
-        public OptimizedGeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
+        public final Subpart subpart;
+
+        public OptimizedGeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, Subpart subpart) {
             super(conds);
             this.base = base;
@@ -513,12 +513,12 @@
                 range = Range.ZERO_TO_INFINITY;
             }
-            this.subpart = subpart;
-        }
-
-        public OptimizedGeneralSelector(String base, Range range, List<Condition> conds, String subpart) {
+            this.subpart = subpart != null ? subpart : Subpart.DEFAULT_SUBPART;
+        }
+
+        public OptimizedGeneralSelector(String base, Range range, List<Condition> conds, Subpart subpart) {
             super(conds);
             this.base = base;
             this.range = range;
-            this.subpart = subpart;
+            this.subpart = subpart != null ? subpart : Subpart.DEFAULT_SUBPART;
         }
 
@@ -528,5 +528,5 @@
 
         @Override
-        public String getSubpart() {
+        public Subpart getSubpart() {
             return subpart;
         }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Subpart.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Subpart.java	(revision 8086)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Subpart.java	(revision 8086)
@@ -0,0 +1,48 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import org.openstreetmap.josm.gui.mappaint.Cascade;
+import org.openstreetmap.josm.gui.mappaint.Environment;
+
+/**
+ * A subpart identifies different rendering layers (<code>::subpart</code> syntax).
+ */
+public interface Subpart {
+    String getId(Environment env);
+
+    public static Subpart DEFAULT_SUBPART = new StringSubpart("default");
+
+    /**
+     * Simple static subpart identifier.
+     *
+     * E.g. ::layer_1
+     */
+    public static class StringSubpart implements Subpart {
+        private final String id;
+
+        public StringSubpart(String id) {
+            this.id = id;
+        }
+        @Override
+        public String getId(Environment env) {
+            return id;
+        }
+    }
+
+    /**
+     * Subpart identifier given by an expression.
+     *
+     * E.g. ::(concat("layer_", prop("i", "default")))
+     */
+    public static class ExpressionSubpart implements Subpart {
+        private final Expression id;
+
+        public ExpressionSubpart(Expression id) {
+            this.id = id;
+        }
+        @Override
+        public String getId(Environment env) {
+            return Cascade.convertTo(id.evaluate(env), String.class);
+        }
+    }
+}
