Merge branch 'ts'
authorShaverdova Elena <eshaverdova@gmail.com>
Thu, 24 May 2012 15:20:46 +0000 (19:20 +0400)
committerShaverdova Elena <eshaverdova@gmail.com>
Thu, 24 May 2012 15:20:46 +0000 (19:20 +0400)
81 files changed:
plugins/typoScript/gen/com/jetbrains/typoscript/lang/TypoScriptElementTypes.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/TypoScriptGeneratedParser.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Assignment.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/CodeBlock.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ConditionElement.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Copying.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/IncludeStatementElement.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/MultilineValueAssignment.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ObjectPath.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Unsetting.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ValueModification.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Visitor.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/AssignmentImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/CodeBlockImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ConditionElementImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/CopyingImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/IncludeStatementElementImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/MultilineValueAssignmentImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ObjectPathImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/UnsettingImpl.java [new file with mode: 0644]
plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ValueModificationImpl.java [new file with mode: 0644]
plugins/typoScript/resources/icons/condition_ts.png [new file with mode: 0644]
plugins/typoScript/resources/icons/include_ts.png [new file with mode: 0644]
plugins/typoScript/resources/icons/property_ts.png [new file with mode: 0644]
plugins/typoScript/resources/icons/typo3.png [new file with mode: 0644]
plugins/typoScript/resources/messages/TypoScriptBundle.properties [new file with mode: 0644]
plugins/typoScript/src/META-INF/plugin.xml [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptBundle.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptExtensionMappingChecker.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptIcons.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/GeneratedParserUtilBase.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.bnf [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.flex [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptBraceMatcher.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFileType.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFileTypeFactory.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFoldingBuilder.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptLanguage.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptLexer.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptParserDefinition.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptParserUtil.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptStructureViewFactory.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptTokenType.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptTokenTypes.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/_TypoScriptLexer.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptColorsAndFontsPage.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptHighlightingData.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptSyntaxHighlighter.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptCompositeElement.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptCompositeElementImpl.java [new file with mode: 0644]
plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptFile.java [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/assignments.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/assignments.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/codeBlock.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/codeBlock.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/comments.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/comments.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/copyingOperator.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/copyingOperator.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/exampleFromTypo.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/exampleFromTypo.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/include.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/include.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/multilineValue.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/multilineValue.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/objectPaths.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/objectPaths.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/sharpComment.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/sharpComment.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/simpleAssignment.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/simpleAssignment.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/singleLineComments.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/singleLineComments.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/slashComment.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/slashComment.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/unsettingOperator.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/unsettingOperator.test.ts [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/valueModificationOperator.test.expected [new file with mode: 0644]
plugins/typoScript/testData/typoscript/lexer/valueModificationOperator.test.ts [new file with mode: 0644]
plugins/typoScript/tests/com/jetbrains/typoscript/TypoScriptLexerTest.java [new file with mode: 0644]
plugins/typoScript/typoScript.iml [new file with mode: 0644]

diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/TypoScriptElementTypes.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/TypoScriptElementTypes.java
new file mode 100644 (file)
index 0000000..1400cf6
--- /dev/null
@@ -0,0 +1,54 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.PsiElement;
+import com.intellij.lang.ASTNode;
+import com.jetbrains.typoscript.lang.psi.impl.*;
+
+public interface TypoScriptElementTypes {
+
+  IElementType ASSIGNMENT = new TypoScriptTokenType("ASSIGNMENT");
+  IElementType CODE_BLOCK = new TypoScriptTokenType("CODE_BLOCK");
+  IElementType CONDITION_ELEMENT = new TypoScriptTokenType("CONDITION_ELEMENT");
+  IElementType COPYING = new TypoScriptTokenType("COPYING");
+  IElementType INCLUDE_STATEMENT_ELEMENT = new TypoScriptTokenType("INCLUDE_STATEMENT_ELEMENT");
+  IElementType MULTILINE_VALUE_ASSIGNMENT = new TypoScriptTokenType("MULTILINE_VALUE_ASSIGNMENT");
+  IElementType OBJECT_PATH = new TypoScriptTokenType("OBJECT_PATH");
+  IElementType UNSETTING = new TypoScriptTokenType("UNSETTING");
+  IElementType VALUE_MODIFICATION = new TypoScriptTokenType("VALUE_MODIFICATION");
+
+  class Factory {
+    public static PsiElement createElement(ASTNode node) {
+      IElementType type = node.getElementType();
+       if (type == ASSIGNMENT) {
+        return new AssignmentImpl(node);
+      }
+      else if (type == CODE_BLOCK) {
+        return new CodeBlockImpl(node);
+      }
+      else if (type == CONDITION_ELEMENT) {
+        return new ConditionElementImpl(node);
+      }
+      else if (type == COPYING) {
+        return new CopyingImpl(node);
+      }
+      else if (type == INCLUDE_STATEMENT_ELEMENT) {
+        return new IncludeStatementElementImpl(node);
+      }
+      else if (type == MULTILINE_VALUE_ASSIGNMENT) {
+        return new MultilineValueAssignmentImpl(node);
+      }
+      else if (type == OBJECT_PATH) {
+        return new ObjectPathImpl(node);
+      }
+      else if (type == UNSETTING) {
+        return new UnsettingImpl(node);
+      }
+      else if (type == VALUE_MODIFICATION) {
+        return new ValueModificationImpl(node);
+      }
+      throw new AssertionError("Unknown element type: " + type);
+    }
+  }
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/TypoScriptGeneratedParser.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/TypoScriptGeneratedParser.java
new file mode 100644 (file)
index 0000000..528b6d1
--- /dev/null
@@ -0,0 +1,487 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang;
+
+import org.jetbrains.annotations.*;
+import com.intellij.lang.LighterASTNode;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiBuilder.Marker;
+import com.intellij.openapi.diagnostic.Logger;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import static com.jetbrains.typoscript.lang.TypoScriptParserUtil.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.tree.TokenSet;
+import com.intellij.lang.PsiParser;
+import static com.jetbrains.typoscript.lang.TypoScriptTokenTypes.*;
+
+@SuppressWarnings({"SimplifiableIfStatement", "UnusedAssignment"})
+public class TypoScriptGeneratedParser implements PsiParser {
+
+  public static Logger LOG_ = Logger.getInstance("com.jetbrains.typoscript.lang.TypoScriptGeneratedParser");
+
+  @NotNull
+  public ASTNode parse(final IElementType root_, final PsiBuilder builder_) {
+    int level_ = 0;
+    boolean result_;
+    if (root_ == ASSIGNMENT) {
+      result_ = assignment(builder_, level_ + 1);
+    }
+    else if (root_ == CODE_BLOCK) {
+      result_ = code_block(builder_, level_ + 1);
+    }
+    else if (root_ == CONDITION_ELEMENT) {
+      result_ = condition_element(builder_, level_ + 1);
+    }
+    else if (root_ == COPYING) {
+      result_ = copying(builder_, level_ + 1);
+    }
+    else if (root_ == INCLUDE_STATEMENT_ELEMENT) {
+      result_ = include_statement_element(builder_, level_ + 1);
+    }
+    else if (root_ == MULTILINE_VALUE_ASSIGNMENT) {
+      result_ = multiline_value_assignment(builder_, level_ + 1);
+    }
+    else if (root_ == OBJECT_PATH) {
+      result_ = object_path(builder_, level_ + 1);
+    }
+    else if (root_ == UNSETTING) {
+      result_ = unsetting(builder_, level_ + 1);
+    }
+    else if (root_ == VALUE_MODIFICATION) {
+      result_ = value_modification(builder_, level_ + 1);
+    }
+    else {
+      Marker marker_ = builder_.mark();
+      result_ = parse_root_(root_, builder_, level_);
+      while (builder_.getTokenType() != null) {
+        builder_.advanceLexer();
+      }
+      marker_.done(root_);
+    }
+    return builder_.getTreeBuilt();
+  }
+
+  protected boolean parse_root_(final IElementType root_, final PsiBuilder builder_, final int level_) {
+    return file(builder_, level_ + 1);
+  }
+
+  /* ********************************************************** */
+  // object_path '=' ASSIGNMENT_VALUE?
+  public static boolean assignment(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "assignment")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path(builder_, level_ + 1);
+    pinned_ = result_; // pin = 1
+    result_ = result_ && report_error_(builder_, consumeToken(builder_, ASSIGNMENT_OPERATOR));
+    result_ = pinned_ && assignment_2(builder_, level_ + 1) && result_;
+    if (result_ || pinned_) {
+      marker_.done(ASSIGNMENT);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  // ASSIGNMENT_VALUE?
+  private static boolean assignment_2(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "assignment_2")) return false;
+    consumeToken(builder_, ASSIGNMENT_VALUE);
+    return true;
+  }
+
+  /* ********************************************************** */
+  // object_path '{' IGNORED_TEXT? expression* '}' IGNORED_TEXT?
+  public static boolean code_block(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "code_block")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path(builder_, level_ + 1);
+    result_ = result_ && consumeToken(builder_, CODE_BLOCK_OPERATOR_BEGIN);
+    pinned_ = result_; // pin = 2
+    result_ = result_ && report_error_(builder_, code_block_2(builder_, level_ + 1));
+    result_ = pinned_ && report_error_(builder_, code_block_3(builder_, level_ + 1)) && result_;
+    result_ = pinned_ && report_error_(builder_, consumeToken(builder_, CODE_BLOCK_OPERATOR_END)) && result_;
+    result_ = pinned_ && code_block_5(builder_, level_ + 1) && result_;
+    if (result_ || pinned_) {
+      marker_.done(CODE_BLOCK);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  // IGNORED_TEXT?
+  private static boolean code_block_2(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "code_block_2")) return false;
+    consumeToken(builder_, IGNORED_TEXT);
+    return true;
+  }
+
+  // expression*
+  private static boolean code_block_3(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "code_block_3")) return false;
+    int offset_ = builder_.getCurrentOffset();
+    while (true) {
+      if (!expression(builder_, level_ + 1)) break;
+      int next_offset_ = builder_.getCurrentOffset();
+      if (offset_ == next_offset_) {
+        empty_element_parsed_guard_(builder_, offset_, "code_block_3");
+        break;
+      }
+      offset_ = next_offset_;
+    }
+    return true;
+  }
+
+  // IGNORED_TEXT?
+  private static boolean code_block_5(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "code_block_5")) return false;
+    consumeToken(builder_, IGNORED_TEXT);
+    return true;
+  }
+
+  /* ********************************************************** */
+  // CONDITION
+  public static boolean condition_element(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "condition_element")) return false;
+    if (!nextTokenIs(builder_, CONDITION)) return false;
+    boolean result_ = false;
+    final Marker marker_ = builder_.mark();
+    result_ = consumeToken(builder_, CONDITION);
+    if (result_) {
+      marker_.done(CONDITION_ELEMENT);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    return result_;
+  }
+
+  /* ********************************************************** */
+  // object_path '<' object_path_on_same_line
+  public static boolean copying(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "copying")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path(builder_, level_ + 1);
+    result_ = result_ && consumeToken(builder_, COPYING_OPERATOR);
+    pinned_ = result_; // pin = 2
+    result_ = result_ && isObjectPathOnSameLine(builder_, level_ + 1);
+    if (result_ || pinned_) {
+      marker_.done(COPYING);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  /* ********************************************************** */
+  // value_modification | multiline_value_assignment | copying | unsetting | code_block | assignment
+  // | condition_element | include_statement_element
+  static boolean expression(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "expression")) return false;
+    boolean result_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_RECOVER_);
+    result_ = value_modification(builder_, level_ + 1);
+    if (!result_) result_ = multiline_value_assignment(builder_, level_ + 1);
+    if (!result_) result_ = copying(builder_, level_ + 1);
+    if (!result_) result_ = unsetting(builder_, level_ + 1);
+    if (!result_) result_ = code_block(builder_, level_ + 1);
+    if (!result_) result_ = assignment(builder_, level_ + 1);
+    if (!result_) result_ = condition_element(builder_, level_ + 1);
+    if (!result_) result_ = include_statement_element(builder_, level_ + 1);
+    if (!result_) {
+      marker_.rollbackTo();
+    }
+    else {
+      marker_.drop();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, false, _SECTION_RECOVER_, top_expression_recover_parser_);
+    return result_;
+  }
+
+  /* ********************************************************** */
+  // (expression)*
+  static boolean file(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "file")) return false;
+    int offset_ = builder_.getCurrentOffset();
+    while (true) {
+      if (!file_0(builder_, level_ + 1)) break;
+      int next_offset_ = builder_.getCurrentOffset();
+      if (offset_ == next_offset_) {
+        empty_element_parsed_guard_(builder_, offset_, "file");
+        break;
+      }
+      offset_ = next_offset_;
+    }
+    return true;
+  }
+
+  // (expression)
+  private static boolean file_0(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "file_0")) return false;
+    boolean result_ = false;
+    final Marker marker_ = builder_.mark();
+    result_ = expression(builder_, level_ + 1);
+    if (!result_) {
+      marker_.rollbackTo();
+    }
+    else {
+      marker_.drop();
+    }
+    return result_;
+  }
+
+  /* ********************************************************** */
+  // INCLUDE_STATEMENT
+  public static boolean include_statement_element(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "include_statement_element")) return false;
+    if (!nextTokenIs(builder_, INCLUDE_STATEMENT)) return false;
+    boolean result_ = false;
+    final Marker marker_ = builder_.mark();
+    result_ = consumeToken(builder_, INCLUDE_STATEMENT);
+    if (result_) {
+      marker_.done(INCLUDE_STATEMENT_ELEMENT);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    return result_;
+  }
+
+  /* ********************************************************** */
+  // object_path MULTILINE_VALUE_OPERATOR_BEGIN IGNORED_TEXT? (MULTILINE_VALUE)* MULTILINE_VALUE_OPERATOR_END IGNORED_TEXT?
+  public static boolean multiline_value_assignment(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "multiline_value_assignment")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path(builder_, level_ + 1);
+    result_ = result_ && consumeToken(builder_, MULTILINE_VALUE_OPERATOR_BEGIN);
+    pinned_ = result_; // pin = 2
+    result_ = result_ && report_error_(builder_, multiline_value_assignment_2(builder_, level_ + 1));
+    result_ = pinned_ && report_error_(builder_, multiline_value_assignment_3(builder_, level_ + 1)) && result_;
+    result_ = pinned_ && report_error_(builder_, consumeToken(builder_, MULTILINE_VALUE_OPERATOR_END)) && result_;
+    result_ = pinned_ && multiline_value_assignment_5(builder_, level_ + 1) && result_;
+    if (result_ || pinned_) {
+      marker_.done(MULTILINE_VALUE_ASSIGNMENT);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  // IGNORED_TEXT?
+  private static boolean multiline_value_assignment_2(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "multiline_value_assignment_2")) return false;
+    consumeToken(builder_, IGNORED_TEXT);
+    return true;
+  }
+
+  // (MULTILINE_VALUE)*
+  private static boolean multiline_value_assignment_3(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "multiline_value_assignment_3")) return false;
+    int offset_ = builder_.getCurrentOffset();
+    while (true) {
+      if (!multiline_value_assignment_3_0(builder_, level_ + 1)) break;
+      int next_offset_ = builder_.getCurrentOffset();
+      if (offset_ == next_offset_) {
+        empty_element_parsed_guard_(builder_, offset_, "multiline_value_assignment_3");
+        break;
+      }
+      offset_ = next_offset_;
+    }
+    return true;
+  }
+
+  // (MULTILINE_VALUE)
+  private static boolean multiline_value_assignment_3_0(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "multiline_value_assignment_3_0")) return false;
+    boolean result_ = false;
+    final Marker marker_ = builder_.mark();
+    result_ = consumeToken(builder_, MULTILINE_VALUE);
+    if (!result_) {
+      marker_.rollbackTo();
+    }
+    else {
+      marker_.drop();
+    }
+    return result_;
+  }
+
+  // IGNORED_TEXT?
+  private static boolean multiline_value_assignment_5(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "multiline_value_assignment_5")) return false;
+    consumeToken(builder_, IGNORED_TEXT);
+    return true;
+  }
+
+  /* ********************************************************** */
+  // '.'? (OBJECT_PATH_ENTITY '.')* OBJECT_PATH_ENTITY
+  public static boolean object_path(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "object_path")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path_0(builder_, level_ + 1);
+    result_ = result_ && object_path_1(builder_, level_ + 1);
+    pinned_ = result_; // pin = 2
+    result_ = result_ && consumeToken(builder_, OBJECT_PATH_ENTITY);
+    if (result_ || pinned_) {
+      marker_.done(OBJECT_PATH);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  // '.'?
+  private static boolean object_path_0(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "object_path_0")) return false;
+    consumeToken(builder_, OBJECT_PATH_SEPARATOR);
+    return true;
+  }
+
+  // (OBJECT_PATH_ENTITY '.')*
+  private static boolean object_path_1(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "object_path_1")) return false;
+    int offset_ = builder_.getCurrentOffset();
+    while (true) {
+      if (!object_path_1_0(builder_, level_ + 1)) break;
+      int next_offset_ = builder_.getCurrentOffset();
+      if (offset_ == next_offset_) {
+        empty_element_parsed_guard_(builder_, offset_, "object_path_1");
+        break;
+      }
+      offset_ = next_offset_;
+    }
+    return true;
+  }
+
+  // (OBJECT_PATH_ENTITY '.')
+  private static boolean object_path_1_0(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "object_path_1_0")) return false;
+    return object_path_1_0_0(builder_, level_ + 1);
+  }
+
+  // OBJECT_PATH_ENTITY '.'
+  private static boolean object_path_1_0_0(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "object_path_1_0_0")) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = consumeToken(builder_, OBJECT_PATH_ENTITY);
+    result_ = result_ && consumeToken(builder_, OBJECT_PATH_SEPARATOR);
+    pinned_ = result_; // pin = 2
+    if (!result_ && !pinned_) {
+      marker_.rollbackTo();
+    }
+    else {
+      marker_.drop();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  /* ********************************************************** */
+  // ! new_line_white_space
+  static boolean top_expression_recover(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "top_expression_recover")) return false;
+    boolean result_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_NOT_);
+    result_ = !isAfterNewLine(builder_, level_ + 1);
+    marker_.rollbackTo();
+    result_ = exitErrorRecordingSection(builder_, result_, level_, false, _SECTION_NOT_, null);
+    return result_;
+  }
+
+  /* ********************************************************** */
+  // object_path '>' IGNORED_TEXT?
+  public static boolean unsetting(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "unsetting")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path(builder_, level_ + 1);
+    result_ = result_ && consumeToken(builder_, UNSETTING_OPERATOR);
+    pinned_ = result_; // pin = 2
+    result_ = result_ && unsetting_2(builder_, level_ + 1);
+    if (result_ || pinned_) {
+      marker_.done(UNSETTING);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  // IGNORED_TEXT?
+  private static boolean unsetting_2(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "unsetting_2")) return false;
+    consumeToken(builder_, IGNORED_TEXT);
+    return true;
+  }
+
+  /* ********************************************************** */
+  // object_path ':=' MODIFICATION_OPERATOR_FUNCTION MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN
+  //   MODIFICATION_OPERATOR_FUNCTION_ARGUMENT MODIFICATION_OPERATOR_FUNCTION_PARAM_END
+  public static boolean value_modification(PsiBuilder builder_, int level_) {
+    if (!recursion_guard_(builder_, level_, "value_modification")) return false;
+    if (!nextTokenIs(builder_, OBJECT_PATH_ENTITY) && !nextTokenIs(builder_, OBJECT_PATH_SEPARATOR)) return false;
+    boolean result_ = false;
+    boolean pinned_ = false;
+    final Marker marker_ = builder_.mark();
+    enterErrorRecordingSection(builder_, level_, _SECTION_GENERAL_);
+    result_ = object_path(builder_, level_ + 1);
+    result_ = result_ && consumeToken(builder_, MODIFICATION_OPERATOR);
+    pinned_ = result_; // pin = 2
+    result_ = result_ && report_error_(builder_, consumeToken(builder_, MODIFICATION_OPERATOR_FUNCTION));
+    result_ = pinned_ && report_error_(builder_, consumeToken(builder_, MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN)) && result_;
+    result_ = pinned_ && report_error_(builder_, consumeToken(builder_, MODIFICATION_OPERATOR_FUNCTION_ARGUMENT)) && result_;
+    result_ = pinned_ && consumeToken(builder_, MODIFICATION_OPERATOR_FUNCTION_PARAM_END) && result_;
+    if (result_ || pinned_) {
+      marker_.done(VALUE_MODIFICATION);
+    }
+    else {
+      marker_.rollbackTo();
+    }
+    result_ = exitErrorRecordingSection(builder_, result_, level_, pinned_, _SECTION_GENERAL_, null);
+    return result_ || pinned_;
+  }
+
+  final static Parser top_expression_recover_parser_ = new Parser() {
+      public boolean parse(PsiBuilder builder_, int level_) {
+        return top_expression_recover(builder_, level_ + 1);
+      }
+    };
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Assignment.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Assignment.java
new file mode 100644 (file)
index 0000000..a7ae1a2
--- /dev/null
@@ -0,0 +1,13 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface Assignment extends TypoScriptCompositeElement {
+
+  @NotNull
+  ObjectPath getObjectPath();
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/CodeBlock.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/CodeBlock.java
new file mode 100644 (file)
index 0000000..acc80db
--- /dev/null
@@ -0,0 +1,37 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface CodeBlock extends TypoScriptCompositeElement {
+
+  @NotNull
+  List<Assignment> getAssignmentList();
+
+  @NotNull
+  List<CodeBlock> getCodeBlockList();
+
+  @NotNull
+  List<ConditionElement> getConditionElementList();
+
+  @NotNull
+  List<Copying> getCopyingList();
+
+  @NotNull
+  List<IncludeStatementElement> getIncludeStatementElementList();
+
+  @NotNull
+  List<MultilineValueAssignment> getMultilineValueAssignmentList();
+
+  @NotNull
+  ObjectPath getObjectPath();
+
+  @NotNull
+  List<Unsetting> getUnsettingList();
+
+  @NotNull
+  List<ValueModification> getValueModificationList();
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ConditionElement.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ConditionElement.java
new file mode 100644 (file)
index 0000000..d63ba4c
--- /dev/null
@@ -0,0 +1,10 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface ConditionElement extends TypoScriptCompositeElement {
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Copying.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Copying.java
new file mode 100644 (file)
index 0000000..4f2b03a
--- /dev/null
@@ -0,0 +1,13 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface Copying extends TypoScriptCompositeElement {
+
+  @NotNull
+  ObjectPath getObjectPath();
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/IncludeStatementElement.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/IncludeStatementElement.java
new file mode 100644 (file)
index 0000000..7a06092
--- /dev/null
@@ -0,0 +1,10 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface IncludeStatementElement extends TypoScriptCompositeElement {
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/MultilineValueAssignment.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/MultilineValueAssignment.java
new file mode 100644 (file)
index 0000000..51a828c
--- /dev/null
@@ -0,0 +1,13 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface MultilineValueAssignment extends TypoScriptCompositeElement {
+
+  @NotNull
+  ObjectPath getObjectPath();
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ObjectPath.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ObjectPath.java
new file mode 100644 (file)
index 0000000..ea37168
--- /dev/null
@@ -0,0 +1,10 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface ObjectPath extends TypoScriptCompositeElement {
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Unsetting.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Unsetting.java
new file mode 100644 (file)
index 0000000..d3e4032
--- /dev/null
@@ -0,0 +1,13 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface Unsetting extends TypoScriptCompositeElement {
+
+  @NotNull
+  ObjectPath getObjectPath();
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ValueModification.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/ValueModification.java
new file mode 100644 (file)
index 0000000..0ad6526
--- /dev/null
@@ -0,0 +1,13 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface ValueModification extends TypoScriptCompositeElement {
+
+  @NotNull
+  ObjectPath getObjectPath();
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Visitor.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/Visitor.java
new file mode 100644 (file)
index 0000000..8d3745d
--- /dev/null
@@ -0,0 +1,49 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi;
+
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElementVisitor;
+
+public class Visitor extends PsiElementVisitor {
+
+  public void visitAssignment(@NotNull Assignment o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitCodeBlock(@NotNull CodeBlock o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitConditionElement(@NotNull ConditionElement o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitCopying(@NotNull Copying o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitIncludeStatementElement(@NotNull IncludeStatementElement o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitMultilineValueAssignment(@NotNull MultilineValueAssignment o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitObjectPath(@NotNull ObjectPath o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitUnsetting(@NotNull Unsetting o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitValueModification(@NotNull ValueModification o) {
+    visitTypoScriptCompositeElement(o);
+  }
+
+  public void visitTypoScriptCompositeElement(@NotNull TypoScriptCompositeElement o) {
+    visitElement(o);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/AssignmentImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/AssignmentImpl.java
new file mode 100644 (file)
index 0000000..96fb606
--- /dev/null
@@ -0,0 +1,31 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class AssignmentImpl extends TypoScriptCompositeElementImpl implements Assignment {
+
+  public AssignmentImpl(ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  @NotNull
+  public ObjectPath getObjectPath() {
+    return findNotNullChildByClass(ObjectPath.class);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitAssignment(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/CodeBlockImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/CodeBlockImpl.java
new file mode 100644 (file)
index 0000000..8faf50d
--- /dev/null
@@ -0,0 +1,79 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class CodeBlockImpl extends TypoScriptCompositeElementImpl implements CodeBlock {
+
+  public CodeBlockImpl(ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  @NotNull
+  public List<Assignment> getAssignmentList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, Assignment.class);
+  }
+
+  @Override
+  @NotNull
+  public List<CodeBlock> getCodeBlockList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, CodeBlock.class);
+  }
+
+  @Override
+  @NotNull
+  public List<ConditionElement> getConditionElementList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, ConditionElement.class);
+  }
+
+  @Override
+  @NotNull
+  public List<Copying> getCopyingList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, Copying.class);
+  }
+
+  @Override
+  @NotNull
+  public List<IncludeStatementElement> getIncludeStatementElementList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, IncludeStatementElement.class);
+  }
+
+  @Override
+  @NotNull
+  public List<MultilineValueAssignment> getMultilineValueAssignmentList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, MultilineValueAssignment.class);
+  }
+
+  @Override
+  @NotNull
+  public ObjectPath getObjectPath() {
+    return findNotNullChildByClass(ObjectPath.class);
+  }
+
+  @Override
+  @NotNull
+  public List<Unsetting> getUnsettingList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, Unsetting.class);
+  }
+
+  @Override
+  @NotNull
+  public List<ValueModification> getValueModificationList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, ValueModification.class);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitCodeBlock(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ConditionElementImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ConditionElementImpl.java
new file mode 100644 (file)
index 0000000..62efff8
--- /dev/null
@@ -0,0 +1,25 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class ConditionElementImpl extends TypoScriptCompositeElementImpl implements ConditionElement {
+
+  public ConditionElementImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitConditionElement(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/CopyingImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/CopyingImpl.java
new file mode 100644 (file)
index 0000000..c0f0d9e
--- /dev/null
@@ -0,0 +1,31 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class CopyingImpl extends TypoScriptCompositeElementImpl implements Copying {
+
+  public CopyingImpl(ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  @NotNull
+  public ObjectPath getObjectPath() {
+    return findNotNullChildByClass(ObjectPath.class);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitCopying(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/IncludeStatementElementImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/IncludeStatementElementImpl.java
new file mode 100644 (file)
index 0000000..f26afc8
--- /dev/null
@@ -0,0 +1,25 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class IncludeStatementElementImpl extends TypoScriptCompositeElementImpl implements IncludeStatementElement {
+
+  public IncludeStatementElementImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitIncludeStatementElement(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/MultilineValueAssignmentImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/MultilineValueAssignmentImpl.java
new file mode 100644 (file)
index 0000000..6ce9968
--- /dev/null
@@ -0,0 +1,31 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class MultilineValueAssignmentImpl extends TypoScriptCompositeElementImpl implements MultilineValueAssignment {
+
+  public MultilineValueAssignmentImpl(ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  @NotNull
+  public ObjectPath getObjectPath() {
+    return findNotNullChildByClass(ObjectPath.class);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitMultilineValueAssignment(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ObjectPathImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ObjectPathImpl.java
new file mode 100644 (file)
index 0000000..7f95ddb
--- /dev/null
@@ -0,0 +1,25 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class ObjectPathImpl extends TypoScriptCompositeElementImpl implements ObjectPath {
+
+  public ObjectPathImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitObjectPath(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/UnsettingImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/UnsettingImpl.java
new file mode 100644 (file)
index 0000000..4e6d268
--- /dev/null
@@ -0,0 +1,31 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class UnsettingImpl extends TypoScriptCompositeElementImpl implements Unsetting {
+
+  public UnsettingImpl(ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  @NotNull
+  public ObjectPath getObjectPath() {
+    return findNotNullChildByClass(ObjectPath.class);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitUnsetting(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ValueModificationImpl.java b/plugins/typoScript/gen/com/jetbrains/typoscript/lang/psi/impl/ValueModificationImpl.java
new file mode 100644 (file)
index 0000000..10f42e3
--- /dev/null
@@ -0,0 +1,31 @@
+// This is a generated file. Not intended for manual editing.
+package com.jetbrains.typoscript.lang.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.jetbrains.typoscript.lang.TypoScriptElementTypes.*;
+import com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl;
+import com.jetbrains.typoscript.lang.psi.*;
+
+public class ValueModificationImpl extends TypoScriptCompositeElementImpl implements ValueModification {
+
+  public ValueModificationImpl(ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  @NotNull
+  public ObjectPath getObjectPath() {
+    return findNotNullChildByClass(ObjectPath.class);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof Visitor) ((Visitor)visitor).visitValueModification(this);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/plugins/typoScript/resources/icons/condition_ts.png b/plugins/typoScript/resources/icons/condition_ts.png
new file mode 100644 (file)
index 0000000..c255ccf
Binary files /dev/null and b/plugins/typoScript/resources/icons/condition_ts.png differ
diff --git a/plugins/typoScript/resources/icons/include_ts.png b/plugins/typoScript/resources/icons/include_ts.png
new file mode 100644 (file)
index 0000000..08ad8e5
Binary files /dev/null and b/plugins/typoScript/resources/icons/include_ts.png differ
diff --git a/plugins/typoScript/resources/icons/property_ts.png b/plugins/typoScript/resources/icons/property_ts.png
new file mode 100644 (file)
index 0000000..0671c39
Binary files /dev/null and b/plugins/typoScript/resources/icons/property_ts.png differ
diff --git a/plugins/typoScript/resources/icons/typo3.png b/plugins/typoScript/resources/icons/typo3.png
new file mode 100644 (file)
index 0000000..5fe6c7b
Binary files /dev/null and b/plugins/typoScript/resources/icons/typo3.png differ
diff --git a/plugins/typoScript/resources/messages/TypoScriptBundle.properties b/plugins/typoScript/resources/messages/TypoScriptBundle.properties
new file mode 100644 (file)
index 0000000..a81b445
--- /dev/null
@@ -0,0 +1,14 @@
+color.settings.name=TypoScript
+color.settings.one.line.comment=Line comment
+color.settings.multiline.comment=Block comment
+color.settings.operator=Operation
+color.settings.string=String
+color.settings.object.path=Object path element
+color.settings.object.path.separator=Dot
+color.settings.assigned.value=Assigned value
+color.settings.bad.character=Bad character
+color.settings.ignored.text=Ignored text
+color.settings.condition=Condition
+color.settings.include=Include
+file.type.registration.warning=<html>{0} files are not associated with TypoScript file type. <a href=\"fix\">Fix</a>?</html>
+plugin.title=TypoScript Support
\ No newline at end of file
diff --git a/plugins/typoScript/src/META-INF/plugin.xml b/plugins/typoScript/src/META-INF/plugin.xml
new file mode 100644 (file)
index 0000000..40e201f
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<idea-plugin version="2">
+
+  <id>com.jetbrains.typoscript</id>
+  <name>TypoScript Support</name>
+
+  <description>Typo3 language TypoScript support</description>
+
+  <version>0.1.0</version>
+  <idea-version since-build="107.89"/>
+
+  <vendor logo="/general/ijLogo.png">JetBrains</vendor>
+  <depends>com.intellij.modules.lang</depends>
+  <resource-bundle>resources.messages.TypoScriptBundle</resource-bundle>
+
+  <extensions defaultExtensionNs="com.intellij">
+    <fileTypeFactory implementation="com.jetbrains.typoscript.lang.TypoScriptFileTypeFactory"/>
+    <syntaxHighlighter key="TypoScript" implementationClass="com.jetbrains.typoscript.lang.highlighter.TypoScriptSyntaxHighlighter"/>
+    <colorSettingsPage implementation="com.jetbrains.typoscript.lang.highlighter.TypoScriptColorsAndFontsPage"/>
+
+    <lang.parserDefinition language="TypoScript" implementationClass="com.jetbrains.typoscript.lang.TypoScriptParserDefinition"/>
+    <lang.braceMatcher language="TypoScript" implementationClass="com.jetbrains.typoscript.lang.TypoScriptBraceMatcher"/>
+
+    <lang.foldingBuilder language="TypoScript" implementationClass="com.jetbrains.typoscript.lang.TypoScriptFoldingBuilder"/>
+
+    <lang.psiStructureViewFactory language="TypoScript" implementationClass="com.jetbrains.typoscript.lang.TypoScriptStructureViewFactory"/>
+  </extensions>
+
+  <application-components>
+    <component>
+      <implementation-class>com.jetbrains.typoscript.TypoScriptExtensionMappingChecker</implementation-class>
+    </component>
+  </application-components>
+</idea-plugin>
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptBundle.java b/plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptBundle.java
new file mode 100644 (file)
index 0000000..dd0bfb8
--- /dev/null
@@ -0,0 +1,37 @@
+package com.jetbrains.typoscript;
+
+import com.intellij.CommonBundle;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.ResourceBundle;
+
+/**
+ * @author lene
+ *         Date: 12.04.12
+ */
+public class TypoScriptBundle {
+  @NonNls public static String NOTIFICATION_ID = "TypoScript";
+  private static Reference<ResourceBundle> ourBundle;
+
+  @NonNls public static final String TYPOSCRIPT_BUNDLE = "messages.TypoScriptBundle";
+
+  private TypoScriptBundle() {
+  }
+
+  public static String message(@PropertyKey(resourceBundle = TYPOSCRIPT_BUNDLE) String key, Object... params) {
+    return CommonBundle.message(getBundle(), key, params);
+  }
+
+  private static ResourceBundle getBundle() {
+    ResourceBundle bundle = null;
+    if (ourBundle != null) bundle = ourBundle.get();
+    if (bundle == null) {
+      bundle = ResourceBundle.getBundle(TYPOSCRIPT_BUNDLE);
+      ourBundle = new SoftReference<ResourceBundle>(bundle);
+    }
+    return bundle;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptExtensionMappingChecker.java b/plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptExtensionMappingChecker.java
new file mode 100644 (file)
index 0000000..66985dd
--- /dev/null
@@ -0,0 +1,118 @@
+package com.jetbrains.typoscript;
+
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationListener;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
+import com.intellij.openapi.application.AccessToken;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.*;
+import com.intellij.util.containers.hash.HashMap;
+import com.jetbrains.typoscript.lang.TypoScriptFileType;
+import com.jetbrains.typoscript.lang.TypoScriptFileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.event.HyperlinkEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * @author lene
+ *         Date: 24.04.12
+ */
+public class TypoScriptExtensionMappingChecker implements ApplicationComponent {
+  private static final Logger LOG = Logger.getInstance(TypoScriptExtensionMappingChecker.class);
+  private final FileTypeManager myFileTypeManager;
+
+  public TypoScriptExtensionMappingChecker(final FileTypeManager fileTypeManager) {
+    myFileTypeManager = fileTypeManager;
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return getClass().getName();
+  }
+
+  public void initComponent() {
+    checkFileTypeAssociation();
+  }
+
+  public void disposeComponent() {
+  }
+
+  private void checkFileTypeAssociation() {
+    final Map<FileNameMatcher, FileType> fileNames = getNonTSMatchers(TypoScriptFileTypeFactory.FILE_NAME_MATCHERS);
+    if (!fileNames.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      boolean addComma = false;
+      for (Map.Entry<FileNameMatcher, FileType> entry : fileNames.entrySet()) {
+        if (addComma) {
+          sb.append(", ");
+        }
+        sb.append(entry.getKey().getPresentableString());
+        addComma |= true;
+      }
+      final String fileMatchers = sb.toString();
+
+      ApplicationManager.getApplication().invokeLater(new Runnable() {
+        public void run() {
+          Notifications.Bus.notify(
+            new Notification(TypoScriptBundle.NOTIFICATION_ID, TypoScriptBundle.message("plugin.title"),
+                             TypoScriptBundle.message("file.type.registration.warning", fileMatchers),
+                             NotificationType.WARNING, new NotificationListener() {
+              public void hyperlinkUpdate(@NotNull final Notification notification, @NotNull final HyperlinkEvent event) {
+                fixAssociation(fileNames.keySet());
+                notification.expire();
+              }
+            }), null);
+        }
+      });
+    }
+  }
+
+  @NotNull
+  private Map<FileNameMatcher, FileType> getNonTSMatchers(@NotNull Collection<? extends FileNameMatcher> matchers) {
+    final Map<FileNameMatcher, FileType> fileNames = new HashMap<FileNameMatcher, FileType>();
+    for (FileNameMatcher matcher : matchers) {
+      FileType registered;
+      if (matcher instanceof ExtensionFileNameMatcher) {
+        registered = myFileTypeManager.getFileTypeByExtension(((ExtensionFileNameMatcher)matcher).getExtension());
+      }
+      else if (matcher instanceof ExactFileNameMatcher) {
+        registered = myFileTypeManager.getFileTypeByFileName(((ExactFileNameMatcher)matcher).getFileName());
+      }
+      else {
+        LOG.error("Unexpected FileNameMatcher class " + matcher.getClass() + " for " + matcher.getPresentableString());
+        break;
+      }
+      if (registered != TypoScriptFileType.INSTANCE) {
+        fileNames.put(matcher, registered);
+      }
+    }
+    return fileNames;
+  }
+
+  private void fixAssociation(@NotNull Collection<FileNameMatcher> fileNameMatchers) {
+    final Map<FileNameMatcher, FileType> refreshedFileNames = getNonTSMatchers(fileNameMatchers);
+    if (!refreshedFileNames.isEmpty()) {
+      final AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass());
+      try {
+        doFixAssociation(refreshedFileNames);
+      }
+      finally {
+        token.finish();
+      }
+    }
+  }
+
+  @SuppressWarnings("deprecation")
+  private void doFixAssociation(@NotNull Map<FileNameMatcher, FileType> fileNames) {
+    for (Map.Entry<FileNameMatcher, FileType> entry : fileNames.entrySet()) {
+      myFileTypeManager.removeAssociation(entry.getValue(), entry.getKey());
+    }
+    myFileTypeManager.registerFileType(TypoScriptFileType.INSTANCE, new ArrayList<FileNameMatcher>(fileNames.keySet()));
+  }
+}
\ No newline at end of file
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptIcons.java b/plugins/typoScript/src/com/jetbrains/typoscript/TypoScriptIcons.java
new file mode 100644 (file)
index 0000000..c460cf2
--- /dev/null
@@ -0,0 +1,15 @@
+package com.jetbrains.typoscript;
+
+import com.intellij.openapi.util.IconLoader;
+
+import javax.swing.*;
+
+/**
+ * @author lene
+ *         Date: 20.04.12
+ */
+public interface TypoScriptIcons {
+  Icon CONDITION_ICON = IconLoader.getIcon("/icons/condition_ts.png");
+  Icon PROPERTY_ICON = IconLoader.getIcon("/icons/property_ts.png");
+  Icon INCLUDE_ICON = IconLoader.getIcon("/icons/include_ts.png");
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/GeneratedParserUtilBase.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/GeneratedParserUtilBase.java
new file mode 100644 (file)
index 0000000..460fc68
--- /dev/null
@@ -0,0 +1,676 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lang.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringHash;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.TokenType;
+import com.intellij.psi.impl.source.resolve.FileContextUtil;
+import com.intellij.psi.impl.source.tree.CompositePsiElement;
+import com.intellij.psi.tree.ICompositeElementType;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+import com.intellij.util.containers.LimitedPool;
+import gnu.trove.THashSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+* @author gregsh
+*/
+@SuppressWarnings("StringEquality")
+public class GeneratedParserUtilBase {
+
+  private static final Logger LOG = Logger.getInstance("org.intellij.grammar.parser.GeneratedParserUtilBase");
+
+  public static final IElementType DUMMY_BLOCK = new DummyBlockElementType();
+
+  public interface Parser {
+    boolean parse(PsiBuilder builder, int level);
+  }
+
+  public static final Parser TOKEN_ADVANCER = new Parser() {
+    @Override
+    public boolean parse(PsiBuilder builder, int level) {
+      if (builder.eof()) return false;
+      builder.advanceLexer();
+      return true;
+    }
+  };
+
+  public static final Parser TRUE_CONDITION = new Parser() {
+    @Override
+    public boolean parse(PsiBuilder builder, int level) {
+      return true;
+    }
+  };
+
+  public static boolean recursion_guard_(PsiBuilder builder_, int level_, String funcName_) {
+    if (level_ > 1000) {
+      builder_.error("Maximum recursion level (" + 1000 + ") reached in " + funcName_);
+      return false;
+    }
+    return true;
+  }
+
+  public static void empty_element_parsed_guard_(PsiBuilder builder_, int offset_, String funcName_) {
+    builder_.error("Empty element parsed in " + funcName_ +" at offset " + offset_);
+  }
+
+  public static boolean invalid_left_marker_guard_(PsiBuilder builder_, PsiBuilder.Marker marker_, String funcName_) {
+    //builder_.error("Invalid left marker encountered in " + funcName_ +" at offset " + builder_.getCurrentOffset());
+    boolean goodMarker = marker_ != null && ((LighterASTNode)marker_).getTokenType() != TokenType.ERROR_ELEMENT;
+    if (!goodMarker) return false;
+    ErrorState state = ErrorState.get(builder_);
+
+    Frame frame = state.levelCheck.isEmpty() ? null : state.levelCheck.getLast();
+    return frame == null || frame.errorReportedAt <= builder_.getCurrentOffset();
+  }
+
+  public static boolean consumeToken(PsiBuilder builder_, IElementType token) {
+    if (nextTokenIsInner(builder_, token, true)) {
+      builder_.advanceLexer();
+      return true;
+    }
+    return false;
+  }
+
+  public static boolean nextTokenIs(PsiBuilder builder_, IElementType token) {
+    return nextTokenIsInner(builder_, token, false);
+  }
+
+  public static boolean nextTokenIsInner(PsiBuilder builder_, IElementType token, boolean force) {
+    ErrorState state = ErrorState.get(builder_);
+    if (state.completionState != null && !force) return true;
+    IElementType tokenType = builder_.getTokenType();
+    if (!state.suppressErrors && state.predicateCount < 2) {
+      addVariant(state, builder_, token);
+    }
+    return token == tokenType;
+  }
+
+  public static void addVariant(PsiBuilder builder_, String text) {
+    addVariant(ErrorState.get(builder_), builder_, text);
+  }
+
+  private static void addVariant(ErrorState state, PsiBuilder builder_, Object o) {
+    final int offset = builder_.getCurrentOffset();
+    Variant variant = state.VARIANTS.alloc();
+    variant.init(offset, o, state.predicateSign);
+    state.variants.add(variant);
+    if (variant.expected && state.lastExpectedVariantOffset < variant.offset) {
+      state.lastExpectedVariantOffset = variant.offset;
+    }
+
+    CompletionState completionState = state.completionState;
+    if (completionState != null && state.predicateSign) {
+      addCompletionVariant(state, completionState, builder_, o, offset);
+    }
+  }
+
+  public static boolean consumeToken(PsiBuilder builder_, String text) {
+    ErrorState state = ErrorState.get(builder_);
+    if (!state.suppressErrors && state.predicateCount < 2) {
+      addVariant(state, builder_, text);
+    }
+    return consumeTokenInner(builder_, text, state.caseSensitive);
+  }
+
+  public static boolean consumeTokenInner(PsiBuilder builder_, String text, boolean caseSensitive) {
+    final CharSequence sequence = builder_.getOriginalText();
+    final int offset = builder_.getCurrentOffset();
+    final int endOffset = offset + text.length();
+    CharSequence tokenText = sequence.subSequence(offset, Math.min(endOffset, sequence.length()));
+
+    if (Comparing.equal(text, tokenText, caseSensitive)) {
+      int count = 0;
+      while (true) {
+        final int nextOffset = builder_.rawTokenTypeStart(++ count);
+        if (nextOffset > endOffset) {
+          return false;
+        }
+        else if (nextOffset == endOffset) {
+          break;
+        }
+      }
+      while (count-- > 0) builder_.advanceLexer();
+      return true;
+    }
+    return false;
+  }
+
+  private static void addCompletionVariant(ErrorState state,
+                                           CompletionState completionState,
+                                           PsiBuilder builder_,
+                                           Object o,
+                                           int offset) {
+    boolean add = false;
+    int diff = completionState.offset - offset;
+    String text = completionState.convertItem(o);
+    int length = text == null? 0 : text.length();
+    if (length == 0) return;
+    if (diff == 0) {
+      add = true;
+    }
+    else if (diff > 0 && diff <= length) {
+      CharSequence fragment = builder_.getOriginalText().subSequence(offset, completionState.offset);
+      add = StringUtil.startsWithIgnoreCase(text, fragment.toString());
+    }
+    else if (diff < 0) {
+      for (int i=-1; ; i--) {
+        IElementType type = builder_.rawLookup(i);
+        int tokenStart = builder_.rawTokenTypeStart(i);
+        if (state.whitespaceTokens.contains(type) || state.commentTokens.contains(type)) {
+          diff = completionState.offset - tokenStart;
+        }
+        else if (type != null && tokenStart < completionState.offset) {
+          CharSequence fragment = builder_.getOriginalText().subSequence(tokenStart, completionState.offset);
+          if (StringUtil.startsWithIgnoreCase(text, fragment.toString())) {
+            diff = completionState.offset - tokenStart;
+          }
+          break;
+        }
+        else break;
+      }
+      add = diff >= 0 && diff < length;
+    }
+    add = add && length > 1 && !(text.charAt(0) == '<' && text.charAt(length - 1) == '>') &&
+          !(text.charAt(0) == '\'' && text.charAt(length - 1) == '\'' && length < 5);
+    if (add) {
+      completionState.items.add(text);
+    }
+  }
+
+
+  public static final String _SECTION_NOT_ = "_SECTION_NOT_";
+  public static final String _SECTION_AND_ = "_SECTION_AND_";
+  public static final String _SECTION_RECOVER_ = "_SECTION_RECOVER_";
+  public static final String _SECTION_GENERAL_ = "_SECTION_GENERAL_";
+
+  public static void enterErrorRecordingSection(PsiBuilder builder_, int key, @NotNull String sectionType) {
+    ErrorState state = ErrorState.get(builder_);
+    state.levelCheck.add(new Frame(builder_.getCurrentOffset(), key, sectionType));
+    if (sectionType == _SECTION_AND_) {
+      if (state.predicateCount == 0 && !state.predicateSign) {
+        throw new AssertionError("Incorrect false predicate sign");
+      }
+      state.predicateCount++;
+    }
+    else if (sectionType == _SECTION_NOT_) {
+      if (state.predicateCount == 0) {
+        state.predicateSign = false;
+      }
+      else {
+        state.predicateSign = !state.predicateSign;
+      }
+      state.predicateCount++;
+    }
+  }
+
+  public static boolean exitErrorRecordingSection(PsiBuilder builder_,
+                                                  boolean result,
+                                                  int key,
+                                                  boolean pinned,
+                                                  @NotNull String sectionType,
+                                                  @Nullable Parser eatMore) {
+    ErrorState state = ErrorState.get(builder_);
+
+    Frame frame = null;
+    int initialOffset = builder_.getCurrentOffset();
+    if (state.levelCheck.isEmpty() || key != (frame = state.levelCheck.removeLast()).level || !sectionType.equals(frame.section)) {
+      LOG.error("Unbalanced error section: got " + new Frame(initialOffset, key, sectionType) + ", expected " + frame);
+      return result;
+    }
+    if (sectionType == _SECTION_AND_ || sectionType == _SECTION_NOT_) {
+      state.predicateCount--;
+      if (sectionType == _SECTION_NOT_) state.predicateSign = !state.predicateSign;
+      return result;
+    }
+    if (sectionType == _SECTION_RECOVER_ && !state.suppressErrors && eatMore != null) {
+      state.suppressErrors = true;
+      final boolean eatMoreFlagOnce = !builder_.eof() && eatMore.parse(builder_, frame.level + 1);
+      final int lastErrorPos = getLastVariantOffset(state, initialOffset);
+      boolean eatMoreFlag = eatMoreFlagOnce || frame.offset == initialOffset && lastErrorPos > frame.offset;
+
+      final LighterASTNode latestDoneMarker =
+        (pinned || result) && lastErrorPos > initialOffset && eatMoreFlagOnce ? builder_.getLatestDoneMarker() : null;
+      PsiBuilder.Marker extensionMarker = null;
+      IElementType extensionTokenType = null;
+      if (latestDoneMarker instanceof PsiBuilder.Marker) {
+        extensionMarker = ((PsiBuilder.Marker)latestDoneMarker).precede();
+        extensionTokenType = latestDoneMarker.getTokenType();
+        ((PsiBuilder.Marker)latestDoneMarker).drop();
+      }
+      // advance to the last error pos
+      // skip tokens until lastErrorPos. parseAsTree might look better here...
+      int parenCount = 0;
+      while (eatMoreFlag && builder_.getCurrentOffset() < lastErrorPos) {
+        if (state.braces != null) {
+          if (builder_.getTokenType() == state.braces[0].getLeftBraceType()) parenCount ++;
+          else if (builder_.getTokenType() == state.braces[0].getRightBraceType()) parenCount --;
+        }
+        builder_.advanceLexer();
+        eatMoreFlag = parenCount != 0 || eatMore.parse(builder_, frame.level + 1);
+      }
+      boolean errorReported = frame.errorReportedAt == initialOffset;
+      if (errorReported) {
+        if (eatMoreFlag) {
+          builder_.advanceLexer();
+          parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore);
+        }
+      }
+      else if (eatMoreFlag) {
+        String tokenText = builder_.getTokenText();
+        String expectedText = state.getExpectedText(builder_);
+        PsiBuilder.Marker mark = builder_.mark();
+        builder_.advanceLexer();
+        final String gotText = !expectedText.isEmpty() ? "got '" + tokenText + "'" : "'" + tokenText + "' unexpected";
+        mark.error(expectedText + gotText);
+        parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore);
+        errorReported = true;
+      }
+      else if (eatMoreFlagOnce || (!result && frame.offset != builder_.getCurrentOffset())) {
+        reportError(state, builder_, true);
+        errorReported = true;
+      }
+      if (extensionMarker != null) {
+        extensionMarker.done(extensionTokenType);
+      }
+      state.suppressErrors = false;
+      if (errorReported || result) {
+        state.clearExpectedVariants();
+      }
+      if (!result && eatMoreFlagOnce && frame.offset != builder_.getCurrentOffset()) result = true;
+    }
+    else if (!result && pinned && frame.errorReportedAt < 0) {
+      // do not report if there're errors after current offset
+      if (getLastVariantOffset(state, initialOffset) == initialOffset) {
+        // do not force, inner recoverRoot might have skipped some tokens
+        if (reportError(state, builder_, false)) {
+          frame.errorReportedAt = initialOffset;
+        }
+      }
+    }
+    // propagate errorReportedAt up the stack to avoid duplicate reporting
+    Frame prevFrame = state.levelCheck.isEmpty() ? null : state.levelCheck.getLast();
+    if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt) prevFrame.errorReportedAt = frame.errorReportedAt;
+    return result;
+  }
+
+  public static boolean report_error_(PsiBuilder builder_, boolean current_) {
+    if (!current_) report_error_(builder_);
+    return current_;
+  }
+
+  public static void report_error_(PsiBuilder builder_) {
+    ErrorState state = ErrorState.get(builder_);
+
+    Frame frame = state.levelCheck.isEmpty()? null : state.levelCheck.getLast();
+    if (frame == null) {
+      LOG.error("Unbalanced error section: got null , expected " + frame);
+      return;
+    }
+    int offset = builder_.getCurrentOffset();
+    if (frame.errorReportedAt < offset && getLastVariantOffset(state, builder_.getCurrentOffset()) <= offset) {
+      if (reportError(state, builder_, true)) {
+        frame.errorReportedAt = offset;
+      }
+    }
+  }
+
+  static int getLastVariantOffset(ErrorState state, int defValue) {
+    return state.lastExpectedVariantOffset < 0? defValue : state.lastExpectedVariantOffset;
+  }
+
+  private static boolean reportError(ErrorState state, PsiBuilder builder_, boolean force) {
+    String expectedText = state.getExpectedText(builder_);
+    boolean notEmpty = StringUtil.isNotEmpty(expectedText);
+    if (force || notEmpty) {
+      final String gotText = builder_.eof()? "unexpected end of file" :
+                             notEmpty? "got '" + builder_.getTokenText() +"'" :
+                             "'" + builder_.getTokenText() +"' unexpected";
+      builder_.error(expectedText + gotText);
+      return true;
+    }
+    return false;
+  }
+
+
+  private static final Key<ErrorState> ERROR_STATE_KEY = Key.create("ERROR_STATE_KEY");
+  public static final Key<CompletionState> COMPLETION_STATE_KEY = Key.create("COMPLETION_STATE_KEY");
+
+  public static class CompletionState {
+    public final int offset;
+    public final Collection<String> items = new THashSet<String>();
+
+    public CompletionState(int offset) {
+      this.offset = offset;
+    }
+
+    @Nullable
+    public String convertItem(Object o) {
+      return o.toString();
+    }
+  }
+
+  public static class ErrorState {
+    int predicateCount;
+    boolean predicateSign = true;
+    boolean suppressErrors;
+    final LinkedList<Frame> levelCheck = new LinkedList<Frame>();
+    CompletionState completionState;
+
+    private boolean caseSensitive;
+    private BracePair[] braces;
+    private TokenSet whitespaceTokens = TokenSet.EMPTY;
+    private TokenSet commentTokens = TokenSet.EMPTY;
+
+    private int lastExpectedVariantOffset = -1;
+    ArrayList<Variant> variants = new ArrayList<Variant>();
+    final LimitedPool<Variant> VARIANTS = new LimitedPool<Variant>(5000, new LimitedPool.ObjectFactory<Variant>() {
+      public Variant create() {
+        return new Variant();
+      }
+
+      public void cleanup(final Variant v) {
+      }
+    });
+
+
+    public static ErrorState get(PsiBuilder builder) {
+      ErrorState state = builder.getUserDataUnprotected(ERROR_STATE_KEY);
+      if (state == null) {
+        builder.putUserDataUnprotected(ERROR_STATE_KEY, state = new ErrorState());
+        PsiFile file = builder.getUserDataUnprotected(FileContextUtil.CONTAINING_FILE_KEY);
+        state.completionState = file == null? null: file.getUserData(COMPLETION_STATE_KEY);
+        if (file != null) {
+          Language language = file.getLanguage();
+          state.caseSensitive = language.isCaseSensitive();
+          PairedBraceMatcher matcher = LanguageBraceMatching.INSTANCE.forLanguage(language);
+          state.braces = matcher == null? null : matcher.getPairs();
+          if (state.braces != null && state.braces.length == 0) state.braces = null;
+          ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
+          if (parserDefinition != null) {
+            state.commentTokens = parserDefinition.getCommentTokens();
+            state.whitespaceTokens = parserDefinition.getWhitespaceTokens();
+          }
+        }
+      }
+      return state;
+    }
+
+    public String getExpectedText(PsiBuilder builder_) {
+      int offset = builder_.getCurrentOffset();
+      StringBuilder sb = new StringBuilder();
+      if (addExpected(sb, offset, true)) {
+        sb.append(" expected, ");
+      }
+      else if (addExpected(sb, offset, false)) sb.append(" unexpected, ");
+      return sb.toString();
+    }
+
+    private static final int MAX_VARIANTS_TO_DISPLAY = Integer.MAX_VALUE;
+    private boolean addExpected(StringBuilder sb, int offset, boolean expected) {
+      String[] strings = new String[variants.size()];
+      long[] hashes = new long[strings.length];
+      Arrays.fill(strings, "");
+      int count = 0;
+      loop: for (Variant variant : variants) {
+        if (offset == variant.offset) {
+          if (variant.expected != expected) continue;
+          String text = variant.object.toString();
+          long hash = StringHash.calc(text);
+          for (int i=0; i<count; i++) {
+            if (hashes[i] == hash) continue loop;
+          }
+          hashes[count] = hash;
+          strings[count] = text;
+          count++;
+        }
+      }
+      Arrays.sort(strings);
+      count = 0;
+      for (String s : strings) {
+        if (s == "") continue;
+        if (count++ > 0) {
+          if (count > MAX_VARIANTS_TO_DISPLAY) {
+            sb.append(" and ...");
+            break;
+          }
+          else {
+            sb.append(", ");
+          }
+        }
+        char c = s.charAt(0);
+        String displayText = c == '<' || StringUtil.isJavaIdentifierStart(c) ? s : '\'' + s + '\'';
+        sb.append(displayText);
+      }
+      if (count > 1 && count < MAX_VARIANTS_TO_DISPLAY) {
+        int idx = sb.lastIndexOf(", ");
+        sb.replace(idx, idx + 1, " or");
+      }
+      return count > 0;
+    }
+
+    void clearExpectedVariants() {
+      lastExpectedVariantOffset = -1;
+      for (Variant v : variants) {
+        VARIANTS.recycle(v);
+      }
+      variants.clear();
+    }
+  }
+
+  public static class Frame {
+    int offset;
+    int level;
+    String section;
+    int errorReportedAt = -1;
+
+    public Frame(int offset, int level, String section) {
+      this.offset = offset;
+      this.level = level;
+      this.section = section;
+    }
+
+    @Override
+    public String toString() {
+      return "<"+offset+", "+section+", "+level+">";
+    }
+  }
+
+
+  public static class Variant {
+    int offset;
+    Object object;
+    boolean expected;
+
+    public void init(int offset, Object text, boolean expected) {
+      this.offset = offset;
+      this.object = text;
+      this.expected = expected;
+    }
+
+    @Override
+    public String toString() {
+      return "<" + offset + ", " + expected + ", " + object + ">";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      Variant variant = (Variant)o;
+
+      if (expected != variant.expected) return false;
+      if (offset != variant.offset) return false;
+      if (!this.object.equals(variant.object)) return false;
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int result = offset;
+      result = 31 * result + object.hashCode();
+      result = 31 * result + (expected ? 1 : 0);
+      return result;
+    }
+  }
+
+  @Nullable
+  private static IElementType getClosingBracket(ErrorState state, IElementType type) {
+    if (state.braces == null) return null;
+    for (BracePair pair : state.braces) {
+      if (type == pair.getLeftBraceType()) return pair.getRightBraceType();
+    }
+    return null;
+  }
+
+
+  private static final int MAX_CHILDREN_IN_TREE = 10;
+  public static boolean parseAsTree(ErrorState state, final PsiBuilder builder_, int level, final IElementType chunkType,
+                                    boolean checkBraces, final Parser parser, final Parser eatMoreCondition) {
+    final LinkedList<Pair<PsiBuilder.Marker, PsiBuilder.Marker>> parenList = new LinkedList<Pair<PsiBuilder.Marker, PsiBuilder.Marker>>();
+    final LinkedList<Pair<PsiBuilder.Marker, Integer>> siblingList = new LinkedList<Pair<PsiBuilder.Marker, Integer>>();
+    PsiBuilder.Marker marker = null;
+
+    final Runnable checkSiblingsRunnable = new Runnable() {
+      public void run() {
+        main:
+        while (!siblingList.isEmpty()) {
+          final Pair<PsiBuilder.Marker, PsiBuilder.Marker> parenPair = parenList.peek();
+          final int rating = siblingList.getFirst().second;
+          int count = 0;
+          for (Pair<PsiBuilder.Marker, Integer> pair : siblingList) {
+            if (pair.second != rating || parenPair != null && pair.first == parenPair.second) break main;
+            if (++count >= MAX_CHILDREN_IN_TREE) {
+              final PsiBuilder.Marker parentMarker = pair.first.precede();
+              while (count-- > 0) {
+                siblingList.removeFirst();
+              }
+              parentMarker.done(chunkType);
+              siblingList.addFirst(Pair.create(parentMarker, rating + 1));
+              continue main;
+            }
+          }
+          break;
+        }
+      }
+    };
+    boolean checkParens = state.braces != null && checkBraces;
+    int totalCount = 0;
+    int tokenCount = 0;
+    if (checkParens && builder_.rawLookup(-1) == state.braces[0].getLeftBraceType()) {
+      LighterASTNode doneMarker = builder_.getLatestDoneMarker();
+      if (doneMarker != null && doneMarker.getStartOffset() == builder_.rawTokenTypeStart(-1) && doneMarker.getTokenType() == TokenType.ERROR_ELEMENT) {
+        parenList.add(Pair.create(((PsiBuilder.Marker)doneMarker).precede(), (PsiBuilder.Marker)null));
+      }
+    }
+    while (true) {
+      final IElementType tokenType = builder_.getTokenType();
+      if (checkParens && (tokenType == state.braces[0].getLeftBraceType() || tokenType == state.braces[0].getRightBraceType() && !parenList.isEmpty())) {
+        if (marker != null) {
+          marker.done(chunkType);
+          siblingList.addFirst(Pair.create(marker, 1));
+          marker = null;
+          tokenCount = 0;
+        }
+        if (tokenType == state.braces[0].getLeftBraceType()) {
+          final Pair<PsiBuilder.Marker, Integer> prev = siblingList.peek();
+          parenList.addFirst(Pair.create(builder_.mark(), prev == null ? null : prev.first));
+        }
+        checkSiblingsRunnable.run();
+        builder_.advanceLexer();
+        if (tokenType == state.braces[0].getRightBraceType()) {
+          final Pair<PsiBuilder.Marker, PsiBuilder.Marker> pair = parenList.removeFirst();
+          pair.first.done(chunkType);
+          // drop all markers inside parens
+          while (!siblingList.isEmpty() && siblingList.getFirst().first != pair.second) {
+            siblingList.removeFirst();
+          }
+          siblingList.addFirst(Pair.create(pair.first, 1));
+          checkSiblingsRunnable.run();
+        }
+      }
+      else {
+        if (marker == null) {
+          marker = builder_.mark();
+        }
+        final boolean result = eatMoreCondition.parse(builder_, level + 1) && parser.parse(builder_, level + 1);
+        if (result) {
+          tokenCount++;
+          totalCount++;
+        }
+        if (!result) {
+          break;
+        }
+      }
+
+      if (tokenCount >= MAX_CHILDREN_IN_TREE && marker != null) {
+        marker.done(chunkType);
+        siblingList.addFirst(Pair.create(marker, 1));
+        checkSiblingsRunnable.run();
+        marker = null;
+        tokenCount = 0;
+      }
+    }
+    if (marker != null) {
+      marker.drop();
+    }
+    for (Pair<PsiBuilder.Marker, PsiBuilder.Marker> pair : parenList) {
+      pair.first.drop();
+    }
+    return totalCount != 0;
+  }
+
+  private static class DummyBlockElementType extends IElementType implements ICompositeElementType{
+    DummyBlockElementType() {
+      super("DUMMY_BLOCK", Language.ANY);
+    }
+
+    @NotNull
+    @Override
+    public ASTNode createCompositeNode() {
+      return new DummyBlock();
+    }
+  }
+
+  public static class DummyBlock extends CompositePsiElement {
+    DummyBlock() {
+      super(DUMMY_BLOCK);
+    }
+
+    @Override
+    public PsiReference[] getReferences() {
+      return PsiReference.EMPTY_ARRAY;
+    }
+
+    @Override
+    public boolean canNavigateToSource() {
+      return false;
+    }
+
+    @Override
+    public boolean canNavigate() {
+      return false;
+    }
+
+    @NotNull
+    @Override
+    public Language getLanguage() {
+      return getParent().getLanguage();
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.bnf b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.bnf
new file mode 100644 (file)
index 0000000..da64af8
--- /dev/null
@@ -0,0 +1,54 @@
+{
+
+  parserClass="com.jetbrains.typoscript.lang.TypoScriptGeneratedParser"
+  stubParserClass="com.jetbrains.typoscript.lang.TypoScriptParserUtil"
+  generateStubParser = true
+  tokenTypeClass="com.jetbrains.typoscript.lang.TypoScriptTokenType"
+  elementTypeClass="com.jetbrains.typoscript.lang.TypoScriptTokenType"
+  elementTypeHolderClass="com.jetbrains.typoscript.lang.TypoScriptElementTypes"
+  generateTokens=false
+  parserImports="static com.jetbrains.typoscript.lang.TypoScriptTokenTypes.*"
+
+  generatePsi=true
+  implements="com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElement"
+  extends="com.jetbrains.typoscript.lang.psi.TypoScriptCompositeElementImpl"
+
+  psiImplClassSuffix="Impl"
+  psiPackage="com.jetbrains.typoscript.lang.psi"
+  psiImplPackage="com.jetbrains.typoscript.lang.psi.impl"
+
+  CODE_BLOCK_OPERATOR_BEGIN = '{'
+  CODE_BLOCK_OPERATOR_END = '}'
+  MODIFICATION_OPERATOR = ':='
+  ASSIGNMENT_OPERATOR = '='
+  UNSETTING_OPERATOR = '>'
+  COPYING_OPERATOR = '<'
+  OBJECT_PATH_SEPARATOR = '.'
+}
+
+file ::= (expression)*
+private expression ::=  value_modification | multiline_value_assignment | copying | unsetting | code_block | assignment
+| condition_element | include_statement_element {recoverUntil="top_expression_recover"}
+private top_expression_recover ::= ! new_line_white_space
+external new_line_white_space ::= isAfterNewLine
+
+include_statement_element ::= INCLUDE_STATEMENT
+condition_element ::= CONDITION
+
+assignment ::= object_path '=' ASSIGNMENT_VALUE? {pin=1}
+
+value_modification ::= object_path ':=' MODIFICATION_OPERATOR_FUNCTION MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN
+  MODIFICATION_OPERATOR_FUNCTION_ARGUMENT MODIFICATION_OPERATOR_FUNCTION_PARAM_END {pin=2}
+
+multiline_value_assignment ::= object_path MULTILINE_VALUE_OPERATOR_BEGIN IGNORED_TEXT? (MULTILINE_VALUE)* MULTILINE_VALUE_OPERATOR_END IGNORED_TEXT? {pin=2}
+
+copying ::= object_path '<' object_path_on_same_line {pin=2}
+external object_path_on_same_line ::= isObjectPathOnSameLine
+
+unsetting ::= object_path '>' IGNORED_TEXT? {pin=2}
+
+code_block ::= object_path '{' IGNORED_TEXT? expression* '}' IGNORED_TEXT? {pin=2}
+
+object_path ::= '.'? (OBJECT_PATH_ENTITY '.')* OBJECT_PATH_ENTITY {pin(".*")=2}
+
+
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.flex b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.flex
new file mode 100644 (file)
index 0000000..1604775
--- /dev/null
@@ -0,0 +1,105 @@
+package com.jetbrains.typoscript.lang;
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import java.io.Reader;
+
+%%
+
+%{
+
+  public _TypoScriptLexer() {
+    this((Reader)null);
+  }
+%}
+
+%public
+%class _TypoScriptLexer
+%implements FlexLexer
+%function advance
+%type IElementType
+%unicode
+%eof{  return;
+%eof}
+
+NOT_WHITE_SPACE=[^\ \n\r\t\f]
+WHITE_SPACE_CHARS=[\ \n\r\t\f]*
+WHITESPACE_WITH_NEW_LINE = [\ \t\f]*(\n|\r|\r\n){WHITE_SPACE_CHARS}
+STRING_TAIL = [^\r\n]*
+ONE_LINE_COMMENT=("/"|"#"){STRING_TAIL}
+C_STYLE_COMMENT="/*" ~((\n|\r|\r\n){WHITE_SPACE_CHARS}"*/")
+ENDTRIMMED_STRING_TAIL = ({STRING_TAIL}{NOT_WHITE_SPACE})?
+TRIMMED_STRING_TAIL = {NOT_WHITE_SPACE}{ENDTRIMMED_STRING_TAIL}
+
+OBJECT_PATH_ENTITY = [A-Za-z0-9\-_]*
+
+%state EXPRESSION_SIGN
+%state ASSIGNMENT_VALUE
+%state ONE_LINE_IGNORED_ZONE
+
+%xstate COPYING_OPERATOR_VALUE
+
+%xstate MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE
+%xstate MULTILINE_OPERATOR_VALUE
+%xstate MULTILINE_NEW_LINE
+
+%xstate MODIFICATION_OPERATOR_VALUE
+%xstate MODIFICATION_OPERATOR_FUNCTION_ARGUMENT
+%%
+
+{WHITESPACE_WITH_NEW_LINE}                            { yybegin(YYINITIAL); return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE; }
+{WHITE_SPACE_CHARS}                                   { return TokenType.WHITE_SPACE; }
+
+<YYINITIAL> {ONE_LINE_COMMENT}                        { return TypoScriptTokenTypes.ONE_LINE_COMMENT; }
+<YYINITIAL> {C_STYLE_COMMENT}                         { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.C_STYLE_COMMENT; }
+<YYINITIAL> {OBJECT_PATH_ENTITY}                      { yybegin(EXPRESSION_SIGN); return TypoScriptTokenTypes.OBJECT_PATH_ENTITY; }
+<YYINITIAL> "."                                       { return TypoScriptTokenTypes.OBJECT_PATH_SEPARATOR; }
+<YYINITIAL> "["{ENDTRIMMED_STRING_TAIL}               { return TypoScriptTokenTypes.CONDITION; }
+
+
+<EXPRESSION_SIGN> {OBJECT_PATH_ENTITY}                { return TypoScriptTokenTypes.OBJECT_PATH_ENTITY; }
+<EXPRESSION_SIGN> "."                                 { return TypoScriptTokenTypes.OBJECT_PATH_SEPARATOR; }
+
+<COPYING_OPERATOR_VALUE> {OBJECT_PATH_ENTITY}         { return TypoScriptTokenTypes.OBJECT_PATH_ENTITY; }
+<COPYING_OPERATOR_VALUE> "."                          { return TypoScriptTokenTypes.OBJECT_PATH_SEPARATOR; }
+<COPYING_OPERATOR_VALUE> {WHITESPACE_WITH_NEW_LINE}   { yybegin(YYINITIAL); return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE; }
+<COPYING_OPERATOR_VALUE> {WHITE_SPACE_CHARS}          { return TokenType.WHITE_SPACE; }
+
+<EXPRESSION_SIGN>   "="                               { yybegin(ASSIGNMENT_VALUE); return TypoScriptTokenTypes.ASSIGNMENT_OPERATOR; }
+<EXPRESSION_SIGN>   ":="                              { yybegin(MODIFICATION_OPERATOR_VALUE); return TypoScriptTokenTypes.MODIFICATION_OPERATOR; }
+<EXPRESSION_SIGN>   ">"                               { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.UNSETTING_OPERATOR; }
+<EXPRESSION_SIGN>   "<"                               { yybegin(COPYING_OPERATOR_VALUE); return TypoScriptTokenTypes.COPYING_OPERATOR; }
+<YYINITIAL>         "<"{ENDTRIMMED_STRING_TAIL}       { return TypoScriptTokenTypes.INCLUDE_STATEMENT; }
+            //todo create "=<" reference sign for typoscript templates; or handle < in assignment value
+<EXPRESSION_SIGN>   "("                               { yybegin(MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE);
+                                                      return TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_BEGIN; }
+<EXPRESSION_SIGN>   "{"                               { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_BEGIN; }
+<YYINITIAL>         "{"{ENDTRIMMED_STRING_TAIL}       { return TypoScriptTokenTypes.IGNORED_TEXT; }
+<YYINITIAL>         "}"                               { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_END; }
+
+
+<ASSIGNMENT_VALUE>       {TRIMMED_STRING_TAIL}        { yybegin(YYINITIAL); return TypoScriptTokenTypes.ASSIGNMENT_VALUE; }
+<ONE_LINE_IGNORED_ZONE>  {STRING_TAIL}                { yybegin(YYINITIAL); return TypoScriptTokenTypes.IGNORED_TEXT; }
+
+
+<MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE>  {STRING_TAIL}                                       { yybegin(MULTILINE_OPERATOR_VALUE);
+                                                                                                    return TypoScriptTokenTypes.IGNORED_TEXT; }
+<MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE>  {WHITESPACE_WITH_NEW_LINE}                          { yybegin(MULTILINE_OPERATOR_VALUE);
+                                                                                                    return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE; }
+<MULTILINE_OPERATOR_VALUE>                    {WHITESPACE_WITH_NEW_LINE}                          { return TokenType.WHITE_SPACE; }
+<MULTILINE_OPERATOR_VALUE>                    [^\ \n\r\t\f\)]{ENDTRIMMED_STRING_TAIL}   { return TypoScriptTokenTypes.MULTILINE_VALUE; }
+<MULTILINE_OPERATOR_VALUE>                    ")"                                                 { yybegin(ONE_LINE_IGNORED_ZONE);
+                                                                                                    return TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_END; }
+
+<MODIFICATION_OPERATOR_VALUE>               ([^" "\r\n"("][^\r\n"("]*[^" "\r\n"("])|([^" "\r\n"("])   { return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION; }
+<MODIFICATION_OPERATOR_VALUE>               "("                                                       { yybegin(MODIFICATION_OPERATOR_FUNCTION_ARGUMENT);
+                                                                                                        return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN;}
+<MODIFICATION_OPERATOR_FUNCTION_ARGUMENT>   ([^" "\r\n")"][^\r\n")"]*[^" "\r\n")"])|([^" "\r\n")"])   { return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_ARGUMENT;}
+<MODIFICATION_OPERATOR_FUNCTION_ARGUMENT>   ")"                                                       { yybegin(ONE_LINE_IGNORED_ZONE);
+                                                                                                        return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_PARAM_END; }
+<MODIFICATION_OPERATOR_VALUE, MODIFICATION_OPERATOR_FUNCTION_ARGUMENT>   {WHITESPACE_WITH_NEW_LINE}   { yybegin(YYINITIAL); return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE; }
+<MODIFICATION_OPERATOR_VALUE, MODIFICATION_OPERATOR_FUNCTION_ARGUMENT>   {WHITE_SPACE_CHARS}          { return TokenType.WHITE_SPACE; }
+
+
+<YYINITIAL, EXPRESSION_SIGN, ASSIGNMENT_VALUE, ONE_LINE_IGNORED_ZONE, COPYING_OPERATOR_VALUE, MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE,
+ MULTILINE_OPERATOR_VALUE, MULTILINE_NEW_LINE, MODIFICATION_OPERATOR_VALUE, MODIFICATION_OPERATOR_FUNCTION_ARGUMENT> . {return TokenType.BAD_CHARACTER;}
\ No newline at end of file
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptBraceMatcher.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptBraceMatcher.java
new file mode 100644 (file)
index 0000000..dca0ddc
--- /dev/null
@@ -0,0 +1,47 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lang.BracePair;
+import com.intellij.lang.PairedBraceMatcher;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.PsiManagerEx;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtilCore;
+import com.jetbrains.typoscript.lang.psi.TypoScriptFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author lene
+ *         Date: 16.04.12
+ */
+public class TypoScriptBraceMatcher implements PairedBraceMatcher {
+
+  private static final BracePair[] PAIRS = new BracePair[]{
+    new BracePair(TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN,
+                  TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_PARAM_END, true),
+    new BracePair(TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_BEGIN, TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_END, false),
+    new BracePair(TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_BEGIN, TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_END, false)
+  };
+
+  @Override
+  public BracePair[] getPairs() {
+    return PAIRS;
+  }
+
+  @Override
+  public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
+    return true;
+  }
+
+  @Override
+  public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
+    if (file instanceof TypoScriptFile) {
+      PsiElement brace = PsiUtilCore.getElementAtOffset(file, openingBraceOffset);
+      PsiElement parent = brace.getParent();
+      return parent!=null? parent.getTextOffset():openingBraceOffset;
+    }
+    return openingBraceOffset;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFileType.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFileType.java
new file mode 100644 (file)
index 0000000..99ea281
--- /dev/null
@@ -0,0 +1,47 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.util.IconLoader;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * @author lene
+ *         Date: 03.04.12
+ */
+public class TypoScriptFileType extends LanguageFileType {
+  private static final Icon ICON = IconLoader.getIcon("/icons/typo3.png");
+
+  public static final TypoScriptFileType INSTANCE = new TypoScriptFileType();
+  public static final String DEFAULT_EXTENSION = "ts";
+
+  private TypoScriptFileType() {
+    super(TypoScriptLanguage.INSTANCE);
+  }
+
+  @NotNull
+  @Override
+  public String getName() {
+    return "TypoScript";
+  }
+
+  @NotNull
+  @Override
+  public String getDescription() {
+    return "TypoScript";
+  }
+
+  @NotNull
+  @Override
+  public String getDefaultExtension() {
+    return DEFAULT_EXTENSION;
+  }
+
+  @Override
+  public Icon getIcon() {
+    return ICON;
+  }
+}
+
+
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFileTypeFactory.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFileTypeFactory.java
new file mode 100644 (file)
index 0000000..2a2361a
--- /dev/null
@@ -0,0 +1,28 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.openapi.fileTypes.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptFileTypeFactory extends FileTypeFactory {
+
+  public static final List<? extends FileNameMatcher> FILE_NAME_MATCHERS =
+    Collections.unmodifiableList(Arrays.asList(new ExtensionFileNameMatcher(TypoScriptFileType.DEFAULT_EXTENSION),
+                                               new ExactFileNameMatcher("setup.txt"),
+                                               new ExactFileNameMatcher("constants.txt"),
+                                               new ExactFileNameMatcher("ext_conf_template.txt"),
+                                               new ExactFileNameMatcher("ext_typoscript_setup.txt"),
+                                               new ExactFileNameMatcher("ext_typoscript_constants.txt")));
+
+  @Override
+  public void createFileTypes(@NotNull FileTypeConsumer consumer) {
+    consumer.consume(TypoScriptFileType.INSTANCE, FILE_NAME_MATCHERS.toArray(new FileNameMatcher[FILE_NAME_MATCHERS.size()]));
+  }
+}
\ No newline at end of file
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFoldingBuilder.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptFoldingBuilder.java
new file mode 100644 (file)
index 0000000..5f15c16
--- /dev/null
@@ -0,0 +1,120 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.folding.FoldingBuilder;
+import com.intellij.lang.folding.FoldingDescriptor;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.tree.IElementType;
+import com.jetbrains.typoscript.lang.psi.CodeBlock;
+import com.jetbrains.typoscript.lang.psi.MultilineValueAssignment;
+import com.jetbrains.typoscript.lang.psi.TypoScriptFile;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author lene
+ *         Date: 18.04.12
+ */
+public class TypoScriptFoldingBuilder implements FoldingBuilder, DumbAware {
+  @NotNull
+  @Override
+  public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode node, @NotNull Document document) {
+    final PsiElement element = node.getPsi();
+    if (!(element instanceof TypoScriptFile)) {
+      return FoldingDescriptor.EMPTY;
+    }
+    final TypoScriptFile file = (TypoScriptFile)element;
+    final PsiElement[] children = file.getChildren();
+    Collection<FoldingDescriptor> result = new LinkedList<FoldingDescriptor>();
+    for (PsiElement child : children) {
+      if (child != null && (child instanceof CodeBlock || child instanceof MultilineValueAssignment || child instanceof PsiComment)) {
+        List<FoldingDescriptor> descriptors = new ArrayList<FoldingDescriptor>();
+        addFoldingDescriptors(descriptors, child, document);
+        result.addAll(descriptors);
+      }
+    }
+    return result.toArray(new FoldingDescriptor[result.size()]);
+  }
+
+  private static void addFoldingDescriptors(final List<FoldingDescriptor> descriptors,
+                                            final PsiElement element,
+                                            @NotNull Document document) {
+
+    TextRange elementRange = element.getTextRange();
+    final int start = elementRange.getStartOffset();
+    final int end = elementRange.getEndOffset();
+
+    if (start + 1 < end) {
+      TextRange range = null;
+      ASTNode astNode = element.getNode();
+      if (element instanceof CodeBlock) {
+        range =
+          buildRangeForBraces(range, astNode, TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_BEGIN, TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_END);
+        addFoldingDescriptorsFromChildren(descriptors, element, document);
+      }
+      else if (element instanceof MultilineValueAssignment) {
+        range = buildRangeForBraces(range, astNode, TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_BEGIN,
+                                    TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_END);
+      }
+      else if (element instanceof PsiComment && ((PsiComment)element).getTokenType() == TypoScriptTokenTypes.C_STYLE_COMMENT) {
+        int startIndex = astNode.getText().indexOf("/*");
+        int endIndex = astNode.getText().lastIndexOf("*/");
+        if (startIndex != -1 && startIndex + "/*".length() < endIndex) {
+          int startOffset = element.getTextRange().getStartOffset();
+          range = buildRange(range, startOffset + startIndex + "/*".length(), startOffset + endIndex);
+        }
+      }
+
+      if (range != null) {
+        descriptors.add(new FoldingDescriptor(astNode, range));
+      }
+    }
+  }
+
+  private static TextRange buildRangeForBraces(TextRange range,
+                                               @NotNull ASTNode astNode,
+                                               IElementType leftBraceType,
+                                               IElementType rightBraceType) {
+    ASTNode lBrace = astNode.findChildByType(leftBraceType);
+    ASTNode rBrace = astNode.findChildByType(rightBraceType);
+    if (lBrace != null && rBrace != null) {
+      range = buildRange(range, lBrace.getStartOffset() + 1, rBrace.getStartOffset());
+    }
+    return range;
+  }
+
+  private static TextRange buildRange(TextRange range, int leftOffset, int rightOffset) {
+    if (leftOffset + 1 < rightOffset) {
+      range = new TextRange(leftOffset, rightOffset);
+    }
+    return range;
+  }
+
+  private static void addFoldingDescriptorsFromChildren(List<FoldingDescriptor> descriptors,
+                                                        PsiElement element,
+                                                        @NotNull Document document) {
+    for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
+      if (child instanceof CodeBlock || child instanceof MultilineValueAssignment || child instanceof PsiComment) {
+        addFoldingDescriptors(descriptors, child, document);
+      }
+    }
+  }
+
+  @Override
+  public String getPlaceholderText(@NotNull ASTNode node) {
+    return "...";
+  }
+
+  @Override
+  public boolean isCollapsedByDefault(@NotNull ASTNode node) {
+    return false;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptLanguage.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptLanguage.java
new file mode 100644 (file)
index 0000000..23edd4b
--- /dev/null
@@ -0,0 +1,23 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
+import com.intellij.psi.templateLanguages.TemplateLanguage;
+
+/**
+ * @author lene
+ *         Date: 03.04.12
+ */
+public class TypoScriptLanguage extends Language {
+  public static final TypoScriptLanguage INSTANCE = new TypoScriptLanguage();
+
+  private TypoScriptLanguage() {
+    super("TypoScript", "");
+  }
+
+  @Override
+  public LanguageFileType getAssociatedFileType() {
+    return TypoScriptFileType.INSTANCE;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptLexer.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptLexer.java
new file mode 100644 (file)
index 0000000..d6e0e37
--- /dev/null
@@ -0,0 +1,15 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lexer.FlexAdapter;
+
+import java.io.Reader;
+
+/**
+ * @author lene
+ *         Date: 03.04.12
+ */
+public class TypoScriptLexer extends FlexAdapter {
+  public TypoScriptLexer() {
+    super(new _TypoScriptLexer((Reader)null));
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptParserDefinition.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptParserDefinition.java
new file mode 100644 (file)
index 0000000..43992d4
--- /dev/null
@@ -0,0 +1,71 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiParser;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.IStubFileElementType;
+import com.intellij.psi.tree.TokenSet;
+import com.jetbrains.typoscript.lang.psi.TypoScriptFile;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptParserDefinition implements ParserDefinition {
+  @NotNull
+  @Override
+  public Lexer createLexer(Project project) {
+    return new TypoScriptLexer();
+  }
+
+  @Override
+  public PsiParser createParser(Project project) {
+    return new TypoScriptGeneratedParser();
+  }
+
+  @Override
+  public IFileElementType getFileNodeType() {
+    return new IStubFileElementType(TypoScriptLanguage.INSTANCE);
+  }
+
+  @NotNull
+  @Override
+  public TokenSet getWhitespaceTokens() {
+    return TypoScriptTokenTypes.WHITESPACES;
+  }
+
+  @NotNull
+  @Override
+  public TokenSet getCommentTokens() {
+    return TypoScriptTokenTypes.COMMENTS;
+  }
+
+  @NotNull
+  @Override
+  public TokenSet getStringLiteralElements() {
+    return TypoScriptTokenTypes.STRING_LITERALS;
+  }
+
+  @NotNull
+  @Override
+  public PsiElement createElement(ASTNode node) {
+    return TypoScriptElementTypes.Factory.createElement(node);
+  }
+
+  @Override
+  public PsiFile createFile(FileViewProvider viewProvider) {
+    return new TypoScriptFile(viewProvider);
+  }
+
+  @Override
+  public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
+    return SpaceRequirements.MAY;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptParserUtil.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptParserUtil.java
new file mode 100644 (file)
index 0000000..437e06d
--- /dev/null
@@ -0,0 +1,27 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.psi.tree.IElementType;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptParserUtil extends GeneratedParserUtilBase {
+
+  static boolean isAfterNewLine(PsiBuilder builder, int level) {
+    return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE == builder.rawLookup(-1);// &&
+           //getLastVariantOffset(ErrorState.get(builder), builder.getCurrentOffset()) < builder.getCurrentOffset();
+  }
+
+
+  static boolean isObjectPathOnSameLine(PsiBuilder builder, int level) {
+    final IElementType type = builder.rawLookup(0);
+    if (TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE == type) {
+      nextTokenIs(builder, TypoScriptTokenTypes.OBJECT_PATH_SEPARATOR);
+      nextTokenIs(builder, TypoScriptTokenTypes.OBJECT_PATH_ENTITY);
+      return false;
+    }
+    return TypoScriptGeneratedParser.object_path(builder, level + 1);
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptStructureViewFactory.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptStructureViewFactory.java
new file mode 100644 (file)
index 0000000..1e5eba9
--- /dev/null
@@ -0,0 +1,162 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.ide.structureView.*;
+import com.intellij.ide.util.treeView.smartTree.TreeElement;
+import com.intellij.lang.PsiStructureViewFactory;
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.pom.Navigatable;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.PlatformIcons;
+import com.jetbrains.typoscript.TypoScriptIcons;
+import com.jetbrains.typoscript.lang.psi.*;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.ArrayList;
+
+/**
+ * @author lene
+ *         Date: 20.04.12
+ */
+public class TypoScriptStructureViewFactory implements PsiStructureViewFactory {
+  private static final Class[] SUITABLE_CLASSES =
+    new Class[]{Assignment.class, CodeBlock.class, ConditionElement.class, Copying.class, IncludeStatementElement.class,
+      MultilineValueAssignment.class, Unsetting.class, ValueModification.class};
+
+  @Override
+  public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
+
+    return new TreeBasedStructureViewBuilder() {
+      @NotNull
+      public StructureViewModel createStructureViewModel() {
+        return new Model(psiFile);
+      }
+
+      @Override
+      public boolean isRootNodeShown() {
+        return false;
+      }
+    };
+  }
+
+  private static class Model extends StructureViewModelBase implements StructureViewModel.ElementInfoProvider {
+
+    public Model(@NotNull PsiFile psiFile) {
+      super(psiFile, new Element(psiFile));
+      withSuitableClasses(SUITABLE_CLASSES);
+    }
+
+    @Override
+    public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
+      return false;
+    }
+
+    @Override
+    public boolean isAlwaysLeaf(StructureViewTreeElement element) {
+      Object psi = element.getValue();
+      return !(psi instanceof TypoScriptFile || psi instanceof CodeBlock);
+    }
+  }
+
+  private static class Element implements StructureViewTreeElement, ItemPresentation {
+    private final PsiElement myElement;
+
+    public Element(PsiElement element) {
+      this.myElement = element;
+    }
+
+    @Override
+    public Object getValue() {
+      return myElement;
+    }
+
+    @Override
+    public void navigate(boolean requestFocus) {
+      ((Navigatable)myElement).navigate(requestFocus);
+    }
+
+    @Override
+    public boolean canNavigate() {
+      return ((Navigatable)myElement).canNavigate();
+    }
+
+    @Override
+    public boolean canNavigateToSource() {
+      return ((Navigatable)myElement).canNavigateToSource();
+    }
+
+    @Override
+    public ItemPresentation getPresentation() {
+      return this;
+    }
+
+    @Override
+    public String getPresentableText() {
+      if (myElement instanceof TypoScriptFile) {
+        return myElement.getContainingFile().getName();
+      }
+      else if (myElement instanceof IncludeStatementElement) {
+        return myElement.getText();
+      }
+      else if (myElement instanceof ConditionElement) {
+        return myElement.getText();
+      }
+      ObjectPath objectPath = PsiTreeUtil.getChildOfType(myElement, ObjectPath.class);
+      if (objectPath != null) {
+        return objectPath.getText();
+      }
+      throw new AssertionError(myElement.getClass().getName() + " " + myElement.getText());
+    }
+
+    @Override
+    public String getLocationString() {
+      return null;
+    }
+
+    @Override
+    public Icon getIcon(boolean open) {
+      if (myElement instanceof TypoScriptFile) {
+        return myElement.getIcon(0);
+      }
+      else if (myElement instanceof IncludeStatementElement) {
+        return TypoScriptIcons.INCLUDE_ICON;
+      }
+      else if (myElement instanceof ConditionElement) {
+        return TypoScriptIcons.CONDITION_ICON;
+      }
+      else if (myElement instanceof CodeBlock) {
+        return PlatformIcons.FOLDER_ICON;
+      }
+      return TypoScriptIcons.PROPERTY_ICON;
+    }
+
+    @Override
+    public TreeElement[] getChildren() {
+      if (myElement instanceof TypoScriptFile || myElement instanceof CodeBlock) {
+        final ArrayList<TreeElement> result = new ArrayList<TreeElement>();
+        for (PsiElement child : myElement.getChildren()) {
+          if (isSuitable(child)) {
+            result.add(new Element(child));
+          }
+        }
+        return result.toArray(new TreeElement[result.size()]);
+      }
+      return new TreeElement[0];
+    }
+  }
+
+
+  private static boolean isSuitable(PsiElement element) {
+    if (!(element instanceof TypoScriptCompositeElement)) {
+      return false;
+    }
+    for (Class aClass : SUITABLE_CLASSES) {
+      if (aClass.isInstance(element)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptTokenType.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptTokenType.java
new file mode 100644 (file)
index 0000000..133e619
--- /dev/null
@@ -0,0 +1,16 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author lene
+ *         Date: 03.04.12
+ */
+public class TypoScriptTokenType extends IElementType {
+
+  public TypoScriptTokenType(@NotNull @NonNls final String debugName) {
+    super(debugName, TypoScriptLanguage.INSTANCE);
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptTokenTypes.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScriptTokenTypes.java
new file mode 100644 (file)
index 0000000..0544a7b
--- /dev/null
@@ -0,0 +1,50 @@
+package com.jetbrains.typoscript.lang;
+
+import com.intellij.psi.TokenType;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/**
+ * @author lene
+ *         Date: 03.04.12
+ */
+public interface TypoScriptTokenTypes extends TokenType {
+  IElementType C_STYLE_COMMENT = new TypoScriptTokenType("C_STYLE_COMMENT");
+  IElementType ONE_LINE_COMMENT = new TypoScriptTokenType("ONE_LINE_COMMENT");
+  IElementType IGNORED_TEXT = new TypoScriptTokenType("IGNORED_TEXT");
+  IElementType WHITE_SPACE_WITH_NEW_LINE = new TypoScriptTokenType("WHITE_SPACE_WITH_NEW_LINE");
+
+  IElementType ASSIGNMENT_OPERATOR = new TypoScriptTokenType("=");
+  IElementType ASSIGNMENT_VALUE = new TypoScriptTokenType("assignment value");
+
+  IElementType MULTILINE_VALUE_OPERATOR_BEGIN = new TypoScriptTokenType("(");
+  IElementType MULTILINE_VALUE_OPERATOR_END = new TypoScriptTokenType(")");
+  IElementType MULTILINE_VALUE = new TypoScriptTokenType("multiline value");
+
+  IElementType CODE_BLOCK_OPERATOR_BEGIN = new TypoScriptTokenType("{");
+  IElementType CODE_BLOCK_OPERATOR_END = new TypoScriptTokenType("}");
+
+  IElementType UNSETTING_OPERATOR = new TypoScriptTokenType(">");
+  IElementType COPYING_OPERATOR = new TypoScriptTokenType("<");
+
+  IElementType MODIFICATION_OPERATOR = new TypoScriptTokenType(":=");
+  IElementType MODIFICATION_OPERATOR_FUNCTION = new TypoScriptTokenType("modification function");
+  IElementType MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN = new TypoScriptTokenType("(");
+  IElementType MODIFICATION_OPERATOR_FUNCTION_PARAM_END = new TypoScriptTokenType(")");
+  IElementType MODIFICATION_OPERATOR_FUNCTION_ARGUMENT = new TypoScriptTokenType("modification value");
+
+  IElementType OBJECT_PATH_ENTITY = new TypoScriptTokenType("object path entity");
+  IElementType OBJECT_PATH_SEPARATOR = new TypoScriptTokenType(".");
+
+  IElementType INCLUDE_STATEMENT = new TypoScriptTokenType("INCLUDE");
+  IElementType CONDITION = new TypoScriptTokenType("CONDITION");
+
+  TokenSet OPERATORS = TokenSet.create(MODIFICATION_OPERATOR, ASSIGNMENT_OPERATOR,
+                                       MULTILINE_VALUE_OPERATOR_BEGIN, MULTILINE_VALUE_OPERATOR_END,
+                                       CODE_BLOCK_OPERATOR_BEGIN, CODE_BLOCK_OPERATOR_END,
+                                       UNSETTING_OPERATOR, COPYING_OPERATOR);
+
+  TokenSet WHITESPACES = TokenSet.create(WHITE_SPACE , WHITE_SPACE_WITH_NEW_LINE);
+  TokenSet COMMENTS = TokenSet.create(ONE_LINE_COMMENT, C_STYLE_COMMENT, IGNORED_TEXT);
+  TokenSet STRING_LITERALS = TokenSet.create(ASSIGNMENT_VALUE, MULTILINE_VALUE);
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/_TypoScriptLexer.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/_TypoScriptLexer.java
new file mode 100644 (file)
index 0000000..f3dbeeb
--- /dev/null
@@ -0,0 +1,649 @@
+/* The following code was generated by JFlex 1.4.3 on 17.04.12 19:23 */
+
+package com.jetbrains.typoscript.lang;
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import java.io.Reader;
+
+
+/**
+ * This class is a scanner generated by 
+ * <a href="http://www.jflex.de/">JFlex</a> 1.4.3
+ * on 17.04.12 19:23 from the specification file
+ * <tt>C:/opt/IDEA/plugins/typoScript/src/com/jetbrains/typoscript/lang/TypoScript.flex</tt>
+ */
+public class _TypoScriptLexer implements FlexLexer {
+  /** initial size of the lookahead buffer */
+  private static final int ZZ_BUFFERSIZE = 16384;
+
+  /** lexical states */
+  public static final int COPYING_OPERATOR_VALUE = 8;
+  public static final int ASSIGNMENT_VALUE = 4;
+  public static final int MODIFICATION_OPERATOR_VALUE = 16;
+  public static final int EXPRESSION_SIGN = 2;
+  public static final int ONE_LINE_IGNORED_ZONE = 6;
+  public static final int YYINITIAL = 0;
+  public static final int MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE = 10;
+  public static final int MULTILINE_OPERATOR_VALUE = 12;
+  public static final int MODIFICATION_OPERATOR_FUNCTION_ARGUMENT = 18;
+  public static final int MULTILINE_NEW_LINE = 14;
+
+  /**
+   * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
+   * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
+   *                  at the beginning of a line
+   * l is of the form l = 2*k, k a non negative integer
+   */
+  private static final int ZZ_LEXSTATE[] = { 
+     0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7, 
+     8,  8,  9, 9
+  };
+
+  /** 
+   * Translates characters to character classes
+   */
+  private static final String ZZ_CMAP_PACKED = 
+    "\11\0\1\2\1\3\1\0\1\2\1\1\22\0\1\22\2\0\1\5"+
+    "\4\0\1\16\1\21\1\6\2\0\1\7\1\10\1\4\12\7\1\13"+
+    "\1\0\1\15\1\12\1\14\2\0\32\7\1\11\3\0\1\7\1\0"+
+    "\32\7\1\17\1\0\1\20\uff82\0";
+
+  /** 
+   * Translates characters to character classes
+   */
+  private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
+
+  /** 
+   * Translates DFA states to action switch labels.
+   */
+  private static final int [] ZZ_ACTION = zzUnpackAction();
+
+  private static final String ZZ_ACTION_PACKED_0 =
+    "\4\1\1\2\1\3\2\0\2\1\1\4\1\5\1\1"+
+    "\2\6\1\7\1\10\1\11\1\12\1\13\1\14\1\2"+
+    "\1\15\1\4\1\16\1\17\1\20\1\21\1\22\1\23"+
+    "\1\3\1\24\1\25\1\1\1\4\1\26\2\27\1\30"+
+    "\2\31\1\32\1\6\3\0\1\33\4\0\1\1\1\0"+
+    "\1\1\3\0\1\34";
+
+  private static int [] zzUnpackAction() {
+    int [] result = new int[58];
+    int offset = 0;
+    offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackAction(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+
+  /** 
+   * Translates a state to a row index in the transition table
+   */
+  private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
+
+  private static final String ZZ_ROWMAP_PACKED_0 =
+    "\0\0\0\23\0\46\0\71\0\114\0\137\0\162\0\205"+
+    "\0\230\0\253\0\276\0\321\0\344\0\367\0\u010a\0\u011d"+
+    "\0\276\0\u0130\0\u0143\0\u0156\0\276\0\u0169\0\276\0\u017c"+
+    "\0\276\0\276\0\276\0\276\0\u018f\0\u01a2\0\u01b5\0\u01c8"+
+    "\0\u01db\0\u01ee\0\u0201\0\276\0\u0214\0\u0227\0\276\0\u023a"+
+    "\0\u024d\0\276\0\u0260\0\u0130\0\u0143\0\u0156\0\276\0\u018f"+
+    "\0\u01db\0\u0201\0\u0214\0\u0227\0\u023a\0\u024d\0\u0273\0\u0286"+
+    "\0\u0299\0\276";
+
+  private static int [] zzUnpackRowMap() {
+    int [] result = new int[58];
+    int offset = 0;
+    offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackRowMap(String packed, int offset, int [] result) {
+    int i = 0;  /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int high = packed.charAt(i++) << 16;
+      result[j++] = high | packed.charAt(i++);
+    }
+    return j;
+  }
+
+  /** 
+   * The transition table of the DFA
+   */
+  private static final int [] ZZ_TRANS = zzUnpackTrans();
+
+  private static final String ZZ_TRANS_PACKED_0 =
+    "\1\13\1\14\1\15\1\14\1\16\1\17\1\13\1\20"+
+    "\1\21\1\22\3\13\1\23\1\13\1\24\1\25\1\13"+
+    "\1\15\1\13\1\14\1\15\1\14\3\13\1\26\1\21"+
+    "\1\13\1\27\1\30\1\31\1\32\1\33\1\34\2\13"+
+    "\1\15\1\35\1\14\1\15\1\14\16\35\1\15\1\36"+
+    "\1\14\1\4\1\14\16\36\1\4\1\13\1\14\1\15"+
+    "\1\14\3\13\1\26\1\21\11\13\1\15\1\37\1\40"+
+    "\1\6\1\40\16\37\1\6\1\41\1\42\1\43\1\42"+
+    "\15\41\1\44\1\43\3\13\1\0\17\13\1\45\1\14"+
+    "\1\46\1\14\12\45\1\47\3\45\1\15\1\50\1\14"+
+    "\1\51\1\14\15\50\1\52\1\15\24\0\3\14\16\0"+
+    "\1\14\1\0\1\14\1\15\1\14\16\0\1\15\1\17"+
+    "\1\0\1\17\1\0\2\17\1\53\15\17\1\0\1\17"+
+    "\1\0\17\17\7\0\1\20\13\0\1\22\1\0\1\54"+
+    "\1\0\16\22\1\54\1\23\1\0\1\55\1\0\16\23"+
+    "\1\55\1\24\1\0\1\56\1\0\16\24\1\56\7\0"+
+    "\1\26\25\0\1\57\10\0\1\35\1\0\1\60\1\0"+
+    "\16\35\1\60\1\36\1\0\1\36\1\0\17\36\1\37"+
+    "\1\0\1\37\1\0\17\37\1\0\3\40\16\0\1\40"+
+    "\1\41\1\0\1\61\1\0\16\41\1\61\1\0\3\42"+
+    "\16\0\1\42\1\0\1\42\1\62\1\42\16\0\1\62"+
+    "\1\45\1\0\1\45\1\0\12\45\1\0\3\45\1\63"+
+    "\1\45\1\14\1\46\1\14\12\45\1\0\3\45\1\64"+
+    "\1\50\1\0\1\50\1\0\15\50\1\0\1\65\1\50"+
+    "\1\14\1\51\1\14\15\50\1\0\1\66\1\53\1\67"+
+    "\1\53\1\67\17\53\1\70\3\67\2\70\1\71\13\70"+
+    "\1\67\1\70\1\67\1\70\1\67\20\70\1\67\1\70"+
+    "\1\67\1\72\16\70";
+
+  private static int [] zzUnpackTrans() {
+    int [] result = new int[684];
+    int offset = 0;
+    offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackTrans(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      value--;
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+
+  /* error codes */
+  private static final int ZZ_UNKNOWN_ERROR = 0;
+  private static final int ZZ_NO_MATCH = 1;
+  private static final int ZZ_PUSHBACK_2BIG = 2;
+  private static final char[] EMPTY_BUFFER = new char[0];
+  private static final int YYEOF = -1;
+  private static java.io.Reader zzReader = null; // Fake
+
+  /* error messages for the codes above */
+  private static final String ZZ_ERROR_MSG[] = {
+    "Unkown internal scanner error",
+    "Error: could not match input",
+    "Error: pushback value was too large"
+  };
+
+  /**
+   * ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
+   */
+  private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+  private static final String ZZ_ATTRIBUTE_PACKED_0 =
+    "\6\1\2\0\2\1\1\11\5\1\1\11\3\1\1\11"+
+    "\1\1\1\11\1\1\4\11\7\1\1\11\2\1\1\11"+
+    "\2\1\1\11\1\1\3\0\1\11\4\0\1\1\1\0"+
+    "\1\1\3\0\1\11";
+
+  private static int [] zzUnpackAttribute() {
+    int [] result = new int[58];
+    int offset = 0;
+    offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+  /** the current state of the DFA */
+  private int zzState;
+
+  /** the current lexical state */
+  private int zzLexicalState = YYINITIAL;
+
+  /** this buffer contains the current text to be matched and is
+      the source of the yytext() string */
+  private CharSequence zzBuffer = "";
+
+  /** this buffer may contains the current text array to be matched when it is cheap to acquire it */
+  private char[] zzBufferArray;
+
+  /** the textposition at the last accepting state */
+  private int zzMarkedPos;
+
+  /** the textposition at the last state to be included in yytext */
+  private int zzPushbackPos;
+
+  /** the current text position in the buffer */
+  private int zzCurrentPos;
+
+  /** startRead marks the beginning of the yytext() string in the buffer */
+  private int zzStartRead;
+
+  /** endRead marks the last character in the buffer, that has been read
+      from input */
+  private int zzEndRead;
+
+  /**
+   * zzAtBOL == true <=> the scanner is currently at the beginning of a line
+   */
+  private boolean zzAtBOL = true;
+
+  /** zzAtEOF == true <=> the scanner is at the EOF */
+  private boolean zzAtEOF;
+
+  /** denotes if the user-EOF-code has already been executed */
+  private boolean zzEOFDone;
+
+  /* user code: */
+
+  public _TypoScriptLexer() {
+    this((Reader)null);
+  }
+
+
+  public _TypoScriptLexer(java.io.Reader in) {
+    this.zzReader = in;
+  }
+
+  /**
+   * Creates a new scanner.
+   * There is also java.io.Reader version of this constructor.
+   *
+   * @param   in  the java.io.Inputstream to read input from.
+   */
+  public _TypoScriptLexer(java.io.InputStream in) {
+    this(new java.io.InputStreamReader(in));
+  }
+
+  /** 
+   * Unpacks the compressed character translation table.
+   *
+   * @param packed   the packed character translation table
+   * @return         the unpacked character translation table
+   */
+  private static char [] zzUnpackCMap(String packed) {
+    char [] map = new char[0x10000];
+    int i = 0;  /* index in packed string  */
+    int j = 0;  /* index in unpacked array */
+    while (i < 70) {
+      int  count = packed.charAt(i++);
+      char value = packed.charAt(i++);
+      do map[j++] = value; while (--count > 0);
+    }
+    return map;
+  }
+
+  public final int getTokenStart(){
+    return zzStartRead;
+  }
+
+  public final int getTokenEnd(){
+    return getTokenStart() + yylength();
+  }
+
+  public void reset(CharSequence buffer, int start, int end,int initialState){
+    zzBuffer = buffer;
+    zzBufferArray = com.intellij.util.text.CharArrayUtil.fromSequenceWithoutCopying(buffer);
+    zzCurrentPos = zzMarkedPos = zzStartRead = start;
+    zzPushbackPos = 0;
+    zzAtEOF  = false;
+    zzAtBOL = true;
+    zzEndRead = end;
+    yybegin(initialState);
+  }
+
+  /**
+   * Refills the input buffer.
+   *
+   * @return      <code>false</code>, iff there was new input.
+   *
+   * @exception   java.io.IOException  if any I/O-Error occurs
+   */
+  private boolean zzRefill() throws java.io.IOException {
+    return true;
+  }
+
+
+  /**
+   * Returns the current lexical state.
+   */
+  public final int yystate() {
+    return zzLexicalState;
+  }
+
+
+  /**
+   * Enters a new lexical state
+   *
+   * @param newState the new lexical state
+   */
+  public final void yybegin(int newState) {
+    zzLexicalState = newState;
+  }
+
+
+  /**
+   * Returns the text matched by the current regular expression.
+   */
+  public final CharSequence yytext() {
+    return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
+  }
+
+
+  /**
+   * Returns the character at position <tt>pos</tt> from the
+   * matched text.
+   *
+   * It is equivalent to yytext().charAt(pos), but faster
+   *
+   * @param pos the position of the character to fetch.
+   *            A value from 0 to yylength()-1.
+   *
+   * @return the character at position pos
+   */
+  public final char yycharat(int pos) {
+    return zzBufferArray != null ? zzBufferArray[zzStartRead+pos]:zzBuffer.charAt(zzStartRead+pos);
+  }
+
+
+  /**
+   * Returns the length of the matched text region.
+   */
+  public final int yylength() {
+    return zzMarkedPos-zzStartRead;
+  }
+
+
+  /**
+   * Reports an error that occured while scanning.
+   *
+   * In a wellformed scanner (no or only correct usage of
+   * yypushback(int) and a match-all fallback rule) this method
+   * will only be called with things that "Can't Possibly Happen".
+   * If this method is called, something is seriously wrong
+   * (e.g. a JFlex bug producing a faulty scanner etc.).
+   *
+   * Usual syntax/scanner level error handling should be done
+   * in error fallback rules.
+   *
+   * @param   errorCode  the code of the errormessage to display
+   */
+  private void zzScanError(int errorCode) {
+    String message;
+    try {
+      message = ZZ_ERROR_MSG[errorCode];
+    }
+    catch (ArrayIndexOutOfBoundsException e) {
+      message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+    }
+
+    throw new Error(message);
+  }
+
+
+  /**
+   * Pushes the specified amount of characters back into the input stream.
+   *
+   * They will be read again by then next call of the scanning method
+   *
+   * @param number  the number of characters to be read again.
+   *                This number must not be greater than yylength()!
+   */
+  public void yypushback(int number)  {
+    if ( number > yylength() )
+      zzScanError(ZZ_PUSHBACK_2BIG);
+
+    zzMarkedPos -= number;
+  }
+
+
+  /**
+   * Contains user EOF-code, which will be executed exactly once,
+   * when the end of file is reached
+   */
+  private void zzDoEOF() {
+    if (!zzEOFDone) {
+      zzEOFDone = true;
+    
+    }
+  }
+
+
+  /**
+   * Resumes scanning until the next regular expression is matched,
+   * the end of input is encountered or an I/O-Error occurs.
+   *
+   * @return      the next token
+   * @exception   java.io.IOException  if any I/O-Error occurs
+   */
+  public IElementType advance() throws java.io.IOException {
+    int zzInput;
+    int zzAction;
+
+    // cached fields:
+    int zzCurrentPosL;
+    int zzMarkedPosL;
+    int zzEndReadL = zzEndRead;
+    CharSequence zzBufferL = zzBuffer;
+    char[] zzBufferArrayL = zzBufferArray;
+    char [] zzCMapL = ZZ_CMAP;
+
+    int [] zzTransL = ZZ_TRANS;
+    int [] zzRowMapL = ZZ_ROWMAP;
+    int [] zzAttrL = ZZ_ATTRIBUTE;
+
+    while (true) {
+      zzMarkedPosL = zzMarkedPos;
+
+      zzAction = -1;
+
+      zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+      zzState = ZZ_LEXSTATE[zzLexicalState];
+
+
+      zzForAction: {
+        while (true) {
+
+          if (zzCurrentPosL < zzEndReadL)
+            zzInput = zzBufferL.charAt(zzCurrentPosL++);
+          else if (zzAtEOF) {
+            zzInput = YYEOF;
+            break zzForAction;
+          }
+          else {
+            // store back cached positions
+            zzCurrentPos  = zzCurrentPosL;
+            zzMarkedPos   = zzMarkedPosL;
+            boolean eof = zzRefill();
+            // get translated positions and possibly new buffer
+            zzCurrentPosL  = zzCurrentPos;
+            zzMarkedPosL   = zzMarkedPos;
+            zzBufferL      = zzBuffer;
+            zzEndReadL     = zzEndRead;
+            if (eof) {
+              zzInput = YYEOF;
+              break zzForAction;
+            }
+            else {
+              zzInput = zzBufferL.charAt(zzCurrentPosL++);
+            }
+          }
+          int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
+          if (zzNext == -1) break zzForAction;
+          zzState = zzNext;
+
+          int zzAttributes = zzAttrL[zzState];
+          if ( (zzAttributes & 1) == 1 ) {
+            zzAction = zzState;
+            zzMarkedPosL = zzCurrentPosL;
+            if ( (zzAttributes & 8) == 8 ) break zzForAction;
+          }
+
+        }
+      }
+
+      // store back cached position
+      zzMarkedPos = zzMarkedPosL;
+
+      switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+        case 24: 
+          { yybegin(MODIFICATION_OPERATOR_FUNCTION_ARGUMENT);
+                                                                                                        return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN;
+          }
+        case 29: break;
+        case 2: 
+          { return TypoScriptTokenTypes.OBJECT_PATH_ENTITY;
+          }
+        case 30: break;
+        case 28: 
+          { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.C_STYLE_COMMENT;
+          }
+        case 31: break;
+        case 23: 
+          { return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION;
+          }
+        case 32: break;
+        case 4: 
+          { return TokenType.BAD_CHARACTER;
+          }
+        case 33: break;
+        case 17: 
+          { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_BEGIN;
+          }
+        case 34: break;
+        case 7: 
+          { yybegin(EXPRESSION_SIGN); return TypoScriptTokenTypes.OBJECT_PATH_ENTITY;
+          }
+        case 35: break;
+        case 1: 
+          { return TokenType.WHITE_SPACE;
+          }
+        case 36: break;
+        case 22: 
+          { yybegin(ONE_LINE_IGNORED_ZONE);
+                                                                                                    return TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_END;
+          }
+        case 37: break;
+        case 20: 
+          { yybegin(MULTILINE_OPERATOR_VALUE);
+                                                                                                    return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE;
+          }
+        case 38: break;
+        case 19: 
+          { yybegin(YYINITIAL); return TypoScriptTokenTypes.IGNORED_TEXT;
+          }
+        case 39: break;
+        case 6: 
+          { return TypoScriptTokenTypes.ONE_LINE_COMMENT;
+          }
+        case 40: break;
+        case 25: 
+          { return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_ARGUMENT;
+          }
+        case 41: break;
+        case 21: 
+          { return TypoScriptTokenTypes.MULTILINE_VALUE;
+          }
+        case 42: break;
+        case 13: 
+          { yybegin(ASSIGNMENT_VALUE); return TypoScriptTokenTypes.ASSIGNMENT_OPERATOR;
+          }
+        case 43: break;
+        case 3: 
+          { yybegin(MULTILINE_OPERATOR_VALUE);
+                                                                                                    return TypoScriptTokenTypes.IGNORED_TEXT;
+          }
+        case 44: break;
+        case 27: 
+          { yybegin(MODIFICATION_OPERATOR_VALUE); return TypoScriptTokenTypes.MODIFICATION_OPERATOR;
+          }
+        case 45: break;
+        case 12: 
+          { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.CODE_BLOCK_OPERATOR_END;
+          }
+        case 46: break;
+        case 11: 
+          { return TypoScriptTokenTypes.IGNORED_TEXT;
+          }
+        case 47: break;
+        case 15: 
+          { yybegin(COPYING_OPERATOR_VALUE); return TypoScriptTokenTypes.COPYING_OPERATOR;
+          }
+        case 48: break;
+        case 9: 
+          { return TypoScriptTokenTypes.CONDITION;
+          }
+        case 49: break;
+        case 5: 
+          { yybegin(YYINITIAL); return TypoScriptTokenTypes.WHITE_SPACE_WITH_NEW_LINE;
+          }
+        case 50: break;
+        case 26: 
+          { yybegin(ONE_LINE_IGNORED_ZONE);
+                                                                                                        return TypoScriptTokenTypes.MODIFICATION_OPERATOR_FUNCTION_PARAM_END;
+          }
+        case 51: break;
+        case 18: 
+          { yybegin(YYINITIAL); return TypoScriptTokenTypes.ASSIGNMENT_VALUE;
+          }
+        case 52: break;
+        case 10: 
+          { return TypoScriptTokenTypes.INCLUDE_STATEMENT;
+          }
+        case 53: break;
+        case 8: 
+          { return TypoScriptTokenTypes.OBJECT_PATH_SEPARATOR;
+          }
+        case 54: break;
+        case 16: 
+          { yybegin(MULTILINE_AFTER_SIGN_ONE_LINE_IGNORED_ZONE);
+                                                      return TypoScriptTokenTypes.MULTILINE_VALUE_OPERATOR_BEGIN;
+          }
+        case 55: break;
+        case 14: 
+          { yybegin(ONE_LINE_IGNORED_ZONE); return TypoScriptTokenTypes.UNSETTING_OPERATOR;
+          }
+        case 56: break;
+        default:
+          if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+            zzAtEOF = true;
+            zzDoEOF();
+            return null;
+          }
+          else {
+            zzScanError(ZZ_NO_MATCH);
+          }
+      }
+    }
+  }
+
+
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptColorsAndFontsPage.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptColorsAndFontsPage.java
new file mode 100644 (file)
index 0000000..699b9eb
--- /dev/null
@@ -0,0 +1,104 @@
+package com.jetbrains.typoscript.lang.highlighter;
+
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.options.colors.AttributesDescriptor;
+import com.intellij.openapi.options.colors.ColorDescriptor;
+import com.intellij.openapi.options.colors.ColorSettingsPage;
+import com.intellij.psi.codeStyle.DisplayPriority;
+import com.intellij.psi.codeStyle.DisplayPrioritySortable;
+import com.jetbrains.typoscript.TypoScriptBundle;
+import com.jetbrains.typoscript.lang.TypoScriptFileType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Map;
+
+/**
+ * @author lene
+ *         Date: 12.04.12
+ */
+public class TypoScriptColorsAndFontsPage implements ColorSettingsPage, DisplayPrioritySortable {
+
+  @NonNls private static final String DEMO_TEXT = "/*\n" +
+                                                  " *   Menu description\n" +
+                                                  " */\n" +
+                                                  "<INCLUDE_TYPOSCRIPT: source=\"FILE: folder/html/typoscript.txt\">\n" +
+                                                  "temp.menu = COA\n" +
+                                                  "temp.menu { some ignored text\n" +
+                                                  "  10 = HMENU\n" +
+                                                  "  10.entryLevel = 0\n" +
+                                                  "  10.1 = TMENU\n" +
+                                                  "  10.1 {\n" +
+                                                  "    wrap = <div class=\"menuBar\" style=\"width:80%;\">|</div>\n" +
+                                                  "    NO.ATagParams = class=\"menuButton\"\n" +
+                                                  "  } \n" +
+                                                  "} \n" +
+                                                  "\n" +
+                                                  "# Default PAGE object:\n" +
+                                                  "page = PAGE\n" +
+                                                  "[GLOBAL]\n" +
+                                                  "page.typeNum = 0\n" +
+                                                  "page.10 < temp.menu \n" +
+                                                  "&text = my text";
+
+
+  private static final AttributesDescriptor[] ATTRIBUTES =
+    new AttributesDescriptor[]{
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.one.line.comment"), TypoScriptHighlightingData.ONE_LINE_COMMENT),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.multiline.comment"), TypoScriptHighlightingData.MULTILINE_COMMENT),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.ignored.text"), TypoScriptHighlightingData.IGNORED_TEXT),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.operator"), TypoScriptHighlightingData.OPERATOR_SIGN),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.string"), TypoScriptHighlightingData.STRING_VALUE),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.object.path"), TypoScriptHighlightingData.OBJECT_PATH_ENTITY),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.object.path.separator"),
+                               TypoScriptHighlightingData.OBJECT_PATH_SEPARATOR),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.assigned.value"), TypoScriptHighlightingData.ASSIGNED_VALUE),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.condition"), TypoScriptHighlightingData.CONDITION),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.include"), TypoScriptHighlightingData.INCLUDE_STATEMENT),
+      new AttributesDescriptor(TypoScriptBundle.message("color.settings.bad.character"), TypoScriptHighlightingData.BAD_CHARACTER)
+    };
+
+  @NotNull
+  public String getDisplayName() {
+    return TypoScriptBundle.message("color.settings.name");
+  }
+
+  @Nullable
+  public Icon getIcon() {
+    return TypoScriptFileType.INSTANCE.getIcon();
+  }
+
+  @NotNull
+  public AttributesDescriptor[] getAttributeDescriptors() {
+    return ATTRIBUTES;
+  }
+
+  @NotNull
+  public ColorDescriptor[] getColorDescriptors() {
+    return new ColorDescriptor[0];
+  }
+
+  @NotNull
+  public SyntaxHighlighter getHighlighter() {
+    return new TypoScriptSyntaxHighlighter();
+  }
+
+  @NonNls
+  @NotNull
+  public String getDemoText() {
+    return DEMO_TEXT;
+  }
+
+  @Nullable
+  public Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {
+    return null;
+  }
+
+  @Override
+  public DisplayPriority getPriority() {
+    return DisplayPriority.LANGUAGE_SETTINGS;
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptHighlightingData.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptHighlightingData.java
new file mode 100644 (file)
index 0000000..066ae79
--- /dev/null
@@ -0,0 +1,37 @@
+package com.jetbrains.typoscript.lang.highlighter;
+
+import com.intellij.ide.highlighter.custom.CustomHighlighterColors;
+import com.intellij.openapi.editor.HighlighterColors;
+import com.intellij.openapi.editor.SyntaxHighlighterColors;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptHighlightingData {
+  public static final TextAttributesKey ONE_LINE_COMMENT =
+    TextAttributesKey.createTextAttributesKey("TS_ONE_LINE_COMMENT", SyntaxHighlighterColors.LINE_COMMENT.getDefaultAttributes());
+  public static final TextAttributesKey MULTILINE_COMMENT =
+    TextAttributesKey.createTextAttributesKey("TS_MULTILINE_COMMENT", SyntaxHighlighterColors.JAVA_BLOCK_COMMENT.getDefaultAttributes());
+  public static final TextAttributesKey IGNORED_TEXT =
+    TextAttributesKey.createTextAttributesKey("TS_IGNORED_TEXT", SyntaxHighlighterColors.LINE_COMMENT.getDefaultAttributes());
+  public static final TextAttributesKey OPERATOR_SIGN =
+    TextAttributesKey.createTextAttributesKey("TS_OPERATOR_SIGN", SyntaxHighlighterColors.OPERATION_SIGN.getDefaultAttributes());
+  public static final TextAttributesKey STRING_VALUE =
+    TextAttributesKey.createTextAttributesKey("STRING_VALUE", SyntaxHighlighterColors.STRING.getDefaultAttributes());
+  public static final TextAttributesKey ASSIGNED_VALUE =
+    TextAttributesKey.createTextAttributesKey("ASSIGNED_VALUE", HighlighterColors.TEXT.getDefaultAttributes());
+  public static final TextAttributesKey OBJECT_PATH_ENTITY =
+    TextAttributesKey.createTextAttributesKey("TS_OBJECT_PATH_ENTITY", SyntaxHighlighterColors.KEYWORD.getDefaultAttributes());
+  public static final TextAttributesKey OBJECT_PATH_SEPARATOR =
+    TextAttributesKey.createTextAttributesKey("TS_OBJECT_PATH_SEPARATOR", SyntaxHighlighterColors.KEYWORD.getDefaultAttributes());
+  public static final TextAttributesKey CONDITION =
+    TextAttributesKey.createTextAttributesKey("TS_CONDITION", CustomHighlighterColors.CUSTOM_KEYWORD3_ATTRIBUTES.getDefaultAttributes());
+  public static final TextAttributesKey INCLUDE_STATEMENT =
+    TextAttributesKey.createTextAttributesKey("TS_INCLUDE", CustomHighlighterColors.CUSTOM_KEYWORD4_ATTRIBUTES.getDefaultAttributes());
+
+
+  public static final TextAttributesKey BAD_CHARACTER =
+    TextAttributesKey.createTextAttributesKey("TS_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER.getDefaultAttributes());
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptSyntaxHighlighter.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/highlighter/TypoScriptSyntaxHighlighter.java
new file mode 100644 (file)
index 0000000..5165c25
--- /dev/null
@@ -0,0 +1,62 @@
+package com.jetbrains.typoscript.lang.highlighter;
+
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.util.containers.hash.HashMap;
+import com.jetbrains.typoscript.lang.TypoScriptLexer;
+import com.jetbrains.typoscript.lang.TypoScriptTokenTypes;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptSyntaxHighlighter extends SyntaxHighlighterBase {
+  private static final Map<IElementType, TextAttributesKey> ourMap;
+
+  static {
+    ourMap = new HashMap<IElementType, TextAttributesKey>();
+    ourMap.put(TypoScriptTokenTypes.ONE_LINE_COMMENT, TypoScriptHighlightingData.ONE_LINE_COMMENT);
+    ourMap.put(TypoScriptTokenTypes.IGNORED_TEXT, TypoScriptHighlightingData.IGNORED_TEXT);
+    ourMap.put(TypoScriptTokenTypes.C_STYLE_COMMENT, TypoScriptHighlightingData.MULTILINE_COMMENT);
+
+    fillMap(ourMap, TypoScriptTokenTypes.OPERATORS, TypoScriptHighlightingData.OPERATOR_SIGN);
+
+    ourMap.put(TypoScriptTokenTypes.MULTILINE_VALUE, TypoScriptHighlightingData.ASSIGNED_VALUE);
+    ourMap.put(TypoScriptTokenTypes.ASSIGNMENT_VALUE, TypoScriptHighlightingData.ASSIGNED_VALUE);
+
+    ourMap.put(TypoScriptTokenTypes.OBJECT_PATH_ENTITY, TypoScriptHighlightingData.OBJECT_PATH_ENTITY);
+    ourMap.put(TypoScriptTokenTypes.OBJECT_PATH_SEPARATOR, TypoScriptHighlightingData.OBJECT_PATH_SEPARATOR);
+
+    ourMap.put(TypoScriptTokenTypes.CONDITION, TypoScriptHighlightingData.CONDITION);
+    ourMap.put(TypoScriptTokenTypes.INCLUDE_STATEMENT, TypoScriptHighlightingData.INCLUDE_STATEMENT);
+
+    ourMap.put(TypoScriptTokenTypes.BAD_CHARACTER, TypoScriptHighlightingData.BAD_CHARACTER);
+
+    /*
+ IElementType MODIFICATION_OPERATOR_FUNCTION = new TypoScriptTokenType("MODIFICATION_FUNCTION");
+ IElementType MODIFICATION_OPERATOR_FUNCTION_PARAM_BEGIN = new TypoScriptTokenType("MODIFICATION_OPEN");
+ IElementType MODIFICATION_OPERATOR_FUNCTION_PARAM_END = new TypoScriptTokenType("MODIFICATION_CLOSE");
+ IElementType MODIFICATION_OPERATOR_FUNCTION_ARGUMENT = new TypoScriptTokenType("MODIFICATION_VALUE");
+
+ IElementType INCLUDE_STATEMENT = new TypoScriptTokenType("INCLUDE");
+ IElementType CONDITION = new TypoScriptTokenType("CONDITION");
+    */
+  }
+
+  @NotNull
+  @Override
+  public Lexer getHighlightingLexer() {
+    return new TypoScriptLexer();
+  }
+
+  @NotNull
+  @Override
+  public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
+    return pack(ourMap.get(tokenType));
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptCompositeElement.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptCompositeElement.java
new file mode 100644 (file)
index 0000000..2081aff
--- /dev/null
@@ -0,0 +1,12 @@
+package com.jetbrains.typoscript.lang.psi;
+
+import com.intellij.psi.NavigatablePsiElement;
+import com.intellij.psi.tree.IElementType;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public interface TypoScriptCompositeElement extends NavigatablePsiElement {
+  IElementType getTokenType();
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptCompositeElementImpl.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptCompositeElementImpl.java
new file mode 100644 (file)
index 0000000..9d5badb
--- /dev/null
@@ -0,0 +1,22 @@
+package com.jetbrains.typoscript.lang.psi;
+
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptCompositeElementImpl extends ASTWrapperPsiElement implements TypoScriptCompositeElement {
+
+  public TypoScriptCompositeElementImpl(@NotNull final ASTNode node) {
+    super(node);
+  }
+
+  @Override
+  public IElementType getTokenType() {
+    return getNode().getElementType();
+  }
+}
diff --git a/plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptFile.java b/plugins/typoScript/src/com/jetbrains/typoscript/lang/psi/TypoScriptFile.java
new file mode 100644 (file)
index 0000000..fd7bbec
--- /dev/null
@@ -0,0 +1,30 @@
+package com.jetbrains.typoscript.lang.psi;
+
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.psi.FileViewProvider;
+import com.jetbrains.typoscript.lang.TypoScriptFileType;
+import com.jetbrains.typoscript.lang.TypoScriptLanguage;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author lene
+ *         Date: 11.04.12
+ */
+public class TypoScriptFile  extends PsiFileBase {
+
+  public TypoScriptFile(@NotNull FileViewProvider viewProvider) {
+    super(viewProvider, TypoScriptLanguage.INSTANCE);
+  }
+
+  @NotNull
+  @Override
+  public FileType getFileType() {
+    return TypoScriptFileType.INSTANCE;
+  }
+
+  @Override
+  public String toString() {
+    return "TypoScript File";
+  }
+}
diff --git a/plugins/typoScript/testData/typoscript/lexer/assignments.test.expected b/plugins/typoScript/testData/typoscript/lexer/assignments.test.expected
new file mode 100644 (file)
index 0000000..e85f622
--- /dev/null
@@ -0,0 +1,61 @@
+object path entity ('myObject')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('[value 1]')
+WHITE_SPACE_WITH_NEW_LINE ('
+  ')
+object path entity ('myObject')
+. ('.')
+object path entity ('myProperty')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('<value 2>')
+WHITE_SPACE_WITH_NEW_LINE ('
+   ')
+object path entity ('myObject')
+. ('.')
+object path entity ('myProperty')
+. ('.')
+object path entity ('firstProperty')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('[value 3]')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('myObject')
+. ('.')
+object path entity ('myProperty')
+. ('.')
+object path entity ('secondProperty')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('[value 4]')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+object path entity ('myObject')
+. ('.')
+object path entity ('myProperty')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('{value 2 with [GLOBAL] anf other () provocations}')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('myObject')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('HTML')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('myObject')
+. ('.')
+object path entity ('value')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE ('   ')
+assignment value ('<strong> HTML - code </strong>')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/assignments.test.ts b/plugins/typoScript/testData/typoscript/lexer/assignments.test.ts
new file mode 100644 (file)
index 0000000..67fb4eb
--- /dev/null
@@ -0,0 +1,8 @@
+myObject = [value 1]
+  myObject.myProperty = <value 2>
+   myObject.myProperty.firstProperty= [value 3]
+myObject.myProperty.secondProperty = [value 4]
+
+myObject.myProperty = {value 2 with [GLOBAL] anf other () provocations}
+myObject = HTML
+myObject.value =   <strong> HTML - code </strong>
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/codeBlock.test.expected b/plugins/typoScript/testData/typoscript/lexer/codeBlock.test.expected
new file mode 100644 (file)
index 0000000..e044b22
--- /dev/null
@@ -0,0 +1,101 @@
+object path entity ('myObject')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('field')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('title')
+WHITE_SPACE_WITH_NEW_LINE ('
+   ')
+object path entity ('ifEmpty')
+WHITE_SPACE (' ')
+{ ('{')
+IGNORED_TEXT ('  IGNORED_TEXT')
+WHITE_SPACE_WITH_NEW_LINE ('
+       ')
+object path entity ('data')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('leveltitle:0  } bracket is ignored')
+WHITE_SPACE_WITH_NEW_LINE ('
+     ')
+CONDITION ('[i = 5]')
+WHITE_SPACE_WITH_NEW_LINE ('
+    ')
+} ('}')
+IGNORED_TEXT ('    some IGNORED_TEXT')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+} ('}')
+IGNORED_TEXT (' this brace is also ignored by parser')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+object path entity ('second')
+. ('.')
+object path entity ('object')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+IGNORED_TEXT ('{ ignored opening bracket')
+WHITE_SPACE_WITH_NEW_LINE ('
+ ')
+. ('.')
+object path entity ('10')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('left')
+WHITE_SPACE_WITH_NEW_LINE ('
+ ')
+object path entity ('prop')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+object path entity ('test')
+WHITE_SPACE_WITH_NEW_LINE ('
+ ')
+object path entity ('text')
+( ('(')
+WHITE_SPACE_WITH_NEW_LINE ('
+  ')
+multiline value ('} ignored bracket')
+WHITE_SPACE ('
+ ')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+object path entity ('third')
+. ('.')
+object path entity ('object')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+  ')
+object path entity ('do')
+. ('.')
+object path entity ('not')
+. ('.')
+object path entity ('ignore')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+    ')
+object path entity ('i')
+= ('=')
+assignment value ('5')
+WHITE_SPACE_WITH_NEW_LINE ('
+  ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+} ('}')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/codeBlock.test.ts b/plugins/typoScript/testData/typoscript/lexer/codeBlock.test.ts
new file mode 100644 (file)
index 0000000..96abfb1
--- /dev/null
@@ -0,0 +1,23 @@
+myObject {
+field = title
+   ifEmpty {  IGNORED_TEXT
+       data = leveltitle:0  } bracket is ignored
+     [i = 5]
+    }    some IGNORED_TEXT
+}
+} this brace is also ignored by parser
+
+second.object{
+{ ignored opening bracket
+ .10 = left
+ prop < test
+ text(
+  } ignored bracket
+ )
+}
+
+third.object{
+  do.not.ignore{
+    i=5
+  }
+}
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/comments.test.expected b/plugins/typoScript/testData/typoscript/lexer/comments.test.expected
new file mode 100644 (file)
index 0000000..38a27d6
--- /dev/null
@@ -0,0 +1,26 @@
+C_STYLE_COMMENT ('/*
+a comment */
+*/')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+C_STYLE_COMMENT ('/**
+also comment
+ */')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+ ')
+C_STYLE_COMMENT ('/* */
+comment   */
+  */')
+IGNORED_TEXT (' ignored text')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+object path entity ('assign')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('ment')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/comments.test.ts b/plugins/typoScript/testData/typoscript/lexer/comments.test.ts
new file mode 100644 (file)
index 0000000..529ef03
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+a comment */
+*/
+
+/**
+also comment
+ */
+
+ /* */
+comment   */
+  */ ignored text
+
+assign = ment
diff --git a/plugins/typoScript/testData/typoscript/lexer/copyingOperator.test.expected b/plugins/typoScript/testData/typoscript/lexer/copyingOperator.test.expected
new file mode 100644 (file)
index 0000000..db6e60b
--- /dev/null
@@ -0,0 +1,25 @@
+object path entity ('myOtherObject')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+object path entity ('myObject')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('20')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE ('  ')
+object path entity ('pageObj')
+. ('.')
+object path entity ('10')
+WHITE_SPACE (' ')
+object path entity ('strange')
+WHITE_SPACE (' ')
+object path entity ('text')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('30')
+WHITE_SPACE (' ')
+< ('<')
+. ('.')
+object path entity ('10')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/copyingOperator.test.ts b/plugins/typoScript/testData/typoscript/lexer/copyingOperator.test.ts
new file mode 100644 (file)
index 0000000..f19dbd5
--- /dev/null
@@ -0,0 +1,3 @@
+myOtherObject < myObject
+20 <  pageObj.10 strange text
+30 <.10
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/exampleFromTypo.test.expected b/plugins/typoScript/testData/typoscript/lexer/exampleFromTypo.test.expected
new file mode 100644 (file)
index 0000000..9d9e785
--- /dev/null
@@ -0,0 +1,1358 @@
+object path entity ('mod')
+. ('.')
+object path entity ('wizards')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+       ')
+object path entity ('newContentElement')
+. ('.')
+object path entity ('wizardItems')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+               ')
+object path entity ('forms')
+. ('.')
+object path entity ('elements')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('mailform')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('tt_content_defValues')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('bodytext')
+WHITE_SPACE (' ')
+( ('(')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+multiline value ('enctype = multipart/form-data')
+WHITE_SPACE ('
+')
+multiline value ('method = post')
+WHITE_SPACE ('
+')
+multiline value ('prefix = tx_form')
+WHITE_SPACE ('
+                                       ')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+       ')
+object path entity ('form')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+               ')
+object path entity ('defaults')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('showTabs')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('elements, options, form')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('tabs')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('elements')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('basic, predefined, content')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('basic')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showButtons')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('checkbox, fieldset, fileupload, hidden, password, radio, reset, select, submit, textarea, textline')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('predefined')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showButtons')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('email, radiogroup, checkboxgroup, name')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('content')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showButtons')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('header, textblock')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('options')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('legend, label, attributes, options, validation, filters, various')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('accept, acceptcharset, accesskey, action, alt, checked, class, cols, dir, disabled, enctype, id, label, lang, maxlength, method, multiple, name, readonly, rows, selected, size, src, style, tabindex, title, type, value')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('label')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('alphabetic, alphanumeric, between, date, digit, email, equals, fileallowedtypes, filemaximumsize, fileminimumsize, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('rules')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('alphabetic')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, allowWhiteSpace')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('alphanumeric')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, allowWhiteSpace')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('between')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, minimum, maximum, inclusive')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('date')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, format')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('digit')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('email')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('equals')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, field')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('fileallowedtypes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, types')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('filemaximumsize')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, maximum')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('fileminimumsize')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, minimum')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('float')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('greaterthan')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, minimum')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('inarray')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, array, strict')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('integer')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('ip')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('length')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, minimum, maximum')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('lessthan')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, maximum')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('regexp')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage, expression')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('required')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('uri')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('message, error, breakOnError, showMessage')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('filtering')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showFilters')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, removexss, stripnewlines, titlecase, trim, uppercase')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('filters')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('alphabetic')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('allowWhiteSpace')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('alphanumeric')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('allowWhiteSpace')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('currency')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('decimalPoint, thousandSeparator')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('digit')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('integer')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('lowercase')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('regexp')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('expression')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('removexss')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('stripnewlines')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('titlecase')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('trim')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('characterList')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('uppercase')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('form')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('prefix, attributes, postProcessor')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('accept, acceptcharset, action, class, dir, enctype, id, lang, method, name, style, title')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('postProcessor')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('showPostProcessors')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('mail')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+object path entity ('postProcessors')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+object path entity ('mail')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                                       ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('recipientEmail, senderEmail')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+               ')
+object path entity ('elements')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('button')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('attributes')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('value')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('checkbox')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label, attributes')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name, value')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('fieldset')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('legend')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('fileupload')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label, attributes, validation')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('required, fileallowedtypes, filemaximumsize, fileminimumsize')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('hidden')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('attributes')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name, value')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('password')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label, attributes, validation')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('required, equals')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('radio')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+. ('.')
+object path entity ('checkbox')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('reset')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+. ('.')
+object path entity ('button')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('select')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label, attributes, options, validation')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name, multiple')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('required')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('submit')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+. ('.')
+object path entity ('button')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('textarea')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label, attributes, validation, filters')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name, cols, rows')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('filtering')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showFilters')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('alphabetic, alphanumeric, lowercase, regexp, stripnewlines, titlecase, trim, uppercase')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('alphabetic, alphanumeric, length, regexp, required')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('textline')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('label, attributes, validation, filters')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('attributes')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showProperties')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('name')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('alphabetic, alphanumeric, between, date, digit, email, equals, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('filtering')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showFilters')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, titlecase, trim, uppercase')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('checkboxgroup')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('legend, options, various, validation')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('accordions')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+object path entity ('validation')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                               ')
+object path entity ('showRules')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('required')
+WHITE_SPACE_WITH_NEW_LINE ('
+                                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('email')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+. ('.')
+object path entity ('textline')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('header')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('various')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('textblock')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('various')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('name')
+WHITE_SPACE (' ')
+{ ('{')
+WHITE_SPACE_WITH_NEW_LINE ('
+                               ')
+object path entity ('showAccordions')
+WHITE_SPACE (' ')
+= ('=')
+WHITE_SPACE (' ')
+assignment value ('legend, various')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+                       ')
+object path entity ('radiogroup')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+. ('.')
+object path entity ('checkboxgroup')
+WHITE_SPACE_WITH_NEW_LINE ('
+               ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+       ')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+} ('}')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/exampleFromTypo.test.ts b/plugins/typoScript/testData/typoscript/lexer/exampleFromTypo.test.ts
new file mode 100644 (file)
index 0000000..131eab1
--- /dev/null
@@ -0,0 +1,281 @@
+mod.wizards {
+       newContentElement.wizardItems {
+               forms.elements {
+                       mailform {
+                               tt_content_defValues {
+                                       bodytext (
+enctype = multipart/form-data
+method = post
+prefix = tx_form
+                                       )
+                               }
+                       }
+               }
+       }
+       form {
+               defaults {
+                       showTabs = elements, options, form
+                       tabs {
+                               elements {
+                                       showAccordions = basic, predefined, content
+                                       accordions {
+                                               basic {
+                                                       showButtons = checkbox, fieldset, fileupload, hidden, password, radio, reset, select, submit, textarea, textline
+                                               }
+                                               predefined {
+                                                       showButtons = email, radiogroup, checkboxgroup, name
+                                               }
+                                               content {
+                                                       showButtons = header, textblock
+                                               }
+                                       }
+                               }
+                               options {
+                                       showAccordions = legend, label, attributes, options, validation, filters, various
+                                       accordions {
+                                               attributes {
+                                                       showProperties = accept, acceptcharset, accesskey, action, alt, checked, class, cols, dir, disabled, enctype, id, label, lang, maxlength, method, multiple, name, readonly, rows, selected, size, src, style, tabindex, title, type, value
+                                               }
+                                               label {
+                                                       showProperties = label
+                                               }
+                                               validation {
+                                                       showRules = alphabetic, alphanumeric, between, date, digit, email, equals, fileallowedtypes, filemaximumsize, fileminimumsize, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri
+                                                       rules {
+                                                               alphabetic {
+                                                                       showProperties = message, error, breakOnError, showMessage, allowWhiteSpace
+                                                               }
+                                                               alphanumeric {
+                                                                       showProperties = message, error, breakOnError, showMessage, allowWhiteSpace
+                                                               }
+                                                               between {
+                                                                       showProperties = message, error, breakOnError, showMessage, minimum, maximum, inclusive
+                                                               }
+                                                               date {
+                                                                       showProperties = message, error, breakOnError, showMessage, format
+                                                               }
+                                                               digit {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                               email {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                               equals {
+                                                                       showProperties = message, error, breakOnError, showMessage, field
+                                                               }
+                                                               fileallowedtypes {
+                                                                       showProperties = message, error, breakOnError, showMessage, types
+                                                               }
+                                                               filemaximumsize {
+                                                                       showProperties = message, error, breakOnError, showMessage, maximum
+                                                               }
+                                                               fileminimumsize {
+                                                                       showProperties = message, error, breakOnError, showMessage, minimum
+                                                               }
+                                                               float {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                               greaterthan {
+                                                                       showProperties = message, error, breakOnError, showMessage, minimum
+                                                               }
+                                                               inarray {
+                                                                       showProperties = message, error, breakOnError, showMessage, array, strict
+                                                               }
+                                                               integer {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                               ip {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                               length {
+                                                                       showProperties = message, error, breakOnError, showMessage, minimum, maximum
+                                                               }
+                                                               lessthan {
+                                                                       showProperties = message, error, breakOnError, showMessage, maximum
+                                                               }
+                                                               regexp {
+                                                                       showProperties = message, error, breakOnError, showMessage, expression
+                                                               }
+                                                               required {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                               uri {
+                                                                       showProperties = message, error, breakOnError, showMessage
+                                                               }
+                                                       }
+                                               }
+                                               filtering {
+                                                       showFilters = alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, removexss, stripnewlines, titlecase, trim, uppercase
+                                                       filters {
+                                                               alphabetic {
+                                                                       showProperties = allowWhiteSpace
+                                                               }
+                                                               alphanumeric {
+                                                                       showProperties = allowWhiteSpace
+                                                               }
+                                                               currency {
+                                                                       showProperties = decimalPoint, thousandSeparator
+                                                               }
+                                                               digit {
+                                                                       showProperties =
+                                                               }
+                                                               integer {
+                                                                       showProperties =
+                                                               }
+                                                               lowercase {
+                                                                       showProperties =
+                                                               }
+                                                               regexp {
+                                                                       showProperties = expression
+                                                               }
+                                                               removexss {
+                                                                       showProperties =
+                                                               }
+                                                               stripnewlines {
+                                                                       showProperties =
+                                                               }
+                                                               titlecase {
+                                                                       showProperties =
+                                                               }
+                                                               trim {
+                                                                       showProperties = characterList
+                                                               }
+                                                               uppercase {
+                                                                       showProperties =
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               form {
+                                       showAccordions = prefix, attributes, postProcessor
+                                       accordions {
+                                               attributes {
+                                                       showProperties = accept, acceptcharset, action, class, dir, enctype, id, lang, method, name, style, title
+                                               }
+                                               postProcessor {
+                                                       showPostProcessors = mail
+                                                       postProcessors {
+                                                               mail {
+                                                                       showProperties = recipientEmail, senderEmail
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               elements {
+                       button {
+                               showAccordions = attributes
+                               accordions {
+                                       attributes {
+                                               showProperties = value
+                                       }
+                               }
+                       }
+                       checkbox {
+                               showAccordions = label, attributes
+                               accordions {
+                                       attributes {
+                                               showProperties = name, value
+                                       }
+                               }
+                       }
+                       fieldset {
+                               showAccordions = legend
+                       }
+                       fileupload {
+                               showAccordions = label, attributes, validation
+                               accordions {
+                                       attributes {
+                                               showProperties = name
+                                       }
+                                       validation {
+                                               showRules = required, fileallowedtypes, filemaximumsize, fileminimumsize
+                                       }
+                               }
+                       }
+                       hidden {
+                               showAccordions = attributes
+                               accordions {
+                                       attributes {
+                                               showProperties = name, value
+                                       }
+                               }
+                       }
+                       password {
+                               showAccordions = label, attributes, validation
+                               accordions {
+                                       attributes {
+                                               showProperties = name
+                                       }
+                                       validation {
+                                               showRules = required, equals
+                                       }
+                               }
+                       }
+                       radio < .checkbox
+                       reset < .button
+                       select {
+                               showAccordions = label, attributes, options, validation
+                               accordions {
+                                       attributes {
+                                               showProperties = name, multiple
+                                       }
+                                       validation {
+                                               showRules = required
+                                       }
+                               }
+                       }
+                       submit < .button
+                       textarea {
+                               showAccordions = label, attributes, validation, filters
+                               accordions {
+                                       attributes {
+                                               showProperties = name, cols, rows
+                                       }
+                                       filtering {
+                                               showFilters = alphabetic, alphanumeric, lowercase, regexp, stripnewlines, titlecase, trim, uppercase
+                                       }
+                                       validation {
+                                               showRules = alphabetic, alphanumeric, length, regexp, required
+                                       }
+                               }
+                       }
+                       textline {
+                               showAccordions = label, attributes, validation, filters
+                               accordions {
+                                       attributes {
+                                               showProperties = name
+                                       }
+                                       validation {
+                                               showRules = alphabetic, alphanumeric, between, date, digit, email, equals, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri
+                                       }
+                                       filtering {
+                                               showFilters = alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, titlecase, trim, uppercase
+                                       }
+                               }
+                       }
+                       checkboxgroup {
+                               showAccordions = legend, options, various, validation
+                               accordions {
+                                       validation {
+                                               showRules = required
+                                       }
+                               }
+                       }
+                       email < .textline
+                       header {
+                               showAccordions = various
+                       }
+                       textblock {
+                               showAccordions = various
+                       }
+                       name {
+                               showAccordions = legend, various
+                       }
+                       radiogroup < .checkboxgroup
+               }
+       }
+}
diff --git a/plugins/typoScript/testData/typoscript/lexer/include.test.expected b/plugins/typoScript/testData/typoscript/lexer/include.test.expected
new file mode 100644 (file)
index 0000000..e2ae7bc
--- /dev/null
@@ -0,0 +1,21 @@
+INCLUDE ('<INCLUDE_TYPOSCRIPT : source="FILE: fileadmin/html/mainmenu_typoscript.txt">')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+INCLUDE ('<INCLUDE_TYPOSCRIPT : source="EXT:myext/directory/file.txt">')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+INCLUDE ('<INCLUDE_TYPOSCRIPT : source="FILE: fileadmin/html/mainmenu_typoscript.txt"> t = 8')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+INCLUDE ('<')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+INCLUDE ('< INCLsome strange text>')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+INCLUDE ('< f = 34')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+INCLUDE ('< fff.dsfs')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/include.test.ts b/plugins/typoScript/testData/typoscript/lexer/include.test.ts
new file mode 100644 (file)
index 0000000..bc32dad
--- /dev/null
@@ -0,0 +1,7 @@
+<INCLUDE_TYPOSCRIPT : source="FILE: fileadmin/html/mainmenu_typoscript.txt">
+<INCLUDE_TYPOSCRIPT : source="EXT:myext/directory/file.txt">
+<INCLUDE_TYPOSCRIPT : source="FILE: fileadmin/html/mainmenu_typoscript.txt"> t = 8
+<
+< INCLsome strange text>
+< f = 34
+< fff.dsfs
diff --git a/plugins/typoScript/testData/typoscript/lexer/multilineValue.test.expected b/plugins/typoScript/testData/typoscript/lexer/multilineValue.test.expected
new file mode 100644 (file)
index 0000000..3e4d372
--- /dev/null
@@ -0,0 +1,56 @@
+object path entity ('myObject')
+( ('(')
+WHITE_SPACE_WITH_NEW_LINE ('
+  ')
+multiline value ('some value')
+WHITE_SPACE ('
+')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+object path entity ('myObject')
+. ('.')
+object path entity ('nextProperty')
+WHITE_SPACE (' ')
+( ('(')
+IGNORED_TEXT ('IGNORED_TEXT')
+WHITE_SPACE ('
+  ')
+multiline value ('some other value ))')
+WHITE_SPACE ('
+  ')
+multiline value ('and one more string with provocations{')
+WHITE_SPACE ('
+    ')
+multiline value ('[GLOBAL]')
+WHITE_SPACE ('
+  ')
+multiline value ('}')
+WHITE_SPACE ('
+')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+object path entity ('myObject3')
+WHITE_SPACE (' ')
+( ('(')
+WHITE_SPACE_WITH_NEW_LINE ('
+ ')
+multiline value ('prop{')
+WHITE_SPACE ('
+  ')
+multiline value ('p1 = 2')
+WHITE_SPACE ('
+  ')
+multiline value ('p4 = 5')
+WHITE_SPACE ('
+ ')
+multiline value ('}')
+WHITE_SPACE ('
+')
+) (')')
+IGNORED_TEXT ('also IGNORED_TEXT')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/multilineValue.test.ts b/plugins/typoScript/testData/typoscript/lexer/multilineValue.test.ts
new file mode 100644 (file)
index 0000000..01f5ba5
--- /dev/null
@@ -0,0 +1,17 @@
+myObject(
+  some value
+)
+
+myObject.nextProperty (IGNORED_TEXT
+  some other value ))
+  and one more string with provocations{
+    [GLOBAL]
+  }
+)
+
+myObject3 (
+ prop{
+  p1 = 2
+  p4 = 5
+ }
+)also IGNORED_TEXT
diff --git a/plugins/typoScript/testData/typoscript/lexer/objectPaths.test.expected b/plugins/typoScript/testData/typoscript/lexer/objectPaths.test.expected
new file mode 100644 (file)
index 0000000..677076d
--- /dev/null
@@ -0,0 +1,49 @@
+object path entity ('myObject')
+. ('.')
+object path entity ('prop1')
+. ('.')
+object path entity ('prop2')
+. ('.')
+object path entity ('prop3')
+. ('.')
+object path entity ('prop4')
+. ('.')
+object path entity ('prop5')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+object path entity ('otherObject')
+. ('.')
+object path entity ('prop')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+. ('.')
+object path entity ('10')
+WHITE_SPACE (' ')
+> ('>')
+IGNORED_TEXT (' not.a.path')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('9path')
+. ('.')
+BAD_CHARACTER ('%')
+object path entity ('BAD_SYMBOL')
+BAD_CHARACTER ('%')
+. ('.')
+object path entity ('prop')
+WHITE_SPACE (' ')
+< ('<')
+WHITE_SPACE (' ')
+object path entity ('not')
+WHITE_SPACE (' ')
+object path entity ('a')
+WHITE_SPACE (' ')
+object path entity ('path')
+. ('.')
+object path entity ('because')
+. ('.')
+object path entity ('of')
+. ('.')
+object path entity ('spaces')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/objectPaths.test.ts b/plugins/typoScript/testData/typoscript/lexer/objectPaths.test.ts
new file mode 100644 (file)
index 0000000..1cfd303
--- /dev/null
@@ -0,0 +1,3 @@
+myObject.prop1.prop2.prop3.prop4.prop5 < otherObject.prop
+.10 > not.a.path
+9path.%BAD_SYMBOL%.prop < not a path.because.of.spaces
diff --git a/plugins/typoScript/testData/typoscript/lexer/sharpComment.test.expected b/plugins/typoScript/testData/typoscript/lexer/sharpComment.test.expected
new file mode 100644 (file)
index 0000000..de03073
--- /dev/null
@@ -0,0 +1 @@
+ONE_LINE_COMMENT ('#CommentText')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/sharpComment.test.ts b/plugins/typoScript/testData/typoscript/lexer/sharpComment.test.ts
new file mode 100644 (file)
index 0000000..ddcea3f
--- /dev/null
@@ -0,0 +1 @@
+#CommentText
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/simpleAssignment.test.expected b/plugins/typoScript/testData/typoscript/lexer/simpleAssignment.test.expected
new file mode 100644 (file)
index 0000000..28fa7f8
--- /dev/null
@@ -0,0 +1,3 @@
+object path entity ('myObject')
+= ('=')
+assignment value ('[value 1]')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/simpleAssignment.test.ts b/plugins/typoScript/testData/typoscript/lexer/simpleAssignment.test.ts
new file mode 100644 (file)
index 0000000..e7989e3
--- /dev/null
@@ -0,0 +1 @@
+myObject=[value 1]
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/singleLineComments.test.expected b/plugins/typoScript/testData/typoscript/lexer/singleLineComments.test.expected
new file mode 100644 (file)
index 0000000..4027cef
--- /dev/null
@@ -0,0 +1,28 @@
+ONE_LINE_COMMENT ('#CommentText')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+ONE_LINE_COMMENT ('/ another comment')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+ONE_LINE_COMMENT ('/third comment for test')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+ONE_LINE_COMMENT ('#fourth comment')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+ONE_LINE_COMMENT ('# the fifth comment')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+ONE_LINE_COMMENT ('#sixth comment')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+ONE_LINE_COMMENT ('/seventh')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+ONE_LINE_COMMENT ('/and one more comment')
+WHITE_SPACE_WITH_NEW_LINE ('
+
+')
+ONE_LINE_COMMENT ('// must be single comment')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/singleLineComments.test.ts b/plugins/typoScript/testData/typoscript/lexer/singleLineComments.test.ts
new file mode 100644 (file)
index 0000000..a331496
--- /dev/null
@@ -0,0 +1,12 @@
+#CommentText
+/ another comment
+
+/third comment for test
+#fourth comment
+# the fifth comment
+
+#sixth comment
+/seventh
+/and one more comment
+
+// must be single comment
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/slashComment.test.expected b/plugins/typoScript/testData/typoscript/lexer/slashComment.test.expected
new file mode 100644 (file)
index 0000000..ddb2f1c
--- /dev/null
@@ -0,0 +1 @@
+ONE_LINE_COMMENT ('/CommentText')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/slashComment.test.ts b/plugins/typoScript/testData/typoscript/lexer/slashComment.test.ts
new file mode 100644 (file)
index 0000000..8e5cad1
--- /dev/null
@@ -0,0 +1 @@
+/CommentText
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/unsettingOperator.test.expected b/plugins/typoScript/testData/typoscript/lexer/unsettingOperator.test.expected
new file mode 100644 (file)
index 0000000..dfebef6
--- /dev/null
@@ -0,0 +1,18 @@
+WHITE_SPACE (' ')
+object path entity ('myObject')
+WHITE_SPACE (' ')
+> ('>')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('object')
+WHITE_SPACE (' ')
+> ('>')
+IGNORED_TEXT (' some irrelevant text')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('nextObjext')
+. ('.')
+object path entity ('secondProperty')
+WHITE_SPACE (' ')
+> ('>')
+IGNORED_TEXT (' [GLOBAL] {test=3} (value)')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/unsettingOperator.test.ts b/plugins/typoScript/testData/typoscript/lexer/unsettingOperator.test.ts
new file mode 100644 (file)
index 0000000..3a0622d
--- /dev/null
@@ -0,0 +1,3 @@
+ myObject >
+object > some irrelevant text
+nextObjext.secondProperty > [GLOBAL] {test=3} (value)
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/valueModificationOperator.test.expected b/plugins/typoScript/testData/typoscript/lexer/valueModificationOperator.test.expected
new file mode 100644 (file)
index 0000000..e8130c9
--- /dev/null
@@ -0,0 +1,53 @@
+object path entity ('value1')
+:= (':=')
+modification function ('addToList')
+( ('(')
+modification value ('4,5')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('value2')
+:= (':=')
+modification function ('addToList')
+( ('(')
+modification value ('4,5')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('value3')
+:= (':=')
+( ('(')
+WHITE_SPACE (' ')
+modification value ('4 and some text')
+WHITE_SPACE ('   ')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('value4')
+BAD_CHARACTER (':')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('value5')
+:= (':=')
+modification function ('add To My List')
+WHITE_SPACE (' ')
+( ('(')
+WHITE_SPACE (' ')
+modification value ('4,5')
+) (')')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('value6')
+:= (':=')
+modification function ('add To My List')
+( ('(')
+modification value ('4,5')
+) (')')
+IGNORED_TEXT ('  some IGNORED_TEXT')
+WHITE_SPACE_WITH_NEW_LINE ('
+')
+object path entity ('value7')
+BAD_CHARACTER (':')
+WHITE_SPACE (' ')
+object path entity ('addToList')
+( ('(')
+IGNORED_TEXT (' ,5)')
\ No newline at end of file
diff --git a/plugins/typoScript/testData/typoscript/lexer/valueModificationOperator.test.ts b/plugins/typoScript/testData/typoscript/lexer/valueModificationOperator.test.ts
new file mode 100644 (file)
index 0000000..defa660
--- /dev/null
@@ -0,0 +1,7 @@
+value1:=addToList(4,5)
+value2:=addToList(4,5
+value3:=( 4 and some text   )
+value4:
+value5:=add To My List ( 4,5)
+value6:=add To My List(4,5)  some IGNORED_TEXT
+value7: addToList( ,5)
\ No newline at end of file
diff --git a/plugins/typoScript/tests/com/jetbrains/typoscript/TypoScriptLexerTest.java b/plugins/typoScript/tests/com/jetbrains/typoscript/TypoScriptLexerTest.java
new file mode 100644 (file)
index 0000000..c5375b6
--- /dev/null
@@ -0,0 +1,124 @@
+package com.jetbrains.typoscript;
+
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.testFramework.UsefulTestCase;
+import com.jetbrains.typoscript.lang.TypoScriptLexer;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author lene
+ *         Date: 04.04.12
+ */
+public class TypoScriptLexerTest extends UsefulTestCase {
+  @NonNls
+  private static final String INPUT_DATA_FILE_EXT = "test.ts";
+  @NonNls
+  private static final String EXPECTED_RESULT_FILE_EXT = "test.expected";
+
+
+  public void testSlashComment() throws Throwable {
+    doTest();
+  }
+
+  public void testSharpComment() throws Throwable {
+    doTest();
+  }
+
+  public void testSingleLineComments() throws Throwable {
+    doTest();
+  }
+
+  public void testSimpleAssignment() throws Throwable {
+    doTest();
+  }
+
+  public void testAssignments() throws Throwable {
+    doTest();
+  }
+
+  public void testCopyingOperator() throws Throwable {
+    doTest();
+  }
+
+  public void testUnsettingOperator() throws Throwable {
+    doTest();
+  }
+
+  public void testMultilineValue() throws Throwable {
+    doTest();
+  }
+
+  public void testValueModificationOperator() throws Throwable {
+    doTest();
+  }
+
+  public void testInclude() throws Throwable {
+    doTest();
+  }
+
+  public void testObjectPaths() throws Throwable {
+    doTest();
+  }
+
+  public void testCodeBlock() throws Throwable {
+    doTest();
+  }
+
+  public void testExampleFromTypo() throws Throwable {
+    doTest();
+  }
+
+  public void testComments() throws Throwable {
+    doTest();
+  }
+
+  private void doTest() throws IOException {
+    Lexer lexer = new TypoScriptLexer();
+    String testText = getInputData(getDataSubPath(), getTestName(true));
+    String expected = getExpectedDataFilePath(getDataSubPath(), getTestName(true));
+    doFileLexerTest(lexer, testText, expected);
+  }
+
+  private static void doFileLexerTest(Lexer lexer, String testText, String expected) {
+    lexer.start(testText);
+    String result = "";
+    for (IElementType tokenType = lexer.getTokenType(); tokenType != null; tokenType = lexer.getTokenType()) {
+      String tokenText = lexer.getBufferSequence().subSequence(lexer.getTokenStart(), lexer.getTokenEnd()).toString();
+      String tokenTypeName = tokenType.toString();
+      String line = tokenTypeName + " ('" + tokenText + "')\n";
+      result += line;
+      lexer.advance();
+    }
+    UsefulTestCase.assertSameLinesWithFile(expected, result);
+  }
+
+  private static String getExpectedDataFilePath(final String dataSubPath, final String testName) {
+    return getInputDataFilePath(dataSubPath, testName, EXPECTED_RESULT_FILE_EXT);
+  }
+
+  private static String getInputData(final String dataSubPath, final String testName) {
+    final String filePath = getInputDataFilePath(dataSubPath, testName, INPUT_DATA_FILE_EXT);
+    try {
+      return FileUtil.loadFile(new File(filePath));
+    }
+    catch (IOException e) {
+      System.out.println(filePath);
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static String getInputDataFilePath(final String dataSubPath, final String testName, final String fileExtension) {
+    return PathManager.getHomePath() + "/" + dataSubPath + "/" + testName + "." + fileExtension;
+  }
+
+  @NonNls
+  private static String getDataSubPath() {
+    return "/plugins/typoScript/testData/typoscript/lexer";
+  }
+}
\ No newline at end of file
diff --git a/plugins/typoScript/typoScript.iml b/plugins/typoScript/typoScript.iml
new file mode 100644 (file)
index 0000000..a25c711
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="core-api" />
+    <orderEntry type="module" module-name="testFramework" />
+    <orderEntry type="module" module-name="php" />
+  </component>
+</module>
+