Skip to content

Commit

Permalink
Fold compound expressions with literal arguments into literals
Browse files Browse the repository at this point in the history
  • Loading branch information
Anand Thakker committed Sep 16, 2017
1 parent 50243f7 commit c027323
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
18 changes: 14 additions & 4 deletions src/style-spec/function/definitions/literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { Color, isValue, typeOf } = require('../values');

import type { Type } from '../types';
import type { Value } from '../values';
import type { Expression, ParsingContext } from '../expression';
import type { Expression, ParsingContext, CompilationContext } from '../expression';

const u2028 = /\u2028/g;
const u2029 = /\u2029/g;
Expand Down Expand Up @@ -45,9 +45,19 @@ class Literal implements Expression {
return new Literal(context.key, type, value);
}

compile() {
const value = Literal.compile(this.value);
return typeof this.value === 'object' ? `(${value})` : value;
compile(ctx: CompilationContext) {
let value;
if (this.type.kind === 'Color') {
value = `(new $this.Color(${(this.value: any).join(', ')}))`;
} else {
value = Literal.compile(this.value);
}

if (typeof this.value === 'object' && this.value !== null) {
return ctx.addVariable(value);
} else {
return value;
}
}

static compile(value: Value) {
Expand Down
1 change: 1 addition & 0 deletions src/style-spec/function/evaluation_context.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ function ensure(condition: any, message: string) {
module.exports = () => ({
types: types,

Color: Color, // used for compiling color literals
ensure: ensure,
error: (msg: string) => ensure(false, msg),

Expand Down
35 changes: 35 additions & 0 deletions src/style-spec/function/parse_expression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// @flow

const Literal = require('./definitions/literal');
const {CompilationContext} = require('./expression');
import type {ParsingContext, Expression} from './expression';

/**
Expand Down Expand Up @@ -55,6 +57,22 @@ function parseExpression(expr: mixed, context: ParsingContext): ?Expression {
}
}

// If an expression's arguments are all literals, we can evaluate
// it immediately and replace it with a literal value in the
// parsed/compiled result.
if (isConstant(parsed)) {
const cc = new CompilationContext();
const ec = require('./evaluation_context')();
const compiled = cc.compileToFunction(parsed, ec);
try {
const value = compiled({}, {});
parsed = new Literal(parsed.key, parsed.type, value);
} catch (e) {
context.error(e.message);
return null;
}
}

return parsed;
}

Expand All @@ -68,4 +86,21 @@ function parseExpression(expr: mixed, context: ParsingContext): ?Expression {
}
}

const nonConstantExpressions = [ 'error', 'get', 'has', 'properties', 'id', 'geometry-type', 'zoom' ];
function isConstant(expression: Expression) {
const {CompoundExpression} = require('./compound_expression');
const Var = require('./definitions/var');
if (expression instanceof CompoundExpression && nonConstantExpressions.indexOf(expression.name) >= 0) {
return false;
} else if (expression instanceof Var) {
return false;
}

let constant = true;
expression.eachChild(arg => {
constant = constant && (arg instanceof Literal);
});
return constant;
}

module.exports = parseExpression;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"expectExpressionType": {"kind": "Color"},
"expression": [
"curve",
["step"],
["get", "x"],
"black",
0,
"invalid",
10,
"blue"
],
"inputs": [
[{}, {"properties": {"x": -1}}],
[{}, {"properties": {"x": 0}}],
[{}, {"properties": {"x": 5}}],
[{}, {"properties": {"x": 10}}],
[{}, {"properties": {"x": 11}}]
],
"expected": {
"compiled": {
"result": "error",
"errors": [
{"key": "[5]", "error": "Could not parse color from value 'invalid'"}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"expectExpressionType": null,
"expression": ["to-color", "red"],
"inputs": [[{}, {}]],
"expected": {
"compiled": {
"result": "success",
"isFeatureConstant": true,
"isZoomConstant": true,
"type": "Color"
},
"outputs": [
[1, 0, 0, 1]
]
}
}

0 comments on commit c027323

Please sign in to comment.