Skip to content

Extending Less Language

Mária Jurčovičová edited this page Mar 22, 2014 · 68 revisions

Warning: this feature is still in experimental mode.

If less4j does not contain all functions you need, extend it with custom functions. Custom functions are called before build-in functions and may overwrite them.

Basics

Custom function must implement LessFunction interface. It has two methods:

public interface LessFunction {
  public boolean canEvaluate(FunctionExpression call, List<Expression> parameters);
  public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems);
}

The canEvaluate method analysis less function call supplied in input parameters. It returns true only if it should be used to calculate the result. Second evaluate method is called only if the canEvaluate returned true.

Custom functions are passed to less4j using addCustomFunction and addCustomFunctions methods of the Configuration object:

Configuration configuration = new Configuration();
configuration.addCustomFunction(new CustomFunction());
CompilationResult compilationResult = compiler.compile(inputLessFile, configuration);

Example

We will create function able evaluate only constant() function calls with no parameters. It will always returns the same result, an identifier fixed.

Test input:

div {
  property: constant();
}

should produce:

div {
  property: fixed;
}

Custom function implementation:

class ConstantFunction implements LessFunction {

  @Override
  public boolean canEvaluate(FunctionExpression call, List<Expression> parameters) {
    return call.getName().equals("constant") && parameters.isEmpty();
  }

  @Override
  public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems) {
    return new IdentifierExpression(call.getUnderlyingStructure(), "fixed");
  }
  
}

Use the Configuration object to pass your new function to the compiler:

Configuration configuration = new Configuration();
configuration.addCustomFunction(new ConstantFunction());

LessCompiler compiler = new DefaultLessCompiler();
CompilationResult compilationResult = compiler.compile(inputLessFile, configuration);

Writing Custom Functions

Parameters

The LessFunction interface has two methods:

public boolean canEvaluate(FunctionExpression call, List<Expression> parameters);
public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems);
  • The FunctionExpression call contains abstract syntax tree node corresponding to function call. Its most important method is getName() method which returns the name of called function.

  • The List<Expression> parameters contains list of all expressions used as less function call parameters. Parameter expressions comes in evaluated e.g., variables are already replaced by their values and nested functions/operations are calculated. For example, less function call add(3, 4 + 1) will result in two elements long list. Its first element will correspond to 3 and second element will correspond to 5.

  • The Expression evaluatedParameter contains the same information as previous parameter, but in different form. It contains evaluated parameters as a single abstract syntax tree node. It will be needed only rarely.

  • The last LessProblems problems parameter is used to report errors and warnings. Use it to generate user friendly errors whenever your function encounters wrong or suspicious input.

Output Expression

The evaluate method must return valid instance of Expression. It must not return null. Valid instance means:

  • parent child relationship in returned expression AST must be properly solved,
  • underlyingStructure property of returned value and all of its childs must be non-null.

Error Handling

Clone this wiki locally