Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* $Id: io/sarl/maven/docs/parser/SarlDocumentationParser.java v0.10.0 2019-10-26 17:20:53$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2019 the original authors or authors.
*
* Licensed 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 io.sarl.maven.docs.parser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Named;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.inject.Inject;
import com.google.inject.Injector;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.arakhne.afc.vmutil.FileSystem;
import org.arakhne.afc.vmutil.ReflectionUtil;
import org.eclipse.xtext.Constants;
import org.eclipse.xtext.xbase.lib.Functions.Function2;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import io.sarl.lang.sarl.actionprototype.IActionPrototypeProvider;
import io.sarl.lang.util.OutParameter;
import io.sarl.maven.docs.testing.ReflectExtensions;
import io.sarl.maven.docs.testing.ScriptExecutor;
/** Generator of the marker language files for the modified marker language for SARL.
*
* @author Stéphane Galland
* @author Alexandre Lombard
* @version 0.10.0 2019-10-26 17:20:53
* @mavengroupid io.sarl.maven
* @mavenartifactid io.sarl.maven.docs.generator
* @since 0.6
*/
public class SarlDocumentationParser {
/** Default pattern for formatting inline code.
*/
public static final String DEFAULT_INLINE_FORMAT = "`{0}`"; //$NON-NLS-1$
/** Default string to put for the outline location.
*/
public static final String DEFAULT_OUTLINE_OUTPUT_TAG = "[::Outline::]"; //$NON-NLS-1$
/** Default text for line continuation.
*/
public static final String DEFAULT_LINE_CONTINUATION = " "; //$NON-NLS-1$
private static final String DEFAULT_TAG_NAME_PATTERN = "\\[:(.*?)[:!]?\\]"; //$NON-NLS-1$
private static final int PATTERN_COMPILE_OPTIONS = Pattern.DOTALL | Pattern.MULTILINE;
private Injector injector;
private IActionPrototypeProvider actionPrototypeProvider;
private Map rawPatterns = new HashMap<>();
private Map compiledPatterns = new HashMap<>();
private String inlineFormat;
private Function2 blockFormat;
private String outlineOutputTag;
private String dynamicNameExtractionPattern;
private Deque additionalPropertyProvidersByPriority = new LinkedList<>();
private String lineSeparator;
private String languageName;
private ScriptExecutor scriptExecutor;
private String lineContinuation;
/** Constructor.
*/
public SarlDocumentationParser() {
reset();
}
/** Change the injector.
*
* @param injector the injector.
*/
@Inject
public void setInjector(Injector injector) {
assert injector != null;
this.injector = injector;
}
/** Change the name of the language.
*
* @param outputLanguage the language name, or {@code null} for ignoring the language name.
*/
@Inject
public void setOutputLanguage(@Named(Constants.LANGUAGE_NAME) String outputLanguage) {
if (!Strings.isNullOrEmpty(outputLanguage)) {
final String[] parts = outputLanguage.split("\\.+"); //$NON-NLS-1$
if (parts.length > 0) {
final String simpleName = parts[parts.length - 1];
if (!Strings.isNullOrEmpty(simpleName)) {
this.languageName = simpleName;
return;
}
}
}
this.languageName = null;
}
/** Change the script executor.
*
* @param executor the script executor.
*/
@Inject
public void setScriptExecutor(ScriptExecutor executor) {
this.scriptExecutor = executor;
}
/** Replies the script executor.
*
* @return the script executor.
*/
public ScriptExecutor getScriptExecutor() {
return this.scriptExecutor;
}
/** Replies the string of character to put in the text when line continuation is detected.
*
* @return the line continuation string of characters, or {@code null} to ignore line continuations.
*/
public String getLineContinuation() {
return this.lineContinuation;
}
/** Change the string of character to put in the text when line continuation is detected.
*
* @param lineContinuationText the line continuation string of characters, or {@code null} to ignore line continuations.
*/
public void setLineContinuation(String lineContinuationText) {
this.lineContinuation = lineContinuationText;
}
/** Replies the fenced code block formatter.
*
*
This code block formatter is usually used by Github.
*
* @return the formatter.
*/
public static Function2 getFencedCodeBlockFormatter() {
return (languageName, content) -> {
/*final StringBuilder result = new StringBuilder();
result.append("
\n").append(content).append("
\n"); //$NON-NLS-1$ //$NON-NLS-2$
return result.toString();*/
return "```" + Strings.nullToEmpty(languageName).toLowerCase() + "\n" //$NON-NLS-1$ //$NON-NLS-2$
+ content
+ "```\n"; //$NON-NLS-1$
};
}
/** Replies the basic code block formatter.
*
* @return the formatter.
*/
public static Function2 getBasicCodeBlockFormatter() {
return (languageName, content) -> {
return Pattern.compile("^", Pattern.MULTILINE).matcher(content).replaceAll("\t"); //$NON-NLS-1$ //$NON-NLS-2$
};
}
/** Replies the name of the language.
*
* @return the language name, or {@code null} for ignoring the language name.
*/
public String getOutputLanguage() {
return this.languageName;
}
/** Change the provider of action prototypes.
*
* @param provider the provider.
*/
@Inject
public void setActionPrototypeProvider(IActionPrototypeProvider provider) {
assert provider != null;
this.actionPrototypeProvider = provider;
}
/** Replies the provider of action prototypes.
*
* @return the provider.
*/
@Inject
public IActionPrototypeProvider getActionPrototypeProvider() {
return this.actionPrototypeProvider;
}
/** Reset to the default settings.
*/
public void reset() {
this.rawPatterns.clear();
this.compiledPatterns.clear();
this.inlineFormat = DEFAULT_INLINE_FORMAT;
this.blockFormat = null;
this.outlineOutputTag = DEFAULT_OUTLINE_OUTPUT_TAG;
this.dynamicNameExtractionPattern = DEFAULT_TAG_NAME_PATTERN;
this.lineContinuation = DEFAULT_LINE_CONTINUATION;
}
/** Add a provider of properties that could be used for finding replacement values.
*
*
The given provider will be consider prior to the already declared providers.
*
* @param properties the property provider.
*/
public void addHighPropertyProvider(Properties properties) {
this.additionalPropertyProvidersByPriority.addFirst(properties);
}
/** Add a provider of properties that could be used for finding replacement values.
*
*
The given provider will be consider after the already declared providers.
*
* @param properties the property provider.
*/
public void addLowPropertyProvider(Properties properties) {
this.additionalPropertyProvidersByPriority.addLast(properties);
}
/** Replies additional providers of properties that could be used for finding replacement values.
*
*
The providers are provided from the higher priority to the lower priority.
*
* @return the property providers.
*/
public Iterable getPropertyProvidersByPriority() {
return Collections.unmodifiableCollection(this.additionalPropertyProvidersByPriority);
}
/** Change the pattern of the tag.
*
* @param tag the tag.
* @param regex the regular expression.
*/
public void setPattern(Tag tag, String regex) {
if (Strings.isNullOrEmpty(regex)) {
this.rawPatterns.remove(tag);
this.compiledPatterns.remove(tag);
} else {
this.rawPatterns.put(tag, regex);
this.compiledPatterns.put(tag, Pattern.compile("^\\s*" + regex, PATTERN_COMPILE_OPTIONS)); //$NON-NLS-1$
}
}
/** Replies the pattern of the tag.
*
* @param tag the tag.
* @return the regular expression pattern.
*/
public String getPattern(Tag tag) {
final String pattern = this.rawPatterns.get(tag);
if (pattern == null) {
return tag.getDefaultPattern();
}
return pattern;
}
/** Replies the tag that is matching the given text.
*
* @param text the text to match.
* @return the tag or {@code null}.
*/
public Tag getTagForPattern(CharSequence text) {
for (final Tag tag : Tag.values()) {
Pattern pattern = this.compiledPatterns.get(tag);
if (pattern == null) {
pattern = Pattern.compile("^\\s*" + getPattern(tag), Pattern.DOTALL); //$NON-NLS-1$
this.compiledPatterns.put(tag, pattern);
}
final Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
return tag;
}
}
return null;
}
/** Change the pattern for the failure tag.
*
* @param regex the regular expression.
*/
public final void setFailurePattern(String regex) {
setPattern(Tag.FAILURE, regex);
}
/** Replies the pattern for the failure tag.
*
* @return the regular expression.
*/
public final String getFailurePattern() {
return getPattern(Tag.FAILURE);
}
/** Change the pattern for the success tag.
*
* @param regex the regular expression.
*/
public final void setSuccessPattern(String regex) {
setPattern(Tag.SUCCESS, regex);
}
/** Replies the pattern for the success tag.
*
* @return the regular expression.
*/
public final String getSuccessPattern() {
return getPattern(Tag.SUCCESS);
}
/** Change the pattern for the definition tag.
*
* @param regex the regular expression.
*/
public final void setDefinitionPattern(String regex) {
setPattern(Tag.DEFINITION, regex);
}
/** Replies the pattern for the definition tag.
*
* @return the regular expression.
*/
public final String getDefinitionPattern() {
return getPattern(Tag.DEFINITION);
}
/** Change the pattern for the reference tag.
*
* @param regex the regular expression.
*/
public final void setReferencePattern(String regex) {
setPattern(Tag.REFERENCE, regex);
}
/** Replies the pattern for the reference tag.
*
* @return the regular expression.
*/
public final String getReferencePattern() {
return getPattern(Tag.REFERENCE);
}
/** Change the pattern for the "off" tag.
*
* @param regex the regular expression.
*/
public final void setOffPattern(String regex) {
setPattern(Tag.OFF, regex);
}
/** Replies the pattern for the "off" tag.
*
* @return the regular expression.
*/
public final String getOffPattern() {
return getPattern(Tag.OFF);
}
/** Change the pattern for the "on" tag.
*
* @param regex the regular expression.
*/
public final void setOnPattern(String regex) {
setPattern(Tag.ON, regex);
}
/** Replies the pattern for the "on" tag.
*
* @return the regular expression.
*/
public final String getOnPattern() {
return getPattern(Tag.ON);
}
/** Change the pattern for the fact tag.
*
* @param regex the regular expression.
*/
public final void setFactPattern(String regex) {
setPattern(Tag.FACT, regex);
}
/** Replies the pattern for the fact tag.
*
* @return the regular expression.
*/
public final String getFactPattern() {
return getPattern(Tag.FACT);
}
/** Change the pattern for the include tag.
*
* @param regex the regular expression.
*/
public final void setIncludePattern(String regex) {
setPattern(Tag.INCLUDE, regex);
}
/** Replies the pattern for the include tag.
*
* @return the regular expression.
*/
public final String getIncludePattern() {
return getPattern(Tag.INCLUDE);
}
/** Change the pattern for the outline tag.
*
* @param regex the regular expression.
*/
public final void setOutlinePattern(String regex) {
setPattern(Tag.OUTLINE, regex);
}
/** Replies the pattern for the outline tag.
*
* @return the regular expression.
*/
public final String getOutlinePattern() {
return getPattern(Tag.OUTLINE);
}
/** Set the template for inline codes.
*
*
The template should follow the {@link MessageFormat} specifications.
*
* @param template the template.
*/
public void setInlineCodeTemplate(String template) {
if (!Strings.isNullOrEmpty(template)) {
this.inlineFormat = template;
}
}
/** Replies the template for inline codes.
*
*
The template should follow the {@link MessageFormat} specifications.
*
* @return the template.
*/
public String getInlineCodeTemplate() {
return this.inlineFormat;
}
/** Set the template for block codes.
*
*
The first parameter of the function is the language name. The second parameter is
* the code to format.
*
* @param template the template.
*/
public void setBlockCodeTemplate(Function2 template) {
this.blockFormat = template;
}
/** Replies the template for block codes.
*
*
The first parameter of the function is the language name. The second parameter is
* the code to format.
*
* @return the template.
*/
public Function2 getBlockCodeTemplate() {
return this.blockFormat;
}
/** Change the outline output tag that will be output when the outline
* tag is found in the input content.
*
* @param tag the tag for outline.
*/
protected void setOutlineOutputTag(String tag) {
this.outlineOutputTag = tag;
}
/** Replies the outline output tag that will be output when the outline
* tag is found in the input content.
*
* @return the tag.
*/
public String getOutlineOutputTag() {
return this.outlineOutputTag;
}
/** Set the regular expression for extracting the dynamic name of a tag string.
*
* @param pattern the regex.
*/
public void setDynamicNameExtractionPattern(String pattern) {
if (!Strings.isNullOrEmpty(pattern)) {
this.dynamicNameExtractionPattern = pattern;
}
}
/** Replies the regular expression for extracting the dynamic name of a tag string.
*
* @return the regex.
*/
public String getDynamicNameExtractionPattern() {
return this.dynamicNameExtractionPattern;
}
/** Replies the OS-dependent line separator.
*
* @return the line separator from the {@code "line.separator"} property, or {@code "\n"}.
*/
public String getLineSeparator() {
if (Strings.isNullOrEmpty(this.lineSeparator)) {
final String nl = System.getProperty("line.separator"); //$NON-NLS-1$
if (Strings.isNullOrEmpty(nl)) {
return "\n"; //$NON-NLS-1$
}
return nl;
}
return this.lineSeparator;
}
/** Change the OS-dependent line separator.
*
* @param lineSeparator the line separator or {@code null} to use the system configuration.
*/
public void setLineSeparator(String lineSeparator) {
this.lineSeparator = lineSeparator;
}
private String buildGeneralTagPattern() {
final StringBuilder pattern = new StringBuilder();
int nbTags = 0;
for (final Tag tag : Tag.values()) {
if (nbTags >= 1) {
pattern.append("|"); //$NON-NLS-1$
}
pattern.append("(?:"); //$NON-NLS-1$
if (tag.isEnclosingSpaceCouldRemovable()) {
pattern.append("[ \\t]*"); //$NON-NLS-1$
}
pattern.append("("); //$NON-NLS-1$
pattern.append(getPattern(tag));
pattern.append(")"); //$NON-NLS-1$
if (tag.hasParameter()) {
pattern.append("(?:"); //$NON-NLS-1$
pattern.append("(?:\\(\\s*([^\\)]*?)\\s*\\))|"); //$NON-NLS-1$
pattern.append("(?:\\{\\s*([^\\}]*?)\\s*\\})|"); //$NON-NLS-1$
pattern.append("(?:\\|\\s*([^\\|]*?)\\s*\\|)|"); //$NON-NLS-1$
pattern.append("(?:\\$\\s*([^\\$]*?)\\s*\\$)"); //$NON-NLS-1$
pattern.append(")"); //$NON-NLS-1$
}
if (tag.isEnclosingSpaceCouldRemovable()) {
pattern.append("[ \\t]*"); //$NON-NLS-1$
}
pattern.append(")"); //$NON-NLS-1$
++nbTags;
}
if (nbTags > 0) {
pattern.insert(0, "(" + org.eclipse.xtext.util.Strings.convertToJavaString(getLineSeparator()) //$NON-NLS-1$
+ ")|"); //$NON-NLS-1$
return pattern.toString();
}
return null;
}
/** Extract the dynamic name of that from the raw text.
*
* @param tag the tag to extract for.
* @param name the raw text.
* @param dynamicName the dynamic name.
*/
protected void extractDynamicName(Tag tag, CharSequence name, OutParameter dynamicName) {
if (tag.hasDynamicName()) {
final Pattern pattern = Pattern.compile(getDynamicNameExtractionPattern());
final Matcher matcher = pattern.matcher(name);
if (matcher.matches()) {
dynamicName.set(Strings.nullToEmpty(matcher.group(1)));
return;
}
}
dynamicName.set(name.toString());
}
private static int findFirstGroup(Matcher matcher, int startIdx) {
final int len = matcher.groupCount();
for (int i = startIdx + 1; i <= len; ++i) {
final String value = matcher.group(i);
if (value != null) {
return i;
}
}
return 1;
}
/** Read the given file and transform its content in order to have a raw text.
*
* @param inputFile the input file.
* @return the raw file context.
*/
public String transform(File inputFile) {
final String content;
try (FileReader reader = new FileReader(inputFile)) {
content = read(reader);
} catch (IOException exception) {
reportError(Messages.SarlDocumentationParser_0, exception);
return null;
}
return transform(content, inputFile);
}
/** Read the given input stream and transform its content in order to have a raw text.
*
* @param reader the input stream.
* @param inputFile the name of the input file for locating included features and formatting error messages.
* @return the raw file context.
*/
public String transform(Reader reader, File inputFile) {
final String content;
try {
content = read(reader);
} catch (IOException exception) {
reportError(Messages.SarlDocumentationParser_0, exception);
return null;
}
return transform(content, inputFile);
}
/** Read the given input content and transform it in order to have a raw text.
*
* @param content the content to parse.
* @param inputFile the name of the input file for locating included features and formatting error messages.
* @return the raw file context.
*/
public String transform(CharSequence content, File inputFile) {
final ParsingContext rootContextForReplacements = new ParsingContext();
initializeContext(rootContextForReplacements);
CharSequence rawContent = preProcessing(content);
Stage stage = Stage.first();
do {
final ContentParserInterceptor interceptor = new ContentParserInterceptor();
// Reset the lineno because it is not reset between the different stages.
rootContextForReplacements.setLineNo(1);
final boolean hasChanged = parse(rawContent, inputFile, 0, stage, rootContextForReplacements, interceptor);
if (hasChanged) {
rawContent = interceptor.getResult();
}
stage = stage.next();
} while (stage != null);
return postProcessing(rawContent);
}
/** Do a pre processing of the text.
*
* @param text the text to pre process.
* @return the pre-processed text.
*/
@SuppressWarnings("static-method")
protected CharSequence preProcessing(CharSequence text) {
return text;
}
/** Do a post processing of the text.
*
* @param text the text to post process.
* @return the post-processed text.
*/
protected String postProcessing(CharSequence text) {
final String lineContinuation = getLineContinuation();
if (lineContinuation != null) {
final Pattern pattern = Pattern.compile(
"\\s*\\\\[\\n\\r]+\\s*", //$NON-NLS-1$
Pattern.DOTALL);
final Matcher matcher = pattern.matcher(text.toString().trim());
return matcher.replaceAll(lineContinuation);
}
return text.toString().trim();
}
/** Read the given input content and extract validation components.
*
* @param inputFile the input file.
* @param observer the oberserver to be called with extracted information. The parameter of the lambda maps
* the tags to the associated list of the extraction information.
*/
public void extractValidationComponents(File inputFile,
Procedure1