SASS parser problem with "calc" function

Hello,

We run to a problem after updating our Vaadin version from 7.2.3 to 7.2.4. While loading a page, the server throws following exception to its console:

com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException: Incompatible units found in: '100%'
    at com.vaadin.sass.internal.parser.LexicalUnitImpl.checkAndGetUnit(LexicalUnitImpl.java:377)
    at com.vaadin.sass.internal.parser.LexicalUnitImpl.minus(LexicalUnitImpl.java:360)
    at com.vaadin.sass.internal.expression.BinaryOperator$10.evalInternal(BinaryOperator.java:102)
    at com.vaadin.sass.internal.expression.BinaryOperator.eval(BinaryOperator.java:186)
    at com.vaadin.sass.internal.expression.BinaryExpression.eval(BinaryExpression.java:48)
    at com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator.evaluate(ArithmeticExpressionEvaluator.java:113)
    at com.vaadin.sass.internal.parser.SassExpression.evaluateFunctionsAndExpressions(SassExpression.java:214)
    at com.vaadin.sass.internal.parser.ArgumentList.evaluateFunctionsAndExpressions(ArgumentList.java:80)
    at com.vaadin.sass.internal.parser.ActualArgumentList.evaluateFunctionsAndExpressions(ActualArgumentList.java:167)
    at com.vaadin.sass.internal.parser.LexicalUnitImpl.evaluateFunctionsAndExpressions(LexicalUnitImpl.java:777)
    at com.vaadin.sass.internal.tree.RuleNode.traverse(RuleNode.java:104)
    at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
    at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:89)
    at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
    at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:89)
    at com.vaadin.sass.internal.visitor.MixinNodeHandler.replaceMixinNode(MixinNodeHandler.java:61)
    at com.vaadin.sass.internal.visitor.MixinNodeHandler.replaceMixins(MixinNodeHandler.java:40)
    at com.vaadin.sass.internal.visitor.MixinNodeHandler.traverse(MixinNodeHandler.java:30)
    at com.vaadin.sass.internal.tree.MixinNode.doTraverse(MixinNode.java:61)
    at com.vaadin.sass.internal.tree.NodeWithVariableArguments.traverse(NodeWithVariableArguments.java:95)
    at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
    at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:89)
    at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
    at com.vaadin.sass.internal.ScssStylesheet.traverse(ScssStylesheet.java:307)
    at com.vaadin.sass.internal.ScssStylesheet.compile(ScssStylesheet.java:249)
    at com.vaadin.server.VaadinServlet.serveOnTheFlyCompiledScss(VaadinServlet.java:886)
    at com.vaadin.server.VaadinServlet.serveStaticResourcesInVAADIN(VaadinServlet.java:642)
    at com.vaadin.server.VaadinServlet.serveStaticResources(VaadinServlet.java:612)
    at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:230)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at procountor.servlet.CrossSiteScriptingFilter.doFilter(CrossSiteScriptingFilter.java:33)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:122)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
    at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:170)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

The culprit (
LexicalUnitImpl
) does following check before throwing the exception:

protected short checkAndGetUnit(LexicalUnitImpl another) {
    if (getLexicalUnitType() != SAC_INTEGER
            && getLexicalUnitType() != SAC_REAL
            && another.getLexicalUnitType() != SAC_INTEGER
            && another.getLexicalUnitType() != SAC_REAL
            && getLexicalUnitType() != another.getLexicalUnitType()) {
        throw new IncompatibleUnitsException(printState());
    }
    if (another.getLexicalUnitType() != SAC_INTEGER
            && another.getLexicalUnitType() != SAC_REAL) {
        return another.getLexicalUnitType();
    }
    return getLexicalUnitType();
}

So it doesn’t seem to like anymore
calc
function in our SCSS files when the function tries to subtract pixels from percentages:

...    
width: calc(100% - 16px);
...
width: calc(100% - 130px);
...
width: -moz-calc(100% - 130px);
...

Now if I make both of the values to have the same unit, the problem goes away.

/*width: calc(100% - 16px);*/
width: calc(100% - 16%);

I managed to replicate this problem by creating a new Vaadin project and changing only the scss file to following:

/* Import the reindeer theme.*/
/* This only allows us to use the mixins defined in it and does not add any styles by itself. */
@import "../reindeer/reindeer.scss";

/* This contains all of your theme.*/
/* If somebody wants to extend the theme she will include this mixin. */
@mixin testi {
  /* Include all the styles from the reindeer theme */
  @include reindeer;
   
  $color : yellow;
  .v-button-caption {
    color:  $color;
    height: calc(100% - 1px);
  }
}

I found ticket
#13532
from the release notes of the version 7.2.4 and it seems that the CSS parser has been updated which might explain this change in behavior.

I’m not a CSS guru by any stretch of imagination so I’m wondering if this is a bug or feature. Has there been a change in the calc function parameters so that it’s nowadays illegal to subtract values with different units? Or could this be just a bug in the parser? Or maybe I’m missing something obvious here… I would usually suspect our SCSS files (or myself) to be at fault but they did work in the previous versions of Vaadin so maybe they’re innocent this time.

For the background info: I’m running the application on Tomcat 7.0.53 (Servlet 3.0 spec, Java 7).

Thanks,
Antti

There have been major changes to the Sass compiler over the last months. These include support for custom functions and a number of built-in functions, better support for arithmetics and much, much more.

In this case, our Sass compiler does not handle the CSS function calc() as a special case but tries to evaluate the expression “100% - 1px” at theme compilation time, which is not possible. I created the ticket
#14205
for this.

Added information about an ugly workaround to the ticket.

Thanks for the prompt reply.

I see you just fixed the ticket so I’ll skip the ugly workaround and wait for the release of the new version of the Sass compiler.

I am seeing a compile error on 7.2.6, I wonder if this is related or should I open a separate thread:

[java]
 Aug 05, 2014 5:18:48 PM com.vaadin.sass.internal.tree.BlockNode traverse
     [java]
 SEVERE: null
     [java]
 com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException: Incompatible units found in: '100vh'
     [java]
     at com.vaadin.sass.internal.parser.LexicalUnitImpl.checkAndGetUnit(LexicalUnitImpl.java:377)
     [java]
     at com.vaadin.sass.internal.parser.LexicalUnitImpl.minus(LexicalUnitImpl.java:360)
     [java]
     at com.vaadin.sass.internal.expression.BinaryOperator$10.evalInternal(BinaryOperator.java:102)
     [java]
     at com.vaadin.sass.internal.expression.BinaryOperator.eval(BinaryOperator.java:186)
     [java]
     at com.vaadin.sass.internal.expression.BinaryExpression.eval(BinaryExpression.java:48)
     [java]
     at com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator.evaluate(ArithmeticExpressionEvaluator.java:113)
     [java]
     at com.vaadin.sass.internal.parser.SassExpression.evaluateFunctionsAndExpressions(SassExpression.java:214)
     [java]
     at com.vaadin.sass.internal.parser.ArgumentList.evaluateFunctionsAndExpressions(ArgumentList.java:80)
     [java]
     at com.vaadin.sass.internal.parser.ActualArgumentList.evaluateFunctionsAndExpressions(ActualArgumentList.java:167)
     [java]
     at com.vaadin.sass.internal.parser.LexicalUnitImpl.evaluateFunctionsAndExpressions(LexicalUnitImpl.java:777)
     [java]
     at com.vaadin.sass.internal.tree.RuleNode.traverse(RuleNode.java:104)
     [java]
     at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
     [java]
     at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:89)
     [java]
     at com.vaadin.sass.internal.visitor.MixinNodeHandler.replaceMixinNode(MixinNodeHandler.java:61)
     [java]
     at com.vaadin.sass.internal.visitor.MixinNodeHandler.replaceMixins(MixinNodeHandler.java:40)
     [java]
     at com.vaadin.sass.internal.visitor.MixinNodeHandler.traverse(MixinNodeHandler.java:30)
     [java]
     at com.vaadin.sass.internal.tree.MixinNode.doTraverse(MixinNode.java:61)
     [java]
     at com.vaadin.sass.internal.tree.NodeWithVariableArguments.traverse(NodeWithVariableArguments.java:95)
     [java]
     at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
     [java]
     at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:89)
     [java]
     at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:169)
     [java]
     at com.vaadin.sass.internal.ScssStylesheet.traverse(ScssStylesheet.java:307)
     [java]
     at com.vaadin.sass.internal.ScssStylesheet.compile(ScssStylesheet.java:249)
     [java]
     at com.vaadin.sass.SassCompiler.main(SassCompiler.java:57)

This looks like a separate issue. Please
create a ticket
with a snippet of Scss to reproduce the problem if not already done.

Hello,

The basic calc() function is working correctly (Vaadin 7.3.0), but there still seems to be a similar problems with “-moz-calc()” and “-webkit-calc()” functions. They both throw the following error:

com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException: Incompatible units found in: '100%'
    at com.vaadin.sass.internal.parser.LexicalUnitImpl.checkAndGetUnit(LexicalUnitImpl.java:405)
    at com.vaadin.sass.internal.parser.LexicalUnitImpl.minus(LexicalUnitImpl.java:388)
    at com.vaadin.sass.internal.expression.BinaryOperator$10.evalInternal(BinaryOperator.java:144)
    at com.vaadin.sass.internal.expression.BinaryOperator.eval(BinaryOperator.java:228)
    at com.vaadin.sass.internal.expression.BinaryExpression.eval(BinaryExpression.java:48)
    at com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator.evaluate(ArithmeticExpressionEvaluator.java:116)
    at com.vaadin.sass.internal.parser.SassExpression.evaluateFunctionsAndExpressions(SassExpression.java:216)
    at com.vaadin.sass.internal.parser.ArgumentList.evaluateFunctionsAndExpressions(ArgumentList.java:79)
    at com.vaadin.sass.internal.parser.ActualArgumentList.evaluateFunctionsAndExpressions(ActualArgumentList.java:166)
    at com.vaadin.sass.internal.parser.LexicalUnitImpl.evaluateFunctionsAndExpressions(LexicalUnitImpl.java:817)
    at com.vaadin.sass.internal.tree.RuleNode.traverse(RuleNode.java:108)
    at com.vaadin.sass.internal.visitor.BlockNodeHandler.traverse(BlockNodeHandler.java:68)
    at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:119)
    at com.vaadin.sass.internal.visitor.BlockNodeHandler.traverse(BlockNodeHandler.java:66)
    at com.vaadin.sass.internal.tree.BlockNode.traverse(BlockNode.java:119)
    at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:213)
    at com.vaadin.sass.internal.tree.Node.traverseChildren(Node.java:200)
    at com.vaadin.sass.internal.ScssStylesheet.traverse(ScssStylesheet.java:270)
    at com.vaadin.sass.internal.ScssStylesheet.compile(ScssStylesheet.java:239)
    at com.vaadin.server.VaadinServlet.compileScssOnTheFly(VaadinServlet.java:950)
    at com.vaadin.server.VaadinServlet.serveOnTheFlyCompiledScss(VaadinServlet.java:906)
    at com.vaadin.server.VaadinServlet.serveStaticResourcesInVAADIN(VaadinServlet.java:682)
    at com.vaadin.server.VaadinServlet.serveStaticResources(VaadinServlet.java:652)
    at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:298)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:122)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:170)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

Based on a quick look around, out of reasonably recent browsers, only Safari 6.0 really needs the vendor prefix. Safari 6.1 and later don’t need a prefix, the -moz prefix is only needed on Firefox versions older than 16, and Chrome hasn’t needed the -webkit prefix since version 26.

Anyway, you can
create a ticket
for support of vendor prefixes for calc().