Index: /trunk/build.xml
===================================================================
--- /trunk/build.xml	(revision 3855)
+++ /trunk/build.xml	(revision 3856)
@@ -135,4 +135,14 @@
 		<delete dir="build" />
 		<delete dir="dist" />
+	</target>
+
+	<target name="javacc">
+		<exec executable="javacc">
+			<arg value="-debug_parser=false"/>
+			<arg value="-debug_lookahead=false"/>
+			<arg value="-debug_token_manager=false"/>
+			<arg value="-output_directory=${src.dir}/org/openstreetmap/josm/gui/mappaint/mapcss/parser"/>
+			<arg value="${src.dir}/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj"/>
+		</exec>
 	</target>
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 3856)
@@ -21,5 +21,5 @@
 
     public static AreaElemStyle create(Cascade c) {
-        Color color = c.getColor("fill-color", null);
+        Color color = c.get("fill-color", null, Color.class);
         if (color == null)
             return null;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/Cascade.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/Cascade.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/Cascade.java	(revision 3856)
@@ -5,4 +5,5 @@
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
@@ -26,5 +27,5 @@
      *      value, def otherwise
      */
-    public <T> T get(String key, T def, Class klass) {
+    public <T> T get(String key, T def, Class<T> klass) {
         if (def != null && !klass.isInstance(def))
             throw new IllegalArgumentException();
@@ -32,10 +33,10 @@
         if (o == null)
             return def;
-        if (klass.isInstance(o)) {
-            @SuppressWarnings("unchecked") T res = (T) klass.cast(o);
+        T res = convertTo(o, klass);
+        if (res == null) {
+            System.err.println(String.format("Warning: unable to convert property %s to type %s: found %s of type %s!", key, klass, o, o.getClass()));
+            return def;
+        } else
             return res;
-        }
-        System.err.println(String.format("Warning: wrong type for mappaint property %s: %s expected, but %s of type %s found!", key, klass, o, o.getClass()));
-        return def;
     }
 
@@ -44,29 +45,84 @@
     }
 
-    public Float getFloat(String key, Float def) {
-        Object o = prop.get(key);
+    @SuppressWarnings("unchecked")
+    public static <T> T convertTo(Object o, Class<T> klass) {
         if (o == null)
-            return def;
+            return null;
+        if (klass.isInstance(o))
+            return (T) o;
+
+        if (klass == float.class || klass == Float.class)
+            return (T) toFloat(o);
+
+        if (klass == double.class || klass == Double.class) {
+            o = toFloat(o);
+            if (o != null) {
+                o = new Double((Float) o);
+            }
+            return (T) o;
+        }
+
+        if (klass == boolean.class || klass == Boolean.class)
+            return (T) toBool(o);
+
+        if (klass == float[].class) {
+            return (T) toFloatArray(o);
+        }
+
+        if (klass == Color.class) {
+            return (T) toColor(o);
+        }
+        return null;
+    }
+
+    private static Float toFloat(Object o) {
         if (o instanceof Float)
             return (Float) o;
+        if (o instanceof Double)
+            return new Float((Double) o);
         if (o instanceof Integer)
             return new Float((Integer) o);
-        return def;
+        if (o instanceof String) {
+            try {
+                float f = Float.parseFloat((String) o);
+                return f;
+            } catch (NumberFormatException e) {
+            }
+        }
+        return null;
     }
 
-    public Color getColor(String key, Color def) {
-        Object o = prop.get(key);
-        if (o == null)
-            return def;
+    private static Boolean toBool(Object o) {
+        if (o instanceof Boolean)
+            return (Boolean) o;
+        if (o instanceof String)
+            return Boolean.parseBoolean((String) o);
+        return null;
+    }
+
+    private static float[] toFloatArray(Object o) {
+        if (o instanceof float[])
+            return (float[]) o;
+        if (o instanceof List) {
+            List l = (List) o;
+            float[] a = new float[l.size()];
+            for (int i=0; i<l.size(); ++i) {
+                Float f = toFloat(l.get(i));
+                if (f == null)
+                    return null;
+                else
+                    a[i] = f;
+            }
+            return a;
+        }
+        return null;
+    }
+
+     public static Color toColor(Object o) {
         if (o instanceof Color)
             return (Color) o;
-        if (o instanceof String) {
-            Color clr = CSSColors.get((String) o);
-            if (clr != null)
-                return clr;
-            else
-                return def;
-        }
-        return def;
+        if (o instanceof String)
+            return CSSColors.get((String) o);
+        return null;
     }
 
@@ -111,3 +167,7 @@
         return res.append("}").toString();
     }
+
+    public boolean containsKey(String key) {
+        return prop.containsKey(key);
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 3856)
@@ -17,6 +17,6 @@
 
     protected ElemStyle(Cascade c) {
-        z_index = c.getFloat("z-index", 0f);
-        object_z_index = c.getFloat("object-z-index", 0f);
+        z_index = c.get("z-index", 0f, Float.class);
+        object_z_index = c.get("object-z-index", 0f, Float.class);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 3856)
@@ -48,12 +48,12 @@
 
     private static LineElemStyle createImpl(Cascade c, String prefix) {
-        Float width = c.getFloat(prefix + "width", null);
+        Float width = c.get(prefix + "width", null, Float.class);
         if (width == null)
             return null;
 
-        float realWidth = c.getFloat(prefix + "real-width", 0f);
-        Color color = c.getColor(prefix + "color", null);
+        float realWidth = c.get(prefix + "real-width", 0f, Float.class);
+        Color color = c.get(prefix + "color", null, Color.class);
         if (color == null) {
-            color = c.getColor(prefix + "fill-color", null);
+            color = c.get(prefix + "fill-color", null, Color.class);
         }
         if (color == null) {
@@ -61,5 +61,20 @@
         }
         float[] dashes = c.get(prefix + "dashes", null, float[].class);
-        Color dashesBackground = c.getColor(prefix + "dashes-background-color", null);
+        if (dashes != null) {
+            boolean hasPositive = false;
+            for (float f : dashes) {
+                if (f > 0) {
+                    hasPositive = true;
+                }
+                if (f < 0) {
+                    dashes = null;
+                    break;
+                }
+            }
+            if (!hasPositive) {
+                dashes = null;
+            }
+        }
+        Color dashesBackground = c.get(prefix + "dashes-background-color", null, Color.class);
 
         return new LineElemStyle(c, width, realWidth, color, dashes, dashesBackground);
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 3856)
@@ -2,5 +2,4 @@
 package org.openstreetmap.josm.gui.mappaint.mapcss;
 
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
@@ -9,5 +8,5 @@
 abstract public class Condition {
 
-    abstract public boolean applies(OsmPrimitive osm);
+    abstract public boolean applies(Environment e);
 
     public static enum Op {EQ, NEQ}
@@ -27,10 +26,10 @@
 
         @Override
-        public boolean applies(OsmPrimitive osm) {
+        public boolean applies(Environment e) {
             switch (op) {
                 case EQ:
-                    return Utils.equal(osm.get(k), v);
+                    return Utils.equal(e.osm.get(k), v);
                 case NEQ:
-                    return !Utils.equal(osm.get(k), v);
+                    return !Utils.equal(e.osm.get(k), v);
                 default:
                     throw new AssertionError();
@@ -55,6 +54,6 @@
 
         @Override
-        public boolean applies(OsmPrimitive osm) {
-            return osm.hasKey(k) ^ not;
+        public boolean applies(Environment e) {
+            return e.osm.hasKey(k) ^ not;
         }
 
@@ -76,9 +75,9 @@
 
         @Override
-        public boolean applies(OsmPrimitive osm) {
+        public boolean applies(Environment e) {
             if ("closed".equals(id)) {
-                if (osm instanceof Way && ((Way) osm).isClosed())
+                if (e.osm instanceof Way && ((Way) e.osm).isClosed())
                     return true;
-                if (osm instanceof Relation && ((Relation) osm).isMultipolygon())
+                if (e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon())
                     return true;
                 return false;
@@ -92,4 +91,26 @@
         }
     }
+    
+    public static class ExpressionCondition extends Condition {
+
+        private Expression e;
+
+        public ExpressionCondition(Expression e) {
+            this.e = e;
+        }
+
+        @Override
+        public boolean applies(Environment env) {
+            Object o = e.evaluate(env);
+            if (o instanceof Boolean)
+                return (Boolean) o;
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "[" + e + "]";
+        }
+    }
 
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(revision 3856)
@@ -2,7 +2,16 @@
 package org.openstreetmap.josm.gui.mappaint.mapcss;
 
+import java.awt.Color;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.search.SearchCompiler;
+import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
+import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
 import org.openstreetmap.josm.gui.mappaint.Cascade;
 import org.openstreetmap.josm.tools.Utils;
@@ -43,53 +52,209 @@
         }
 
-        @Override
-        public Object evaluate(Environment env) {
-            if (name.equals("eval")) {
-                if (args.size() != 1) {
+        public static class EvalFunctions {
+            Environment env;
+
+            public Object eval(Object o) {
+                return o;
+            }
+
+            public static float plus(float... args) {
+                float res = 0;
+                for (float f : args) {
+                    res += f;
+                }
+                return res;
+            }
+
+            public Float minus(float... args) {
+                if (args.length == 0)
+                    return 0f;
+                float res = args[0];
+                for (int i=1; i<args.length; ++i) {
+                    res -= args[i];
+                }
+                return res;
+            }
+
+            public static float times(float... args) {
+                float res = 1;
+                for (float f : args) {
+                    res *= f;
+                }
+                return res;
+            }
+
+            public Float devided_by(float... args) {
+                if (args.length == 0)
+                    return 1f;
+                float res = args[0];
+                for (int i=1; i<args.length; ++i) {
+                    if (args[i] == 0f)
+                        return null;
+                    res /= args[i];
+                }
+                return res;
+            }
+
+            public static List list(Object... args) {
+                return Arrays.asList(args);
+            }
+
+            public Color rgb(float r, float g, float b) {
+                Color c = null;
+                try {
+                    c = new Color(r, g, b);
+                } catch (IllegalArgumentException e) {
                     return null;
                 }
-                return args.get(0).evaluate(env);
-            }
-            
-            if (name.equals("prop")) {
-                if (!(args.size() == 1 || args.size() == 2))
-                    return null;
-                Object pr = args.get(0).evaluate(env);
-                if (!(pr instanceof String))
-                    return null;
+                return c;
+            }
+
+            public Object prop(String key) {
+                return prop(key, null);
+            }
+
+            public Object prop(String key, String layer) {
                 Cascade c;
-                if (args.size() == 1) {
+                if (layer == null) {
                     c = env.getCascade();
                 } else {
-                    Object layer = args.get(1).evaluate(env);
-                    if (!(layer instanceof String))
-                        return null;
-                    c = env.mc.getCascade((String) layer);
-                }
-                return c.get((String) pr);
-            }
-            if (name.equals("+") || name.equals("*")) {
-                float result = name.equals("+") ? 0f : 1f;
-                for (Expression exp : args) {
-                    Float f = getFloat(exp.evaluate(env));
-                    if (f == null)
-                        return null;
-                    if (name.equals("+")) {
-                        result += f;
-                    } else {
-                        result *= f;
+                    c = env.mc.getCascade(layer);
+                }
+                return c.get(key);
+            }
+
+            public Boolean is_prop_set(String key) {
+                return is_prop_set(key, null);
+            }
+
+            public Boolean is_prop_set(String key, String layer) {
+                Cascade c;
+                if (layer == null) {
+                    c = env.getCascade();
+                } else {
+                    c = env.mc.getCascade(layer);
+                }
+                return c.containsKey(key);
+            }
+
+            public Object cond(boolean cond, Object if_, Object else_) {
+                return cond ? if_ : else_; // fixme: do not evaluate the other branch
+            }
+
+            public boolean not(boolean b) {
+                return !b;
+            }
+
+            public boolean and(boolean... bs) {
+                for (boolean b : bs) {  // fixme: lazy evaluation
+                    if (!b)
+                        return false;
+                }
+                return true;
+            }
+
+            public boolean or(boolean... bs) {
+                for (boolean b : bs) {
+                    if (b)
+                        return true;
+                }
+                return false;
+            }
+
+            public Boolean JOSM_search(String s) {
+                Match m;
+                try {
+                    m = SearchCompiler.compile(s, false, false);
+                } catch (ParseError ex) {
+                    return null;
+                }
+                return m.match(env.osm);
+            }
+
+            public String JOSM_pref(String s, String def) {
+                String res = Main.pref.get(s, null);
+                return res != null ? res : def;
+            }
+
+            public Color JOSM_pref_color(String s, Color def) {
+                Color res = Main.pref.getColor(s, null);
+                return res != null ? res : def;
+            }
+        }
+
+        @Override
+        public Object evaluate(Environment env) {
+            EvalFunctions fn = new EvalFunctions();
+            fn.env = env;
+            Method[] customMethods = EvalFunctions.class.getDeclaredMethods();
+            List<Method> allMethods = new ArrayList<Method>();
+            allMethods.addAll(Arrays.asList(customMethods));
+            try {
+                allMethods.add(Math.class.getMethod("abs", float.class));
+                allMethods.add(Math.class.getMethod("acos", double.class));
+                allMethods.add(Math.class.getMethod("asin", double.class));
+                allMethods.add(Math.class.getMethod("atan", double.class));
+                allMethods.add(Math.class.getMethod("atan2", double.class, double.class));
+                allMethods.add(Math.class.getMethod("ceil", double.class));
+                allMethods.add(Math.class.getMethod("cos", double.class));
+                allMethods.add(Math.class.getMethod("cosh", double.class));
+                allMethods.add(Math.class.getMethod("exp", double.class));
+                allMethods.add(Math.class.getMethod("floor", double.class));
+                allMethods.add(Math.class.getMethod("log", double.class));
+                allMethods.add(Math.class.getMethod("max", float.class, float.class));
+                allMethods.add(Math.class.getMethod("min", float.class, float.class));
+                allMethods.add(Math.class.getMethod("random"));
+                allMethods.add(Math.class.getMethod("round", float.class));
+                allMethods.add(Math.class.getMethod("signum", double.class));
+                allMethods.add(Math.class.getMethod("sin", double.class));
+                allMethods.add(Math.class.getMethod("sinh", double.class));
+                allMethods.add(Math.class.getMethod("sqrt", double.class));
+                allMethods.add(Math.class.getMethod("tan", double.class));
+                allMethods.add(Math.class.getMethod("tanh", double.class));
+            } catch (NoSuchMethodException ex) {
+                throw new RuntimeException(ex);
+            } catch (SecurityException ex) {
+                throw  new RuntimeException(ex);
+            }
+            for (Method m : allMethods) {
+                if (!m.getName().equals(name))
+                    continue;
+                Class<?>[] expectedParameterTypes = m.getParameterTypes();
+                Object[] convertedArgs = new Object[expectedParameterTypes.length];
+
+                if (expectedParameterTypes.length == 1 && expectedParameterTypes[0].isArray())
+                {
+                    Class<?> arrayComponentType = expectedParameterTypes[0].getComponentType();
+                    Object arrayArg = Array.newInstance(arrayComponentType, args.size());
+                    for (int i=0; i<args.size(); ++i)
+                    {
+                        Object o = Cascade.convertTo(args.get(i).evaluate(env), arrayComponentType);
+                        if (o == null)
+                            return null;
+                        Array.set(arrayArg, i, o);
                     }
+                    convertedArgs[0] = arrayArg;
+                } else {
+                    if (args.size() != expectedParameterTypes.length)
+                        continue;
+                    for (int i=0; i<args.size(); ++i) {
+                        convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
+                        if (convertedArgs[i] == null)
+                            return null;
+                    }
+                }
+                Object result = null;
+                try {
+                    result = m.invoke(fn, convertedArgs);
+                } catch (IllegalAccessException ex) {
+                    throw new RuntimeException(ex);
+                } catch (IllegalArgumentException ex) {
+                    throw new RuntimeException(ex);
+                } catch (InvocationTargetException ex) {
+                    System.err.println(ex);
+                    return null;
                 }
                 return result;
-            }
-            if (name.equals("-")) {
-                if (args.size() != 2) {
-                    return null;
-                }
-                Float fst = getFloat(args.get(0).evaluate(env));
-                Float snd = getFloat(args.get(1).evaluate(env));
-                if (fst == null || snd == null)
-                    return null;
-                return fst - snd;
             }
             return null;
@@ -101,11 +266,4 @@
         }
 
-        static Float getFloat(Object o) {
-            if (o instanceof Float)
-                return (Float) o;
-            if (o instanceof Integer)
-                return new Float((Integer) o);
-            return null;
-        }
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 3856)
@@ -87,5 +87,5 @@
                 if (s.base.equals("meta")) {
                     for (Condition cnd : s.conds) {
-                        if (!cnd.applies(n))
+                        if (!cnd.applies(env))
                             continue NEXT_RULE;
                     }
@@ -105,7 +105,8 @@
     @Override
     public void apply(MultiCascade mc, OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed) {
+        Environment env = new Environment(osm, mc, null);
         for (MapCSSRule r : rules) {
             for (Selector s : r.selectors) {
-                if (s.applies(osm)) {
+                if (s.applies(env)) {
                     if (s.range.contains(scale)) {
                         mc.range = Range.cut(mc.range, s.range);
@@ -130,7 +131,7 @@
                     }
 
-                    if (sub.equals("*")) {
+                    if (sub.equals("*")) { // fixme: proper subparts handling
                         for (Entry<String, Cascade> entry : mc.entrySet()) {
-                            Environment env = new Environment(osm, mc, entry.getKey());
+                            env.layer = entry.getKey();
                             for (Instruction i : r.declaration) {
                                 i.execute(env);
@@ -138,5 +139,5 @@
                         }
                     } else {
-                        Environment env = new Environment(osm, mc, sub);
+                        env.layer = sub;
                         for (Instruction i : r.declaration) {
                             i.execute(env);
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 3856)
@@ -34,9 +34,9 @@
     }
 
-    public boolean applies(OsmPrimitive osm) {
-        if (!baseApplies(osm))
+    public boolean applies(Environment e) {
+        if (!baseApplies(e.osm))
             return false;
         for (Condition c : conds) {
-            if (!c.applies(osm))
+            if (!c.applies(e))
                 return false;
         }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.java	(revision 3856)
@@ -33,7 +33,7 @@
  *       |            |                   |
  *     zoom       condition          instruction
- *     
+ *
  * more general:
- * 
+ *
  * way|z13-[a=b][c=d]::subpart, way|z-3[u=v]:closed::subpart2 { p1 : val; p2 : val; }
  *
@@ -141,5 +141,5 @@
  * comma delimited list of floats (at least 2, all >= 0)
  */
-  final public float[] float_array() throws ParseException {
+  final public List<Float> float_array() throws ParseException {
     float f;
     List<Float> fs = new ArrayList<Float>();
@@ -161,9 +161,5 @@
       }
     }
-        float[] a = new float[fs.size()];
-        for (int i=0; i<fs.size(); ++i) {
-            a[i] = fs.get(i);
-        }
-        {if (true) return a;}
+        {if (true) return fs;}
     throw new Error("Missing return statement in function");
   }
@@ -323,44 +319,74 @@
 
   final public Condition condition() throws ParseException {
+    Condition c;
+    Expression e;
+    jj_consume_token(LSQUARE);
+    if (jj_2_1(2)) {
+      c = simple_key_condition();
+      jj_consume_token(RSQUARE);
+                                                   {if (true) return c;}
+    } else if (jj_2_2(3)) {
+      c = simple_key_value_condition();
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case IDENT:
+      case UINT:
+      case UFLOAT:
+      case STRING:
+      case HEXCOLOR:
+      case LPAR:
+      case PLUS:
+      case MINUS:
+        e = expression();
+                             c = new Condition.ExpressionCondition(e);
+        break;
+      default:
+        jj_la1[16] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    jj_consume_token(RSQUARE);
+      {if (true) return c;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Condition simple_key_condition() throws ParseException {
+    boolean not = false;
+    String key;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case EXCLAMATION:
+      jj_consume_token(EXCLAMATION);
+                      not = true;
+      break;
+    default:
+      jj_la1[17] = jj_gen;
+      ;
+    }
+    key = string_or_ident();
+      {if (true) return new Condition.KeyCondition(key, not);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Condition simple_key_value_condition() throws ParseException {
     boolean not = false;
     String key;
     String val;
-    jj_consume_token(LSQUARE);
-    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-    case EXCLAMATION:
-      jj_consume_token(EXCLAMATION);
-                      not = true;
-      break;
-    default:
-      jj_la1[16] = jj_gen;
-      ;
-    }
     key = string_or_ident();
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case EXCLAMATION_EQUAL:
+      jj_consume_token(EXCLAMATION_EQUAL);
+                            not = true;
+      break;
     case EQUAL:
-    case EXCLAMATION_EQUAL:
-      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case EXCLAMATION_EQUAL:
-        jj_consume_token(EXCLAMATION_EQUAL);
-                                not = true;
-        break;
-      case EQUAL:
-        jj_consume_token(EQUAL);
-        break;
-      default:
-        jj_la1[17] = jj_gen;
-        jj_consume_token(-1);
-        throw new ParseException();
-      }
-      val = string_or_ident();
-      jj_consume_token(RSQUARE);
-          {if (true) return new Condition.KeyValueCondition(key, val, not ? Condition.Op.NEQ : Condition.Op.EQ);}
+      jj_consume_token(EQUAL);
       break;
     default:
       jj_la1[18] = jj_gen;
-      ;
-    }
-    jj_consume_token(RSQUARE);
-      {if (true) return new Condition.KeyCondition(key, not);}
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    val = string_or_ident();
+      {if (true) return new Condition.KeyValueCondition(key, val, not ? Condition.Op.NEQ : Condition.Op.EQ);}
     throw new Error("Missing return statement in function");
   }
@@ -373,5 +399,5 @@
     case EXCLAMATION:
       jj_consume_token(EXCLAMATION);
-                              not = true;
+                      not = true;
       break;
     default:
@@ -460,5 +486,5 @@
     jj_consume_token(COLON);
     w();
-    if (jj_2_1(2)) {
+    if (jj_2_3(2)) {
       val = float_array();
       w();
@@ -498,6 +524,9 @@
     case STAR:
     case SLASH:
+    case PIPE:
     case PLUS:
     case MINUS:
+    case AMPERSAND:
+    case QUESTION:
       switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
       case PLUS:
@@ -505,8 +534,8 @@
         while (true) {
           jj_consume_token(PLUS);
-                       op = "+";
+                       op = "plus";
           w();
           e = primary();
-                                                     args.add(e);
+                                                        args.add(e);
           w();
           switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
@@ -524,8 +553,8 @@
         while (true) {
           jj_consume_token(STAR);
-                       op = "*";
+                       op = "times";
           w();
           e = primary();
-                                                     args.add(e);
+                                                         args.add(e);
           w();
           switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
@@ -540,21 +569,74 @@
         break;
       case MINUS:
-        jj_consume_token(MINUS);
-                        op = "-";
+        label_9:
+        while (true) {
+          jj_consume_token(MINUS);
+                        op = "minus";
+          w();
+          e = primary();
+                                                          args.add(e);
+          w();
+          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+          case MINUS:
+            ;
+            break;
+          default:
+            jj_la1[27] = jj_gen;
+            break label_9;
+          }
+        }
+        break;
+      case SLASH:
+        label_10:
+        while (true) {
+          jj_consume_token(SLASH);
+                        op = "divided_by";
+          w();
+          e = primary();
+                                                               args.add(e);
+          w();
+          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+          case SLASH:
+            ;
+            break;
+          default:
+            jj_la1[28] = jj_gen;
+            break label_10;
+          }
+        }
+        break;
+      case AMPERSAND:
+        jj_consume_token(AMPERSAND);
+        jj_consume_token(AMPERSAND);
+                                        op = "and";
         w();
         e = primary();
-                                                      args.add(e);
+                                                                        args.add(e);
         w();
         break;
-      case SLASH:
-        jj_consume_token(SLASH);
-                        op = "/";
+      case PIPE:
+        jj_consume_token(PIPE);
+        jj_consume_token(PIPE);
+                              op = "or";
         w();
         e = primary();
-                                                      args.add(e);
+                                                             args.add(e);
         w();
         break;
+      case QUESTION:
+        jj_consume_token(QUESTION);
+                           op = "cond";
+        w();
+        e = primary();
+                                                            args.add(e);
+        w();
+        jj_consume_token(COLON);
+        w();
+        e = primary();
+                                                                                                         args.add(e);
+        w();
+        break;
       default:
-        jj_la1[27] = jj_gen;
+        jj_la1[29] = jj_gen;
         jj_consume_token(-1);
         throw new ParseException();
@@ -562,8 +644,8 @@
       break;
     default:
-      jj_la1[28] = jj_gen;
+      jj_la1[30] = jj_gen;
       ;
     }
-        if (args.size() == 1)
+        if (op == null)
             {if (true) return args.get(0);}
         {if (true) return new FunctionExpression(op, args);}
@@ -575,5 +657,5 @@
     FunctionExpression fn;
     Object lit;
-    if (jj_2_2(2)) {
+    if (jj_2_4(2)) {
       // both function and identifier start with an identifier
               fn = function();
@@ -599,5 +681,5 @@
         break;
       default:
-        jj_la1[29] = jj_gen;
+        jj_la1[31] = jj_gen;
         jj_consume_token(-1);
         throw new ParseException();
@@ -617,20 +699,34 @@
     jj_consume_token(LPAR);
     w();
-    arg = expression();
-                       args.add(arg);
-    label_9:
-    while (true) {
-      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case COMMA:
-        ;
-        break;
-      default:
-        jj_la1[30] = jj_gen;
-        break label_9;
-      }
-      jj_consume_token(COMMA);
-      w();
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case IDENT:
+    case UINT:
+    case UFLOAT:
+    case STRING:
+    case HEXCOLOR:
+    case LPAR:
+    case PLUS:
+    case MINUS:
       arg = expression();
-                                     args.add(arg);
+                           args.add(arg);
+      label_11:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case COMMA:
+          ;
+          break;
+        default:
+          jj_la1[32] = jj_gen;
+          break label_11;
+        }
+        jj_consume_token(COMMA);
+        w();
+        arg = expression();
+                                         args.add(arg);
+      }
+      break;
+    default:
+      jj_la1[33] = jj_gen;
+      ;
     }
     jj_consume_token(RPAR);
@@ -675,5 +771,5 @@
       break;
     default:
-      jj_la1[31] = jj_gen;
+      jj_la1[34] = jj_gen;
       jj_consume_token(-1);
       throw new ParseException();
@@ -705,57 +801,82 @@
   }
 
-  private boolean jj_3R_15() {
+  private boolean jj_2_3(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_3(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(2, xla); }
+  }
+
+  private boolean jj_2_4(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_4(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(3, xla); }
+  }
+
+  private boolean jj_3R_13() {
+    if (jj_3R_17()) return true;
     Token xsp;
     xsp = jj_scanpos;
-    if (jj_scan_token(7)) {
+    if (jj_3R_18()) {
     jj_scanpos = xsp;
-    if (jj_3R_16()) return true;
-    }
+    if (jj_scan_token(16)) return true;
+    }
+    if (jj_3R_17()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_20() {
+    if (jj_scan_token(COMMA)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_16() {
+    if (jj_scan_token(EXCLAMATION)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_25() {
+    if (jj_scan_token(STRING)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_12() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_16()) jj_scanpos = xsp;
+    if (jj_3R_17()) return true;
     return false;
   }
 
   private boolean jj_3R_14() {
+    if (jj_3R_19()) return true;
     Token xsp;
+    if (jj_3R_20()) return true;
     while (true) {
       xsp = jj_scanpos;
-      if (jj_3R_15()) { jj_scanpos = xsp; break; }
-    }
-    return false;
-  }
-
-  private boolean jj_3_2() {
-    if (jj_3R_11()) return true;
-    return false;
-  }
-
-  private boolean jj_3R_13() {
-    if (jj_scan_token(COMMA)) return true;
-    return false;
-  }
-
-  private boolean jj_3R_10() {
-    if (jj_3R_12()) return true;
-    Token xsp;
-    if (jj_3R_13()) return true;
-    while (true) {
-      xsp = jj_scanpos;
-      if (jj_3R_13()) { jj_scanpos = xsp; break; }
-    }
-    return false;
-  }
-
-  private boolean jj_3R_11() {
+      if (jj_3R_20()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_23() {
+    if (jj_3R_25()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_15() {
     if (jj_scan_token(IDENT)) return true;
-    if (jj_3R_14()) return true;
+    if (jj_3R_21()) return true;
     if (jj_scan_token(LPAR)) return true;
     return false;
   }
 
-  private boolean jj_3R_16() {
+  private boolean jj_3R_26() {
     if (jj_scan_token(COMMENT_START)) return true;
     return false;
   }
 
-  private boolean jj_3R_12() {
+  private boolean jj_3R_19() {
     Token xsp;
     xsp = jj_scanpos;
@@ -767,6 +888,61 @@
   }
 
+  private boolean jj_3_2() {
+    if (jj_3R_13()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_24() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(7)) {
+    jj_scanpos = xsp;
+    if (jj_3R_26()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_21() {
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_24()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
   private boolean jj_3_1() {
-    if (jj_3R_10()) return true;
+    if (jj_3R_12()) return true;
+    if (jj_scan_token(RSQUARE)) return true;
+    return false;
+  }
+
+  private boolean jj_3_3() {
+    if (jj_3R_14()) return true;
+    return false;
+  }
+
+  private boolean jj_3_4() {
+    if (jj_3R_15()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_18() {
+    if (jj_scan_token(EXCLAMATION_EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_17() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_22()) {
+    jj_scanpos = xsp;
+    if (jj_3R_23()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_22() {
+    if (jj_scan_token(IDENT)) return true;
     return false;
   }
@@ -783,13 +959,18 @@
   private int jj_la;
   private int jj_gen;
-  final private int[] jj_la1 = new int[32];
+  final private int[] jj_la1 = new int[35];
   static private int[] jj_la1_0;
+  static private int[] jj_la1_1;
   static {
       jj_la1_init_0();
+      jj_la1_init_1();
    }
    private static void jj_la1_init_0() {
-      jj_la1_0 = new int[] {0xc,0x12,0x80,0x4000080,0x4000080,0x400000,0x102,0x400000,0x102,0x800000,0x81000,0x81000,0x100000,0x4,0x2000000,0x2000004,0x20000,0x50000,0x50000,0x20000,0x102,0x800,0x200000,0x800,0x300405e,0x1000000,0x100,0x3000300,0x3000300,0x300405e,0x400000,0x300005e,};
+      jj_la1_0 = new int[] {0xc,0x12,0x80,0x20000080,0x20000080,0x400000,0x102,0x400000,0x102,0x1000000,0x81000,0x81000,0x100000,0x4,0x4000000,0x4000004,0x600405e,0x20000,0x50000,0x20000,0x102,0x800,0x200000,0x800,0x600405e,0x2000000,0x100,0x4000000,0x200,0x1e800300,0x1e800300,0x600405e,0x400000,0x600405e,0x600005e,};
    }
-  final private JJCalls[] jj_2_rtns = new JJCalls[2];
+   private static void jj_la1_init_1() {
+      jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,};
+   }
+  final private JJCalls[] jj_2_rtns = new JJCalls[4];
   private boolean jj_rescan = false;
   private int jj_gc = 0;
@@ -806,5 +987,5 @@
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 32; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 35; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
@@ -821,5 +1002,5 @@
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 32; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 35; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
@@ -832,5 +1013,5 @@
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 32; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 35; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
@@ -843,5 +1024,5 @@
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 32; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 35; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
@@ -853,5 +1034,5 @@
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 32; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 35; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
@@ -863,5 +1044,5 @@
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 32; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 35; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
@@ -975,10 +1156,10 @@
   public ParseException generateParseException() {
     jj_expentries.clear();
-    boolean[] la1tokens = new boolean[30];
+    boolean[] la1tokens = new boolean[33];
     if (jj_kind >= 0) {
       la1tokens[jj_kind] = true;
       jj_kind = -1;
     }
-    for (int i = 0; i < 32; i++) {
+    for (int i = 0; i < 35; i++) {
       if (jj_la1[i] == jj_gen) {
         for (int j = 0; j < 32; j++) {
@@ -986,8 +1167,11 @@
             la1tokens[j] = true;
           }
+          if ((jj_la1_1[i] & (1<<j)) != 0) {
+            la1tokens[32+j] = true;
+          }
         }
       }
     }
-    for (int i = 0; i < 30; i++) {
+    for (int i = 0; i < 33; i++) {
       if (la1tokens[i]) {
         jj_expentry = new int[1];
@@ -1016,5 +1200,5 @@
   private void jj_rescan_token() {
     jj_rescan = true;
-    for (int i = 0; i < 2; i++) {
+    for (int i = 0; i < 4; i++) {
     try {
       JJCalls p = jj_2_rtns[i];
@@ -1025,4 +1209,6 @@
             case 0: jj_3_1(); break;
             case 1: jj_3_2(); break;
+            case 2: jj_3_3(); break;
+            case 3: jj_3_4(); break;
           }
         }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj	(revision 3856)
@@ -54,7 +54,10 @@
 |   < SEMICOLON: ";" >
 |   < COMMA: "," >
+|   < PIPE: "|" >
 |   < PIPE_Z: "|z" >
 |   < PLUS: "+" >
 |   < MINUS: "-" >
+|   < AMPERSAND: "&" >
+|   < QUESTION: "?" >
 |   < COMMENT_START: "/*" > : COMMENT
 |   < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from
@@ -157,5 +160,5 @@
  * comma delimited list of floats (at least 2, all >= 0)
  */
-float[] float_array() :
+List<Float> float_array() :
 {
     float f;
@@ -169,9 +172,5 @@
     )+
     {
-        float[] a = new float[fs.size()];
-        for (int i=0; i<fs.size(); ++i) {
-            a[i] = fs.get(i);
-        }
-        return a;
+        return fs;
     }
 }
@@ -239,4 +238,35 @@
 Condition condition() :
 {
+    Condition c;
+    Expression e;
+}
+{
+    <LSQUARE>
+    ( 
+        LOOKAHEAD(2)
+            ( c=simple_key_condition() <RSQUARE> { return c; } )
+        |   
+        LOOKAHEAD(3)
+            c=simple_key_value_condition() 
+        |   
+            e=expression() { c = new Condition.ExpressionCondition(e); }
+    )
+    <RSQUARE>
+    { return c; }
+}
+
+Condition simple_key_condition() :
+{
+    boolean not = false;
+    String key;
+}
+{
+    ( <EXCLAMATION> { not = true; } )?
+    key=string_or_ident()
+    { return new Condition.KeyCondition(key, not); }
+}
+
+Condition simple_key_value_condition() :
+{
     boolean not = false;
     String key;
@@ -244,15 +274,8 @@
 }
 {
-    <LSQUARE>
-    ( <EXCLAMATION> { not = true; } )?
     key=string_or_ident()
-    (
-        ( <EXCLAMATION_EQUAL> { not = true; } | <EQUAL> )
-        val=string_or_ident()
-        <RSQUARE>
-        { return new Condition.KeyValueCondition(key, val, not ? Condition.Op.NEQ : Condition.Op.EQ); }
-    )?
-    <RSQUARE>
-    { return new Condition.KeyCondition(key, not); }
+    ( <EXCLAMATION_EQUAL> { not = true; } | <EQUAL> )
+    val=string_or_ident()
+    { return new Condition.KeyValueCondition(key, val, not ? Condition.Op.NEQ : Condition.Op.EQ); }
 }
 
@@ -331,14 +354,20 @@
     e=primary() { args.add(e); } w()
     (
-            ( <PLUS> { op = "+"; } w() e=primary() { args.add(e); } w() )+
-        |
-            ( <STAR> { op = "*"; } w() e=primary() { args.add(e); } w() )+
-        |
-            ( <MINUS> { op = "-"; } w() e=primary() { args.add(e); } w() )
-        |
-            ( <SLASH> { op = "/"; } w() e=primary() { args.add(e); } w() )
+            ( <PLUS> { op = "plus"; } w() e=primary() { args.add(e); } w() )+
+        |
+            ( <STAR> { op = "times"; } w() e=primary() { args.add(e); } w() )+
+        |
+            ( <MINUS> { op = "minus"; } w() e=primary() { args.add(e); } w() )+
+        |
+            ( <SLASH> { op = "divided_by"; } w() e=primary() { args.add(e); } w() )+
+        |
+            ( <AMPERSAND> <AMPERSAND> { op = "and"; } w() e=primary() { args.add(e); } w() )
+        |
+            ( <PIPE> <PIPE> { op = "or"; } w() e=primary() { args.add(e); } w() )
+        |
+            ( <QUESTION> { op = "cond"; } w() e=primary() { args.add(e); } w() <COLON> w() e=primary() { args.add(e); } w() )
     )?
     {
-        if (args.size() == 1)
+        if (op == null)
             return args.get(0);
         return new FunctionExpression(op, args);
@@ -371,6 +400,8 @@
     tmp=<IDENT> { name = tmp.image; } w()
     <LPAR> w()
-    arg=expression() { args.add(arg); }
-    ( <COMMA> w() arg=expression() { args.add(arg); } )*
+    (
+        arg=expression() { args.add(arg); }
+        ( <COMMA> w() arg=expression() { args.add(arg); } )*
+    )?
     <RPAR>
     { return new FunctionExpression(name, args); }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserConstants.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserConstants.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserConstants.java	(revision 3856)
@@ -56,15 +56,21 @@
   int COMMA = 22;
   /** RegularExpression Id. */
-  int PIPE_Z = 23;
+  int PIPE = 23;
   /** RegularExpression Id. */
-  int PLUS = 24;
+  int PIPE_Z = 24;
   /** RegularExpression Id. */
-  int MINUS = 25;
+  int PLUS = 25;
   /** RegularExpression Id. */
-  int COMMENT_START = 26;
+  int MINUS = 26;
   /** RegularExpression Id. */
-  int UNEXPECTED_CHAR = 27;
+  int AMPERSAND = 27;
   /** RegularExpression Id. */
-  int COMMENT_END = 28;
+  int QUESTION = 28;
+  /** RegularExpression Id. */
+  int COMMENT_START = 29;
+  /** RegularExpression Id. */
+  int UNEXPECTED_CHAR = 30;
+  /** RegularExpression Id. */
+  int COMMENT_END = 31;
 
   /** Lexical state. */
@@ -98,11 +104,14 @@
     "\";\"",
     "\",\"",
+    "\"|\"",
     "\"|z\"",
     "\"+\"",
     "\"-\"",
+    "\"&\"",
+    "\"?\"",
     "\"/*\"",
     "<UNEXPECTED_CHAR>",
     "\"*/\"",
-    "<token of kind 29>",
+    "<token of kind 32>",
   };
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserTokenManager.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserTokenManager.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserTokenManager.java	(revision 3856)
@@ -47,4 +47,6 @@
          jjmatchedKind = 17;
          return jjMoveStringLiteralDfa1_0(0x40000L);
+      case 38:
+         return jjStopAtPos(0, 27);
       case 40:
          return jjStopAtPos(0, 14);
@@ -54,12 +56,12 @@
          return jjStopAtPos(0, 8);
       case 43:
-         return jjStopAtPos(0, 24);
+         return jjStopAtPos(0, 25);
       case 44:
          return jjStopAtPos(0, 22);
       case 45:
-         return jjStopAtPos(0, 25);
+         return jjStopAtPos(0, 26);
       case 47:
          jjmatchedKind = 9;
-         return jjMoveStringLiteralDfa1_0(0x4000000L);
+         return jjMoveStringLiteralDfa1_0(0x20000000L);
       case 58:
          jjmatchedKind = 19;
@@ -69,4 +71,6 @@
       case 61:
          return jjStopAtPos(0, 16);
+      case 63:
+         return jjStopAtPos(0, 28);
       case 91:
          return jjStopAtPos(0, 12);
@@ -76,5 +80,6 @@
          return jjStopAtPos(0, 10);
       case 124:
-         return jjMoveStringLiteralDfa1_0(0x800000L);
+         jjmatchedKind = 23;
+         return jjMoveStringLiteralDfa1_0(0x1000000L);
       case 125:
          return jjStopAtPos(0, 11);
@@ -93,6 +98,6 @@
    {
       case 42:
-         if ((active0 & 0x4000000L) != 0L)
-            return jjStopAtPos(1, 26);
+         if ((active0 & 0x20000000L) != 0L)
+            return jjStopAtPos(1, 29);
          break;
       case 58:
@@ -105,6 +110,6 @@
          break;
       case 122:
-         if ((active0 & 0x800000L) != 0L)
-            return jjStopAtPos(1, 23);
+         if ((active0 & 0x1000000L) != 0L)
+            return jjStopAtPos(1, 24);
          break;
       default :
@@ -346,5 +351,5 @@
    {
       case 42:
-         return jjMoveStringLiteralDfa1_1(0x10000000L);
+         return jjMoveStringLiteralDfa1_1(0x80000000L);
       default :
          return 1;
@@ -360,6 +365,6 @@
    {
       case 47:
-         if ((active0 & 0x10000000L) != 0L)
-            return jjStopAtPos(1, 28);
+         if ((active0 & 0x80000000L) != 0L)
+            return jjStopAtPos(1, 31);
          break;
       default :
@@ -388,5 +393,5 @@
 "", null, null, null, null, null, null, null, "\52", "\57", "\173", "\175", 
 "\133", "\135", "\50", "\51", "\75", "\41", "\41\75", "\72", "\72\72", "\73", "\54", 
-"\174\172", "\53", "\55", "\57\52", null, "\52\57", null, };
+"\174", "\174\172", "\53", "\55", "\46", "\77", "\57\52", null, "\52\57", null, };
 
 /** Lexer state names. */
@@ -399,11 +404,11 @@
 public static final int[] jjnewLexState = {
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-   -1, 1, -1, 0, -1, 
+   -1, -1, -1, -1, 1, -1, 0, -1, 
 };
 static final long[] jjtoToken = {
-   0x1fffffdfL, 
+   0xffffffdfL, 
 };
 static final long[] jjtoSkip = {
-   0x20000000L, 
+   0x100000000L, 
 };
 protected SimpleCharStream input_stream;
@@ -513,7 +518,7 @@
        jjmatchedPos = 0;
        curPos = jjMoveStringLiteralDfa0_0();
-       if (jjmatchedPos == 0 && jjmatchedKind > 27)
+       if (jjmatchedPos == 0 && jjmatchedKind > 30)
        {
-          jjmatchedKind = 27;
+          jjmatchedKind = 30;
        }
        break;
@@ -522,7 +527,7 @@
        jjmatchedPos = 0;
        curPos = jjMoveStringLiteralDfa0_1();
-       if (jjmatchedPos == 0 && jjmatchedKind > 29)
+       if (jjmatchedPos == 0 && jjmatchedKind > 32)
        {
-          jjmatchedKind = 29;
+          jjmatchedKind = 32;
        }
        break;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java	(revision 3856)
@@ -3,4 +3,5 @@
 
 import java.awt.Color;
+import java.util.List;
 
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
@@ -14,5 +15,5 @@
     public Integer realWidth; // the real width of this line in meter
     public Color color;
-    protected float[] dashed;
+    protected List<Float> dashed;
     public Color dashedColor;
 
@@ -41,21 +42,27 @@
     }
 
-    public float[] getDashed() {
+    public List<Float> getDashed() {
         return dashed;
     }
 
-    public void setDashed(float[] dashed) {
-        if (dashed == null || dashed.length == 0) {
-            this.dashed = dashed;
+    public void setDashed(List<Float> dashed) {
+        if (dashed == null || dashed.isEmpty()) {
+            this.dashed = null;
             return;
         }
 
         boolean found = false;
-        for (int i=0; i<dashed.length; i++) {
-            if (dashed[i] > 0) {
+        for (Float f : dashed) {
+            if (f == null) {
+                this.dashed = null;
+                return;
+            }
+            if (f > 0) {
                 found = true;
             }
-            if (dashed[i] < 0) {
-                System.out.println(I18n.tr("Illegal dash pattern, values must be positive"));
+            if (f < 0) {
+                System.err.println(I18n.tr("Illegal dash pattern, values must be positive"));
+                this.dashed = null;
+                return;
             }
         }
@@ -63,5 +70,5 @@
             this.dashed = dashed;
         } else {
-            System.out.println(I18n.tr("Illegal dash pattern, at least one value must be > 0"));
+            System.err.println(I18n.tr("Illegal dash pattern, at least one value must be > 0"));
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSource.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSource.java	(revision 3856)
@@ -303,5 +303,5 @@
                 def.putOrClear("dashes-background-color", p.line.dashedColor);
             }
-            Float refWidth = def.getFloat("width", null);
+            Float refWidth = def.get("width", null, Float.class);
             if (refWidth != null && p.linemods != null) {
                 int numOver = 0, numUnder = 0;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java	(revision 3855)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java	(revision 3856)
@@ -3,4 +3,5 @@
 
 import java.awt.Color;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -91,20 +92,20 @@
                 line.realWidth=Integer.parseInt(atts.getValue(count));
             } else if (atts.getQName(count).equals("dashed")) {
-                float[] dashed;
+                Float[] dashed;
                 try {
                     String[] parts = atts.getValue(count).split(",");
-                    dashed = new float[parts.length];
+                    dashed = new Float[parts.length];
                     for (int i = 0; i < parts.length; i++) {
-                        dashed[i] = (Integer.parseInt(parts[i]));
+                        dashed[i] = (float) Integer.parseInt(parts[i]);
                     }
                 } catch (NumberFormatException nfe) {
                     boolean isDashed = Boolean.parseBoolean(atts.getValue(count));
                     if(isDashed) {
-                        dashed = new float[]{9};
+                        dashed = new Float[]{9f};
                     } else {
                         dashed = null;
                     }
                 }
-                line.setDashed(dashed);
+                line.setDashed(dashed == null ? null : Arrays.asList(dashed));
             } else if (atts.getQName(count).equals("dashedcolour")) {
                 line.dashedColor=convertColor(atts.getValue(count));
