/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 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.lang.mwe2.externalspec.gtk;
import java.text.MessageFormat;
import java.util.Set;
import java.util.TreeSet;
import com.google.inject.Injector;
import org.eclipse.xtext.generator.IGeneratorFragment;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.xtext.generator.web.RegexpExtensions;
import io.sarl.lang.mwe2.externalspec.AbstractXmlHighlightingFragment2;
import io.sarl.lang.mwe2.externalspec.IXmlStyleAppendable;
import io.sarl.lang.mwe2.externalspec.IXmlStyleCloseable;
/**
* A {@link IGeneratorFragment} that create the language specification for
* the GTK source viewer.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @see "https://wiki.gnome.org/Projects/GtkSourceView"
*/
public class GtkSourceViewerGenerator2 extends AbstractXmlHighlightingFragment2 {
/** The default basename pattern for {@link MessageFormat}.
*/
public static final String BASENAME_PATTERN = "{0}.lang"; //$NON-NLS-1$
private static final String XML_FORMAT_VERSION = "2.0"; //$NON-NLS-1$
@Override
public String toString() {
return "GtkSourceView"; //$NON-NLS-1$
}
@Override
public void initialize(Injector injector) {
super.initialize(injector);
setBasenameTemplate(BASENAME_PATTERN);
}
@SuppressWarnings({"checkstyle:parameternumber", "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity"})
@Override
protected void generate(IXmlStyleAppendable it, Set<String> literals, Set<String> expressionKeywords,
Set<String> modifiers, Set<String> primitiveTypes, Set<String> punctuation, Set<String> ignored,
Set<String> specialKeywords, Set<String> typeDeclarationKeywords) {
it.appendHeader();
final IXmlStyleCloseable tag1 = it.open("language", //$NON-NLS-1$
"id", getLanguageSimpleName().toLowerCase(), //$NON-NLS-1$
"_name", getLanguageSimpleName(), //$NON-NLS-1$
"version", XML_FORMAT_VERSION, //$NON-NLS-1$
"_section", "Sources"); //$NON-NLS-1$ //$NON-NLS-2$
IXmlStyleCloseable tag2 = tag1.open("metadata"); //$NON-NLS-1$
generateMetadata(tag2);
tag2.close();
tag2 = tag1.open("styles"); //$NON-NLS-1$
generateStyles(tag2);
tag2.close();
tag2 = tag1.open("definitions"); //$NON-NLS-1$
generateDefinitions(tag2, literals,
sortedConcat(expressionKeywords, modifiers, primitiveTypes, typeDeclarationKeywords, specialKeywords),
punctuation);
tag2.close();
tag1.close();
}
/** Generate the metadata section.
*
* @param it the appendable
*/
protected void generateMetadata(IXmlStyleAppendable it) {
it.appendTagWithValue("property", //$NON-NLS-1$
Strings.concat(";", getMimeTypes()), //$NON-NLS-1$
"name", "mimetypes"); //$NON-NLS-1$ //$NON-NLS-2$
final StringBuilder buffer = new StringBuilder();
for (final String fileExtension : getLanguage().getFileExtensions()) {
if (buffer.length() > 0) {
buffer.append(";"); //$NON-NLS-1$
}
buffer.append("*.").append(fileExtension); //$NON-NLS-1$
}
it.appendTagWithValue("property", //$NON-NLS-1$
buffer.toString(),
"name", "globs"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("property", //$NON-NLS-1$
"//", //$NON-NLS-1$
"name", "line-comment-start"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("property", //$NON-NLS-1$
"/*", //$NON-NLS-1$
"name", "block-comment-start"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("property", //$NON-NLS-1$
"*/", //$NON-NLS-1$
"name", "block-comment-end"); //$NON-NLS-1$ //$NON-NLS-2$
}
/** Generate the style section.
*
* @param it the appendable
*/
@SuppressWarnings("static-method")
protected void generateStyles(IXmlStyleAppendable it) {
it.appendTag("style", //$NON-NLS-1$
"id", "comment", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Comment", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:comment"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "error", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Error", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:error"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "escaped-character", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Escaped Character", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:special-char"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "string", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "String", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:string"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "keyword", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Keyword", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:keyword"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "literal", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Literal", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:special-constant"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "number", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Number", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:number"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "operator", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Operator", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:operator"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "identifier", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Identifier", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:text"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTag("style", //$NON-NLS-1$
"id", "annotation", //$NON-NLS-1$ //$NON-NLS-2$
"_name", "Annotation", //$NON-NLS-1$ //$NON-NLS-2$
"map-to", "def:preprocessor"); //$NON-NLS-1$ //$NON-NLS-2$
}
/** Generate the definition of the language elements.
*
* @param it the appendable
* @param literals the literals of the language.
* @param keywords the keywords of the language.
* @param punctuation the punctuation symbols.
*/
protected void generateDefinitions(IXmlStyleAppendable it, Set<String> literals, Iterable<String> keywords,
Set<String> punctuation) {
it.appendTagWithValue("define-regex", lines("\t", //$NON-NLS-1$ //$NON-NLS-2$
"", //$NON-NLS-1$
"\\\\( # leading backslash", //$NON-NLS-1$
"[\\\\\\\"\\'nrbtf] | # escaped character", //$NON-NLS-1$
"[0-9]{1,3} | # latin encoded char", //$NON-NLS-1$
"u[0-9]{1,4} # unicode char", //$NON-NLS-1$
")"), //$NON-NLS-1$
"id", "escaped-character", //$NON-NLS-1$ //$NON-NLS-2$
"extended", "true"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("define-regex", //$NON-NLS-1$
"0[xX][0-9a-fA-F_]+(#(([bB][iI])|([lL])))?", //$NON-NLS-1$
"id", "hex-number"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("define-regex", //$NON-NLS-1$
"[0-9][0-9_]*", //$NON-NLS-1$
"id", "int-number"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("define-regex", //$NON-NLS-1$
"\\%{int-number}([eE][+\\-]?\\%{int-number})?(([bB][iIdD])|([lLdDfF]))?", //$NON-NLS-1$
"id", "decimal-number"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("define-regex", //$NON-NLS-1$
"(\\%{hex-number})|(\\%{decimal-number}(\\.\\%{decimal-number})?)", //$NON-NLS-1$
"id", "sarl-number"); //$NON-NLS-1$ //$NON-NLS-2$
it.appendTagWithValue("define-regex", //$NON-NLS-1$
"\\^?[a-zA-Z_$][a-zA-Z_$0-9]*", //$NON-NLS-1$
"id", "sarl-identifier"); //$NON-NLS-1$ //$NON-NLS-2$
final IXmlStyleCloseable tag1 = it.open("context", //$NON-NLS-1$
"id", "qq-string", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "string", //$NON-NLS-1$ //$NON-NLS-2$
"end-at-line-end", "true", //$NON-NLS-1$ //$NON-NLS-2$
"class", "string", //$NON-NLS-1$ //$NON-NLS-2$
"class-disabled", "no-spell-check"); //$NON-NLS-1$ //$NON-NLS-2$
tag1.appendTagWithValue("start", "\""); //$NON-NLS-1$ //$NON-NLS-2$
tag1.appendTagWithValue("end", "\""); //$NON-NLS-1$ //$NON-NLS-2$
final IXmlStyleCloseable tag2 = tag1.open("include"); //$NON-NLS-1$
final IXmlStyleCloseable tag3 = tag2.open("context", //$NON-NLS-1$
"id", "qq-string-escaped-character", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "escaped-character"); //$NON-NLS-1$ //$NON-NLS-2$
tag3.appendTagWithValue("match", "\\%{escaped-character}"); //$NON-NLS-1$ //$NON-NLS-2$
tag3.close();
tag2.close();
tag2.close();
final IXmlStyleCloseable tag4 = it.open("context", //$NON-NLS-1$
"id", "q-string", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "string", //$NON-NLS-1$ //$NON-NLS-2$
"end-at-line-end", "true", //$NON-NLS-1$ //$NON-NLS-2$
"class", "string", //$NON-NLS-1$ //$NON-NLS-2$
"class-disabled", "no-spell-check"); //$NON-NLS-1$ //$NON-NLS-2$
tag4.appendTagWithValue("start", "'"); //$NON-NLS-1$ //$NON-NLS-2$
tag4.appendTagWithValue("end", "'"); //$NON-NLS-1$ //$NON-NLS-2$
final IXmlStyleCloseable tag5 = tag4.open("include"); //$NON-NLS-1$
final IXmlStyleCloseable tag6 = tag5.open("context", //$NON-NLS-1$
"id", "q-string-escaped-character", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "escaped-character"); //$NON-NLS-1$ //$NON-NLS-2$
tag6.appendTagWithValue("match", "\\%{escaped-character}"); //$NON-NLS-1$ //$NON-NLS-2$
tag6.close();
tag5.close();
tag4.close();
final IXmlStyleCloseable tag7 = it.open("context", //$NON-NLS-1$
"id", "line-comment", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "comment", //$NON-NLS-1$ //$NON-NLS-2$
"end-at-line-end", "true", //$NON-NLS-1$ //$NON-NLS-2$
"class", "comment", //$NON-NLS-1$ //$NON-NLS-2$
"class-disabled", "no-spell-check"); //$NON-NLS-1$ //$NON-NLS-2$
tag7.appendTagWithValue("start", "//"); //$NON-NLS-1$ //$NON-NLS-2$
final IXmlStyleCloseable tag8 = tag7.open("include"); //$NON-NLS-1$
tag8.appendTag("context", //$NON-NLS-1$
"ref", "def:in-line-comment"); //$NON-NLS-1$ //$NON-NLS-2$
tag8.close();
tag7.close();
final IXmlStyleCloseable tag9 = it.open("context", //$NON-NLS-1$
"id", "block-comment", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "comment", //$NON-NLS-1$ //$NON-NLS-2$
"class", "comment", //$NON-NLS-1$ //$NON-NLS-2$
"class-disabled", "no-spell-check"); //$NON-NLS-1$ //$NON-NLS-2$
tag9.appendTagWithValue("start", "/\\*"); //$NON-NLS-1$ //$NON-NLS-2$
tag9.appendTagWithValue("end", "\\*/"); //$NON-NLS-1$ //$NON-NLS-2$
final IXmlStyleCloseable tag10 = tag9.open("include"); //$NON-NLS-1$
tag10.appendTag("context", //$NON-NLS-1$
"ref", "def:in-comment"); //$NON-NLS-1$ //$NON-NLS-2$
tag10.close();
tag9.close();
final IXmlStyleCloseable tag11 = it.open("context", //$NON-NLS-1$
"id", "close-comment-outside-comment", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "error"); //$NON-NLS-1$ //$NON-NLS-2$
tag11.appendTagWithValue("match", "\\*/(?!\\*)"); //$NON-NLS-1$ //$NON-NLS-2$
tag11.close();
final IXmlStyleCloseable tag12 = it.open("context", //$NON-NLS-1$
"id", "sarl-keywords", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "keyword"); //$NON-NLS-1$ //$NON-NLS-2$
for (final String keyword : keywords) {
tag12.appendTagWithValue("keyword", keyword); //$NON-NLS-1$
}
tag12.close();
final IXmlStyleCloseable tag13 = it.open("context", //$NON-NLS-1$
"id", "sarl-literals", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "literal"); //$NON-NLS-1$ //$NON-NLS-2$
for (final String literal : literals) {
tag13.appendTagWithValue("keyword", literal); //$NON-NLS-1$
}
tag13.close();
final IXmlStyleCloseable tag14 = it.open("context", //$NON-NLS-1$
"id", "annotations", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "annotation"); //$NON-NLS-1$ //$NON-NLS-2$
tag14.appendTagWithValue("match", "\\@\\%{sarl-identifier}(\\.\\%{sarl-identifier})*"); //$NON-NLS-1$ //$NON-NLS-2$
tag14.close();
final IXmlStyleCloseable tag15 = it.open("context", //$NON-NLS-1$
"id", "identifiers", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "identifier"); //$NON-NLS-1$ //$NON-NLS-2$
tag15.appendTagWithValue("match", "\\%{sarl-identifier}"); //$NON-NLS-1$ //$NON-NLS-2$
tag15.close();
final IXmlStyleCloseable tag16 = it.open("context", //$NON-NLS-1$
"id", "numeric", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "number"); //$NON-NLS-1$ //$NON-NLS-2$
tag16.appendTagWithValue("match", "\\%{sarl-number}"); //$NON-NLS-1$ //$NON-NLS-2$
tag16.close();
final IXmlStyleCloseable tag17 = it.open("context", //$NON-NLS-1$
"id", "operators", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "operator", //$NON-NLS-1$ //$NON-NLS-2$
"extend-parent", "false"); //$NON-NLS-1$ //$NON-NLS-2$
StringBuilder buffer = new StringBuilder();
final Set<Character> characters = new TreeSet<>();
for (final String operator : punctuation) {
if (buffer.length() > 0) {
buffer.append("|"); //$NON-NLS-1$
}
buffer.append("("); //$NON-NLS-1$
buffer.append(RegexpExtensions.toRegexpString(operator, false));
buffer.append(")"); //$NON-NLS-1$
operator.chars().forEach(c -> characters.add((char) c));
}
tag17.appendTagWithValue("match", buffer.toString()); //$NON-NLS-1$
tag17.close();
final IXmlStyleCloseable tag18 = it.open("context", //$NON-NLS-1$
"id", "invalid-operators", //$NON-NLS-1$ //$NON-NLS-2$
"style-ref", "error"); //$NON-NLS-1$ //$NON-NLS-2$
buffer = new StringBuilder();
for (final Character character : characters) {
buffer.append(RegexpExtensions.toRegexpString(character.toString(), false));
}
tag18.appendTagWithValue("match", "[" + buffer.toString() + "]+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag18.close();
final IXmlStyleCloseable tag19 = it.open("context", //$NON-NLS-1$
"id", getLanguageSimpleName().toLowerCase(), //$NON-NLS-1$
"class", "no-spell-check"); //$NON-NLS-1$ //$NON-NLS-2$
final IXmlStyleCloseable tag20 = tag19.open("include"); //$NON-NLS-1$
tag20.appendTag("context", "ref", "qq-string"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "q-string"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "line-comment"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "block-comment"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "close-comment-outside-comment"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "sarl-keywords"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "sarl-literals"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "annotations"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "identifiers"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "numeric"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.appendTag("context", "ref", "operators"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
tag20.close();
tag19.close();
}
}