All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sling.scripting.sightly.compiler.SightlyCompiler Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 ******************************************************************************/
package org.apache.sling.scripting.sightly.compiler;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.scripting.sightly.compiler.backend.BackendCompiler;
import org.apache.sling.scripting.sightly.compiler.commands.CommandStream;
import org.apache.sling.scripting.sightly.impl.compiler.CompilationResultImpl;
import org.apache.sling.scripting.sightly.impl.compiler.CompilerFrontend;
import org.apache.sling.scripting.sightly.impl.compiler.CompilerMessageImpl;
import org.apache.sling.scripting.sightly.impl.compiler.PushStream;
import org.apache.sling.scripting.sightly.impl.compiler.debug.SanityChecker;
import org.apache.sling.scripting.sightly.impl.compiler.frontend.SimpleFrontend;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.CoalescingWrites;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.DeadCodeRemoval;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.SequenceStreamTransformer;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.StreamTransformer;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.SyntheticMapRemoval;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.UnusedVariableRemoval;
import org.apache.sling.scripting.sightly.impl.compiler.optimization.reduce.ConstantFolding;
import org.apache.sling.scripting.sightly.impl.filter.Filter;
import org.apache.sling.scripting.sightly.impl.filter.FormatFilter;
import org.apache.sling.scripting.sightly.impl.filter.I18nFilter;
import org.apache.sling.scripting.sightly.impl.filter.JoinFilter;
import org.apache.sling.scripting.sightly.impl.filter.URIManipulationFilter;
import org.apache.sling.scripting.sightly.impl.filter.XSSFilter;
import org.apache.sling.scripting.sightly.impl.plugin.AttributePlugin;
import org.apache.sling.scripting.sightly.impl.plugin.CallPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.ElementPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.IncludePlugin;
import org.apache.sling.scripting.sightly.impl.plugin.ListPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.Plugin;
import org.apache.sling.scripting.sightly.impl.plugin.RepeatPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.ResourcePlugin;
import org.apache.sling.scripting.sightly.impl.plugin.SetPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.TemplatePlugin;
import org.apache.sling.scripting.sightly.impl.plugin.TestPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.TextPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.UnwrapPlugin;
import org.apache.sling.scripting.sightly.impl.plugin.UsePlugin;
import org.osgi.service.component.annotations.Component;

/**
 * 

* The {@link SightlyCompiler} interprets a HTL script and transforms it internally into a {@link CommandStream}. The * {@link CommandStream} can be fed to a {@link BackendCompiler} for transforming the stream into executable code, either by * transpiling the commands to a JVM supported language or by directly executing them. *

*/ @Component( service = SightlyCompiler.class ) public final class SightlyCompiler { private StreamTransformer optimizer; private CompilerFrontend frontend; public SightlyCompiler() { ArrayList transformers = new ArrayList<>(5); transformers.add(ConstantFolding.transformer()); transformers.add(DeadCodeRemoval.transformer()); transformers.add(SyntheticMapRemoval.TRANSFORMER); transformers.add(UnusedVariableRemoval.TRANSFORMER); transformers.add(CoalescingWrites.TRANSFORMER); optimizer = new SequenceStreamTransformer(transformers); // register plugins final List plugins = new ArrayList<>(12); plugins.add(new AttributePlugin()); plugins.add(new CallPlugin()); plugins.add(new ElementPlugin()); plugins.add(new IncludePlugin()); plugins.add(new ListPlugin()); plugins.add(new RepeatPlugin()); plugins.add(new ResourcePlugin()); plugins.add(new TemplatePlugin()); plugins.add(new TestPlugin()); plugins.add(new SetPlugin()); plugins.add(new TextPlugin()); plugins.add(new UnwrapPlugin()); plugins.add(new UsePlugin()); Collections.sort(plugins); // register filters final List filters = new ArrayList<>(5); filters.add(I18nFilter.getInstance()); filters.add(FormatFilter.getInstance()); filters.add(JoinFilter.getInstance()); filters.add(URIManipulationFilter.getInstance()); filters.add(XSSFilter.getInstance()); Collections.sort(filters); frontend = new SimpleFrontend(plugins, filters); } /** * Compiles a {@link CompilationUnit}. * * @param compilationUnit a compilation unit * @return the compilation result */ public CompilationResult compile(CompilationUnit compilationUnit) { return compile(compilationUnit, null); } /** * Compiles a {@link CompilationUnit}, passing the processed {@link CommandStream} to the provided {@link BackendCompiler}. * * @param compilationUnit a compilation unit * @param backendCompiler the backend compiler * @return the compilation result */ public CompilationResult compile(CompilationUnit compilationUnit, BackendCompiler backendCompiler) { String scriptName = compilationUnit.getScriptName(); String scriptSource = null; PushStream stream = new PushStream(); SanityChecker.attachChecker(stream); CommandStream optimizedStream = optimizer.transform(stream); CompilationResultImpl compilationResult = new CompilationResultImpl(optimizedStream); try { scriptSource = IOUtils.toString(compilationUnit.getScriptReader()); //optimizedStream.addHandler(LoggingHandler.INSTANCE); if (backendCompiler != null) { backendCompiler.handle(optimizedStream); } frontend.compile(stream, scriptSource); for (PushStream.StreamMessage w : stream.getWarnings()) { ScriptError warning = getScriptError(scriptSource, w.getCode(), 1, 0, w.getMessage()); compilationResult.getWarnings().add(new CompilerMessageImpl(scriptName, warning.errorMessage, warning.lineNumber, warning .column)); } } catch (SightlyCompilerException e) { ScriptError scriptError = getScriptError(scriptSource, e.getOffendingInput(), e.getLine(), e.getColumn(), e.getMessage()); compilationResult.getErrors().add(new CompilerMessageImpl(scriptName, scriptError.errorMessage, scriptError.lineNumber, scriptError.column)); } catch (IOException e) { throw new SightlyCompilerException("Unable to read source code from CompilationUnit identifying script " + scriptName, e); } compilationResult.seal(); return compilationResult; } private ScriptError getScriptError(String documentFragment, String offendingInput, int lineOffset, int columnOffset, String message) { if (StringUtils.isNotEmpty(offendingInput)) { String longestContiguousOffendingSequence = null; if (documentFragment.contains(offendingInput)) { longestContiguousOffendingSequence = offendingInput; } else { longestContiguousOffendingSequence = getContiguousOffendingSequence(offendingInput); } int offendingInputIndex = documentFragment.indexOf(longestContiguousOffendingSequence); if (offendingInputIndex > -1) { String textBeforeError = documentFragment.substring(0, offendingInputIndex); int line = lineOffset; int lastNewLineIndex = 0; for (String s : new String[] {"\r\n", "\r", "\n"}) { int l = textBeforeError.split(s, -1).length - 1; if (l + lineOffset > line) { line = l + lineOffset; int ix = textBeforeError.lastIndexOf(s); if (ix > 0) { lastNewLineIndex = ix + s.length() - 1; } } } int column = textBeforeError.substring(lastNewLineIndex).length(); if (column != columnOffset) { column +=columnOffset; } return new ScriptError(line, column, longestContiguousOffendingSequence + ": " + message); } } return new ScriptError(lineOffset, columnOffset, message); } private String getContiguousOffendingSequence(String input) { if (input != null) { StringBuilder longestSequence = new StringBuilder(); char[] inputCharArray = input.toCharArray(); for (int index = inputCharArray.length - 1; index >= 0; index--) { char c = inputCharArray[index]; if (!Character.isWhitespace(c)) { longestSequence.insert(0, c); } else { break; } } return longestSequence.toString(); } return null; } private static class ScriptError { private int lineNumber; private int column; private String errorMessage; ScriptError(int lineNumber, int column, String errorMessage) { this.lineNumber = lineNumber; this.column = column; this.errorMessage = errorMessage; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy