package com.reason.lang.ocaml; import org.jetbrains.annotations.NotNull; import com.intellij.lang.ASTNode; import com.intellij.lang.PsiBuilder; import com.intellij.lang.PsiBuilderFactory; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.ILazyParseableElementType; import com.reason.lang.CommonParser; import com.reason.lang.ParserScope; import com.reason.lang.ParserScopeEnum; import com.reason.lang.ParserState; import static com.intellij.codeInsight.completion.CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED; import static com.intellij.lang.parser.GeneratedParserUtilBase.*; import static com.reason.lang.ParserScope.*; import static com.reason.lang.ParserScopeEnum.*; public class OclParser extends CommonParser<OclTypes> { public OclParser() { super(OclTypes.INSTANCE); } public static ASTNode parseOcamlNode(@NotNull ILazyParseableElementType root, @NotNull ASTNode chameleon) { PsiElement parentElement = chameleon.getTreeParent().getPsi(); Project project = parentElement.getProject(); PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, new OclLexer(), root.getLanguage(), chameleon.getText()); //builder.setDebugMode(true); OclParser parser = new OclParser(); return parser.parse(root, builder).getFirstChildNode(); } @Override protected void parseFile(@NotNull PsiBuilder builder, @NotNull ParserState state) { IElementType tokenType = null; state.previousElementType1 = null; int c = current_position_(builder); while (true) { state.previousElementType2 = state.previousElementType1; state.previousElementType1 = tokenType; tokenType = builder.getTokenType(); if (tokenType == null) { break; } if (tokenType == m_types.SEMI) { parseSemi(builder, state); } else if (tokenType == m_types.IN) { parseIn(state); } else if (tokenType == m_types.END) { // end (like a }) parseEnd(state); } else if (tokenType == m_types.UNDERSCORE) { parseUnderscore(state); } else if (tokenType == m_types.RIGHT_ARROW) { parseRightArrow(builder, state); } else if (tokenType == m_types.PIPE) { parsePipe(builder, state); } else if (tokenType == m_types.EQ) { parseEq(builder, state); } else if (tokenType == m_types.OF) { parseOf(builder, state); } else if (tokenType == m_types.STAR) { parseStar(builder, state); } else if (tokenType == m_types.COLON) { parseColon(builder, state); } else if (tokenType == m_types.QUESTION_MARK) { parseQuestionMark(builder, state); } else if (tokenType == m_types.LIDENT) { parseLIdent(builder, state); } else if (tokenType == m_types.UIDENT) { parseUIdent(builder, state); } else if (tokenType == m_types.SIG) { parseSig(builder, state); } else if (tokenType == m_types.STRUCT) { parseStruct(builder, state); } else if (tokenType == m_types.BEGIN) { parseBegin(builder, state); } else if (tokenType == m_types.OBJECT) { parseObject(builder, state); } else if (tokenType == m_types.IF) { parseIf(builder, state); } else if (tokenType == m_types.THEN) { parseThen(builder, state); } else if (tokenType == m_types.ELSE) { parseElse(builder, state); } else if (tokenType == m_types.MATCH) { parseMatch(builder, state); } else if (tokenType == m_types.TRY) { parseTry(builder, state); } else if (tokenType == m_types.WITH) { parseWith(builder, state); } else if (tokenType == m_types.ARROBASE) { parseArrobase(builder, state); } else if (tokenType == m_types.AND) { parseAnd(builder, state); } else if (tokenType == m_types.FUNCTION) { // function is a shortcut for a pattern match parseFunction(builder, state); } else if (tokenType == m_types.FUN) { parseFun(builder, state); } else if (tokenType == m_types.ASSERT) { parseAssert(builder, state); } else if (tokenType == m_types.RAISE) { parseRaise(builder, state); } else if (tokenType == m_types.COMMA) { parseComma(builder, state); } // while ... do ... done else if (tokenType == m_types.WHILE) { parseWhile(builder, state); } // do ... done else if (tokenType == m_types.DO) { parseDo(builder, state); } else if (tokenType == m_types.DONE) { parseDone(state); } // ( ... ) else if (tokenType == m_types.LPAREN) { parseLParen(builder, state); } else if (tokenType == m_types.RPAREN) { parseRParen(state); } // { ... } else if (tokenType == m_types.LBRACE) { parseLBrace(builder, state); } else if (tokenType == m_types.RBRACE) { parseRBrace(state); } // [ ... ] // [> ... ] else if (tokenType == m_types.LBRACKET) { parseLBracket(builder, state); } else if (tokenType == m_types.BRACKET_GT) { parseBracketGt(builder, state); } else if (tokenType == m_types.RBRACKET) { parseRBracket(state); } // [| ... |] else if (tokenType == m_types.LARRAY) { parseLArray(builder, state); } else if (tokenType == m_types.RARRAY) { parseRArray(state); } // < ... > else if (tokenType == m_types.LT) { parseLt(builder, state); } else if (tokenType == m_types.GT) { parseGt(builder, state); } // Starts expression else if (tokenType == m_types.OPEN) { parseOpen(builder, state); } else if (tokenType == m_types.INCLUDE) { parseInclude(builder, state); } else if (tokenType == m_types.EXTERNAL) { parseExternal(builder, state); } else if (tokenType == m_types.TYPE) { parseType(builder, state); } else if (tokenType == m_types.MODULE) { parseModule(builder, state); } else if (tokenType == m_types.CLASS) { parseClass(builder, state); } else if (tokenType == m_types.LET) { parseLet(builder, state); } else if (tokenType == m_types.VAL) { parseVal(builder, state); } else if (tokenType == m_types.METHOD) { parseMethod(builder, state); } else if (tokenType == m_types.EXCEPTION) { parseException(builder, state); } else if (tokenType == m_types.DIRECTIVE_IF) { parseDirectiveIf(builder, state); } else if (tokenType == m_types.DIRECTIVE_ELSE) { parseDirectiveElse(/*builder,*/ state); } else if (tokenType == m_types.DIRECTIVE_ELIF) { parseDirectiveElif(/*builder,*/ state); } else if (tokenType == m_types.DIRECTIVE_END || tokenType == m_types.DIRECTIVE_ENDIF) { parseDirectiveEnd(/*builder,*/ state); } if (state.dontMove) { state.dontMove = false; } else { builder.advanceLexer(); } if (!empty_element_parsed_guard_(builder, "oclFile", c)) { break; } c = builder.rawTokenIndex(); } } private void parseRaise(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(external)) { builder.remapCurrentToken(m_types.LIDENT); state.wrapWith(m_types.C_LOWER_SYMBOL).updateCurrentResolution(externalNamed).complete(); } } private void parseComma(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentContext(let) && state.isCurrentResolution(genericExpression)) { // It must be a deconstruction // let ( a |>,<| b ) = .. state.updateCurrentResolution(deconstruction).updateCurrentCompositeElementType(m_types.C_DECONSTRUCTION); } } private void parseLArray(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(markScope(builder, array, m_types.C_SCOPED_EXPR, m_types.LARRAY)); } private void parseRArray(@NotNull ParserState state) { state.popEndUntilContext(array); if (state.isCurrentResolution(array)) { state.popEnd(); } } private void parseLt(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (!state.isCurrentResolution(whileConditionLoop)) { // |> < <| .. > .. state.add(markScope(builder, object, m_types.C_OBJECT, m_types.LT)). advance(). add(mark(builder, object, objectField, m_types.C_OBJECT_FIELD)); } } private void parseGt(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentContext(object)) { // < ... |> > <| .. if (state.isCurrentResolution(objectFieldNamed)) { state.popEnd(); } state.advance(); if ("Js".equals(builder.getTokenText())) { // it might be a Js object (same with Js.t at the end) state.advance(); if (builder.getTokenType() == m_types.DOT) { state.advance(); if ("t".equals(builder.getTokenText())) { state.updateCurrentCompositeElementType(m_types.C_JS_OBJECT).advance().complete(); } } } else { state.complete(); } state.popEnd(); } } private void parseWhile(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(markScope(builder, whileLoop, m_types.C_WHILE, m_types.WHILE)). advance(). add(mark(builder, whileLoop, whileConditionLoop, m_types.C_WHILE_CONDITION)); } private void parseDo(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(whileConditionLoop)) { state.complete(). popEnd(). add(markScope(builder, doLoop, whileDoLoop, m_types.C_SCOPED_EXPR, m_types.DO)); } else { state.add(markScope(builder, doLoop, m_types.C_SCOPED_EXPR, m_types.DO)); } } private void parseDone(@NotNull ParserState state) { state.popEndUntilContext(doLoop); if (state.isCurrentResolution(whileDoLoop)) { state.advance(). popEndUntilContext(whileLoop). complete(). popEnd(); } if (state.isCurrentResolution(doLoop)) { state.advance().complete().popEnd(); } } private void parseRightArrow(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(signatureItem)) { state.popEnd(). advance(). add(mark(builder, signature, signatureItem, m_types.C_SIG_ITEM).complete()); } else if (state.isCurrentResolution(patternMatch)) { state.advance(). add(mark(builder, state.currentContext(), patternMatchBody, m_types.C_PATTERN_MATCH_BODY).complete()); } else if (state.isCurrentResolution(matchWith)) { state.advance().add(mark(builder, matchException, m_types.C_SCOPED_EXPR)); } else if (state.isCurrentContext(typeConstrName)) { state.popEndUntilContext(type).popEnd(); } else if (state.isCurrentResolution(maybeFunctionParameters)) { state.complete().popEnd().advance(). add(mark(builder, functionBody, m_types.C_FUN_BODY).complete()); } } private void parseUnderscore(@NotNull ParserState state) { if (state.isCurrentResolution(let)) { state.updateCurrentResolution(letNamed); state.complete(); } } private void parseAssert(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(mark(builder, assert_, m_types.C_ASSERT_STMT).complete()); } private void parseAnd(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(functorConstraint) || state.isCurrentResolution(includeConstraint)) { state.complete().popEnd(); return; } // pop scopes until a known context is found endUntilStartExpression(state); if (state.isCurrentResolution(function)) { state.popEnd(); } if (state.isCurrentContext(type)) { state.popEnd().popEnd(). advance(). add(mark(builder, type, m_types.C_EXP_TYPE)). add(mark(builder, typeConstrName, m_types.C_TYPE_CONSTR_NAME)); } else if (state.isCurrentContext(let) || state.isCurrentContext(letBinding)) { if (state.isCurrentContext(letBinding)) { state.popEnd(); } state.popEnd(). advance(). add(mark(builder, let, m_types.C_LET_STMT)); } else if (state.isCurrentContext(moduleDeclaration)) { state.popEnd(). advance(); parseModule(builder, state); } } private void endUntilStartExpression(@NotNull ParserState state) { ParserScopeEnum context = state.currentContext(); while (context != let && context != type && context != moduleDeclaration && context != assert_) { if (context == file || state.isInScopeExpression()) { break; } state.popEnd(); context = state.currentContext(); } } private void parsePipe(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(typeNamedEq)) { state.add(mark(builder, state.currentContext(), typeNamedEqVariant, m_types.C_VARIANT_DECL).complete()); } else if (state.isCurrentResolution(typeNamedEqVariant)) { state.popEnd(); state.add(mark(builder, state.currentContext(), typeNamedEqVariant, m_types.C_VARIANT_DECL).complete()); } else if (state.isCurrentContext(variantConstructor)) { state.popEndWhileContext(variantConstructor); state.popEnd().add(mark(builder, typeNamedEqVariant, m_types.C_VARIANT_DECL).complete()); } else { // By default, a pattern match if (state.isCurrentResolution(patternMatchBody)) { state.popEnd(); } if (state.isCurrentResolution(patternMatch)) { state.popEnd(); } state.add(mark(builder, state.currentContext(), patternMatch, m_types.C_PATTERN_MATCH_EXPR).complete()); } } private void parseMatch(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(mark(builder, match, m_types.C_MATCH_EXPR).complete()).advance().add(mark(builder, matchBinaryCondition, m_types.C_BIN_CONDITION).complete()); } private void parseTry(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(mark(builder, try_, m_types.C_TRY_EXPR).complete()). advance(). add(mark(builder, try_, tryBody, m_types.C_TRY_BODY).complete()); } private void parseWith(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentContext(moduleInstanciation)) { // this is incorrect, it might comes from: // module Constraint : Set.S with type elt = univ_constraint state.popEnd(); } if (state.isCurrentResolution(functorNamedColonResult)) { // A functor with constraints // module Make (M : Input) : S |>with<| type t = M.t state.complete(). popEnd(). add(markScope(builder, functorConstraints, m_types.C_CONSTRAINTS, m_types.WITH)); } else if (state.isCurrentResolution(moduleNamedSignature)) { // A module with a signature and constraints // module G : sig ... end |>with<| type ... state.add(markScope(builder, state.currentContext(), moduleNamedSignatureConstraints, m_types.C_CONSTRAINTS, m_types.WITH)); } else if (state.isCurrentContext(include)) { // An include with constraints // include M |>with<| type ... if (state.isCurrentResolution(maybeFunctorCall)) { state.popEnd(); } state.add(markScope(builder, includeConstraints, m_types.C_CONSTRAINTS, m_types.WITH).complete()); } else if (!state.isCurrentResolution(moduleNamedColon)) { // A try handler // try .. |>with<| .. if (state.isCurrentContext(try_)) { state.endUntilResolution(try_). updateCurrentResolution(tryBodyWith). advance(). add(mark(builder, state.currentContext(), tryBodyWith, m_types.C_TRY_HANDLERS).complete()). add(mark(builder, state.currentContext(), tryBodyWithHandler, m_types.C_TRY_HANDLER).complete()); } else if (state.isCurrentContext(matchBinaryCondition)) { state.popEndUntilContext(match); state.updateCurrentResolution(matchWith).setStart(); state.advance(); } } } private void parseIf(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(mark(builder, if_, m_types.C_IF_STMT).complete()).advance().add(mark(builder, binaryCondition, m_types.C_BIN_CONDITION).complete()); } private void parseThen(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (!state.isCurrentContext(directive)) { state.popEndUntilContext(if_); state.advance().add(mark(builder, ifThenStatement, m_types.C_SCOPED_EXPR).complete()); } } private void parseElse(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.popEndUntilContext(if_); state.advance().add(mark(builder, ifElseStatement, m_types.C_SCOPED_EXPR).complete()); } private void parseStruct(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(moduleNamedEq) || state.isCurrentResolution(moduleNamedSignatureEq)) { state.popEndUntilContext(moduleDeclaration); state.add(markScope(builder, moduleBinding, m_types.C_SCOPED_EXPR, m_types.STRUCT)); } else if (state.isCurrentResolution(functorNamedEq)) { state.popEndUntilContext(functorDeclaration); state.add(markScope(builder, functorBinding, m_types.C_FUNCTOR_BINDING, m_types.STRUCT)); } else { state.add(markScope(builder, struct, m_types.C_STRUCT_EXPR, m_types.STRUCT).complete()); } } private void parseSig(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentContext(moduleDeclaration)) { if (state.isCurrentResolution(moduleNamedEq) || state.isCurrentResolution(moduleNamedColon)) { state.popEndUntilContext(moduleDeclaration); state.updateCurrentResolution(moduleNamedSignature); state.add(markScope(builder, state.currentContext(), moduleSignature, m_types.C_SIG_EXPR, m_types.SIG)); } } else if (state.isCurrentResolution(functorParamColon)) { state.updateCurrentResolution(functorParamColonSignature). add(markScope(builder, state.currentContext(), functorParamColonSignature, m_types.C_SIG_EXPR, m_types.SIG).complete()); } } private void parseSemi(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(recordField)) { // SEMI ends the field, and starts a new one state.complete(); state.popEndUntilContext(recordField); state.popEnd(); state.advance(); state.add(mark(builder, recordField, m_types.C_RECORD_FIELD)); } else { boolean isImplicitScope = state.isCurrentContext(functionBody); // A SEMI operator ends the previous expression if (!isImplicitScope && !state.isInScopeExpression()) { state.popEnd(); if (state.isCurrentContext(object)) { state.advance().add(mark(builder, object, objectField, m_types.C_OBJECT_FIELD)); } } } } private void parseIn(@NotNull ParserState state) { endUntilStartExpression(state); state.popEnd(); } private void parseBegin(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(markScope(builder, beginScope, m_types.C_SCOPED_EXPR, m_types.BEGIN)); } private void parseObject(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(clazzNamedEq)) { state.add(markScope(builder, clazzBodyScope, m_types.C_SCOPED_EXPR, m_types.OBJECT)); } else { state.add(markScope(builder, objectScope, m_types.C_SCOPED_EXPR, m_types.OBJECT)); } } private void parseEnd(@NotNull ParserState state) { ParserScope scope = state.popEndUntilOneOfElementType(m_types.BEGIN, m_types.SIG, m_types.STRUCT, m_types.OBJECT); state.advance(); if (scope != null && scope.isScopeStart()) { scope.complete(); state.popEnd(); } } private void parseColon(@NotNull PsiBuilder builder, @NotNull ParserState state) { // : if (state.isCurrentResolution(moduleNamed)) { state.updateCurrentResolution(moduleNamedColon).complete(); } else if (state.isCurrentResolution(functorNamed)) { state.updateCurrentResolution(functorNamedColon). advance(). add(mark(builder, state.currentContext(), functorNamedColonResult, m_types.C_FUNCTOR_RESULT)); } else if (state.isCurrentResolution(externalNamed)) { state.advance(). add(mark(builder, signature, externalNamedSignature, m_types.C_SIG_EXPR).complete()). add(mark(builder, signature, signatureItem, m_types.C_SIG_ITEM).complete()); } else if (state.isCurrentResolution(valNamed)) { // val x |>:<| ... state.advance(). add(mark(builder, signature, valNamedSignature, m_types.C_SIG_EXPR).complete()). add(mark(builder, signature, signatureItem, m_types.C_SIG_ITEM).complete()); } else if (state.isCurrentResolution(functionParameter)) { state.updateCurrentResolution(functionParameterNamed). advance(). add(mark(builder, signature, functionParameterNamedSignature, m_types.C_SIG_EXPR).complete()). add(mark(builder, signature, signatureItem, m_types.C_SIG_ITEM).complete()); } else if (state.isCurrentResolution(letNamed)) { state.advance(). add(mark(builder, signature, letNamedSignature, m_types.C_SIG_EXPR).complete()). add(mark(builder, signature, signatureItem, m_types.C_SIG_ITEM).complete()); } else if (state.isCurrentResolution(functorParam)) { state.updateCurrentResolution(functorParamColon); } else if (state.isCurrentResolution(objectField)) { state.updateCurrentResolution(objectFieldNamed).complete(); } } private void parseQuestionMark(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(functionParameter) && !state.isInScopeExpression()) { // Start of a new optional parameter // .. ( xxx |>?<|yyy ) .. state.complete(). popEnd(). add(mark(builder, function, functionParameter, m_types.C_FUN_PARAM)); } } private void parseFunction(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.advance(); if (builder.getTokenType() != m_types.PIPE) { state.add(mark(builder, state.currentContext(), patternMatch, m_types.C_PATTERN_MATCH_EXPR).complete()); } } private void parseFun(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentContext(letBinding)) { state.add(markScope(builder, function, m_types.C_FUN_EXPR, m_types.FUN).complete()); state.advance(); state.add(mark(builder, maybeFunctionParameters, m_types.C_FUN_PARAMS)); } } private void parseEq(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentContext(signature)) { state.popEndWhileContext(signature); } else if (state.isCurrentResolution(typeNamedEq)) { IElementType nextElementType = builder.lookAhead(1); if (nextElementType == m_types.STRUCT) { // Functor constraints // module M (..) : S with type x = y |> =<| struct .. end state.popEndUntilStartScope(); state.complete().popEnd(); } else { // Must be multiple declaration // type x = y |> =<| ... // This is not correctly parsed, just to avoid to break next instructions } } if (state.isCurrentResolution(typeNamed)) { state.popEnd(). updateCurrentResolution(typeNamedEq). advance(). add(mark(builder, typeBinding, typeNamedEq, m_types.C_TYPE_BINDING).complete()); } else if (state.isCurrentResolution(letNamed) || state.isCurrentResolution(letNamedSignature)) { state.popEndUntilContext(let); state.updateCurrentResolution(letNamedEq); state.advance(); state.add(mark(builder, letBinding, letNamedBinding, m_types.C_LET_BINDING).complete()); } else if (state.isCurrentResolution(jsxTagProperty)) { state.updateCurrentResolution(jsxTagPropertyEq); } else if (state.isCurrentContext(moduleDeclaration)) { if (state.isCurrentResolution(moduleNamed)) { state.updateCurrentResolution(moduleNamedEq); state.complete(); } else if (state.isCurrentResolution(moduleNamedSignature)) { state.updateCurrentResolution(moduleNamedSignatureEq); state.complete(); } } else if (state.isCurrentContext(functorDeclaration)) { if (state.isCurrentResolution(functorNamedColonResult)) { state.complete().popEnd(); } if (state.isCurrentResolution(functorNamed) || state.isCurrentResolution(functorNamedColon)) { state.updateCurrentResolution(functorNamedEq). complete(); } } else if (state.isCurrentContext(functorConstraints)) { IElementType nextElementType = builder.lookAhead(1); if (nextElementType == m_types.STRUCT) { // Functor constraints // module M (..) : S with type x = y |> =<| struct .. end if (state.isCurrentResolution(functorConstraint)) { state.complete().popEnd(); } state.popEndUntilStartScope().complete(); state.popEnd(); state.updateCurrentResolution(functorNamedEq).complete(); } } else if (state.isCurrentResolution(clazzNamed)) { state.updateCurrentResolution(clazzNamedEq); } else if (state.isCurrentResolution(externalNamed) && state.previousElementType1 == m_types.LPAREN) { // external ( |>=<| ) = ... builder.remapCurrentToken(m_types.LIDENT); state.wrapWith(m_types.C_LOWER_SYMBOL); } else if (state.isCurrentResolution(externalNamedSignature)) { state.complete(); state.popEnd(); state.updateCurrentResolution(externalNamedSignatureEq); } else if (state.isCurrentResolution(maybeFunctionParameters)) { ParserScope innerScope = state.pop(); if (innerScope != null) { // This is a function definition, change the scopes innerScope.resolution(functionParameters).updateCompositeElementType(m_types.C_FUN_PARAMS).complete().end(); state.updateCurrentContext(function). updateCurrentResolution(function). updateCurrentCompositeElementType(m_types.C_FUN_EXPR). complete(); state.advance(); state.add(mark(builder, functionBody, m_types.C_FUN_BODY).complete()); } } else if (state.isCurrentResolution(functionParameter) && !state.isInScopeExpression()) { state.complete(). popEndUntilResolution(function). advance(). add(mark(builder, functionBody, m_types.C_FUN_BODY).complete()); } } private void parseOf(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(typeNamedEqVariant)) { // Variant params :: type t = | Variant «of» .. state.add(mark(builder, variantConstructor, variantConstructorParameters, m_types.C_FUN_PARAMS).complete()). advance(). add(mark(builder, variantConstructor, variantConstructorParameter, m_types.C_FUN_PARAM).complete()); } } private void parseStar(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(variantConstructorParameter)) { // Variant params :: type t = | Variant of x <*> y .. ) state.popEnd(). advance(). add(mark(builder, variantConstructor, variantConstructorParameter, m_types.C_FUN_PARAM).complete()); } } private void parseArrobase(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(annotation)) { state.complete(); state.add(mark(builder, annotationName, m_types.C_MACRO_NAME).complete()); } } private void parseLParen(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.previousElementType2 == m_types.UIDENT && state.previousElementType1 == m_types.DOT) { // Detecting a local open // M1.M2. |>(<| ... ) state.add(markScope(builder, localOpenScope, m_types.C_LOCAL_OPEN, m_types.LPAREN).complete()); } else if (state.isCurrentResolution(external)) { // Overloading an operator // external |>(<| ... ) = ... state.updateCurrentResolution(externalNamed).complete(); state.add(markScope(builder, localOpenScope, m_types.C_SCOPED_EXPR, m_types.LPAREN)); } else if (state.isCurrentResolution(let)) { // Overloading operator OR deconstructing a term // let |>(<| + ) = // let |>(<| a, b ) = state.add(markScope(builder, let, genericExpression, m_types.C_SCOPED_EXPR, m_types.LPAREN)); } else if (state.isCurrentResolution(val)) { // Overloading an operator // val |>(<| .. ) = .. state.updateCurrentResolution(valNamed).complete(); state.add(markScope(builder, valNamedSymbol, m_types.C_SCOPED_EXPR, m_types.LPAREN)); } else if (state.isCurrentResolution(clazzNamed)) { state.add(markScope(builder, state.currentContext(), clazzConstructor, m_types.C_CLASS_CONSTR, m_types.LPAREN)); } else if (state.isCurrentResolution(functionParameters)) { // Start of the first parameter // let f |>(<| .. ) = .. state.add(mark(builder, functionParameters, functionParameter, m_types.C_FUN_PARAM)). add(markScope(builder, state.currentContext(), functionParameter, m_types.C_SCOPED_EXPR, m_types.LPAREN)); } else if (state.isCurrentResolution(functionParameter) && !state.isInScopeExpression() && state.previousElementType1 != m_types.QUESTION_MARK) { // Start of a new parameter // let f xxx |>(<| ..tuple ) = .. state.complete().popEnd(). add(mark(builder, state.currentContext(), functionParameter, m_types.C_FUN_PARAM)). add(markScope(builder, state.currentContext(), functionParameter, m_types.C_SCOPED_EXPR, m_types.LPAREN)); } else if (state.isCurrentResolution(functionParameters)) { state.add(mark(builder, functionParameters, functionParameter, m_types.C_FUN_PARAM)); IElementType nextTokenType = builder.rawLookup(1); if (nextTokenType == m_types.RPAREN) { // unit parameter state.add(mark(builder, state.currentContext(), unit, m_types.C_UNIT). complete()). advance(). advance(). popEnd(); } } else if (state.isCurrentResolution(moduleNamed)) { // This is a functor // module Make |>(<| ... ) state.updateCurrentContext(functorDeclaration). updateCurrentResolution(functorNamed). updateCurrentCompositeElementType(m_types.C_FUNCTOR). add(markScope(builder, functorDeclarationParams, functorParams, m_types.C_FUNCTOR_PARAMS, m_types.LPAREN)). advance(). add(mark(builder, state.currentContext(), functorParam, m_types.C_FUNCTOR_PARAM).complete()); } else if (state.isCurrentResolution(maybeFunctorCall)) { // Yes, it is a functor call // module M = X |>(<| ... ) state.updateCurrentResolution(functorCall).complete(); state.add(markScope(builder, functorDeclarationParams, functorParams, m_types.C_FUNCTOR_PARAMS, m_types.LPAREN)). advance(). add(mark(builder, state.currentContext(), functorParam, m_types.C_FUNCTOR_PARAM).complete()); } else { state.add(markScope(builder, scope, paren, m_types.C_SCOPED_EXPR, m_types.LPAREN)); } } private void parseRParen(@NotNull ParserState state) { ParserScope scope = state.endUntilScopeToken(m_types.LPAREN); state.advance(); if (scope != null) { scope.complete(); state.popEnd(); } if (state.isCurrentResolution(let)) { // we are processing an infix operator or a desconstruction (tuple) : let (..<)> state.updateCurrentResolution(letNamed).complete(); } else if (state.isCurrentResolution(moduleNamedColon)) { // ? state.popEnd(); } } private void parseLBrace(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(functionParameters)) { state.add(mark(builder, function, functionParameter, m_types.C_FUN_PARAM).complete()); } state.add(markScope(builder, recordBinding, m_types.C_RECORD_EXPR, m_types.LBRACE)); state.advance(); state.add(mark(builder, recordField, m_types.C_RECORD_FIELD)); } private void parseRBrace(@NotNull ParserState state) { if (state.isCurrentResolution(recordField) && state.previousElementType1 != m_types.SEMI) { state.complete(); } ParserScope scope = state.endUntilScopeToken(m_types.LBRACE); state.advance(); if (scope != null) { scope.complete(); state.popEnd(); } } private void parseLBracket(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(clazz)) { state.add(markScope(builder, clazzDeclaration, bracket, m_types.C_CLASS_PARAMS, m_types.LBRACKET)); } else { IElementType nextTokenType = builder.rawLookup(1); if (nextTokenType == m_types.ARROBASE) { // This is an annotation state.popEndUntilStartScope(); state.add(markScope(builder, annotation, m_types.C_ANNOTATION_EXPR, m_types.LBRACKET)); } else { state.add(markScope(builder, bracket, m_types.C_SCOPED_EXPR, m_types.LBRACKET)); } } } private void parseBracketGt(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.add(markScope(builder, bracketGt, m_types.C_SCOPED_EXPR, m_types.LBRACKET)); } private void parseRBracket(@NotNull ParserState state) { ParserScope scope = state.endUntilScopeToken(m_types.LBRACKET); state.advance(); if (scope != null) { if (!scope.isResolution(annotation)) { scope.complete(); } state.popEnd(); } } private void parseLIdent(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(typeConstrName)) { state.updateCurrentResolution(typeNamed); state.complete(); state.setPreviousComplete(); } else if (state.isCurrentResolution(external)) { state.updateCurrentResolution(externalNamed); state.complete(); } else if (state.isCurrentResolution(let)) { transitionToLetNamed(builder, state); return; } else if (state.isCurrentResolution(val)) { state.updateCurrentResolution(valNamed); state.complete(); } else if (state.isCurrentResolution(clazz)) { state.updateCurrentResolution(clazzNamed); state.complete(); } else if (state.isCurrentResolution(functionParameters)) { state.add(mark(builder, functionParameters, functionParameter, m_types.C_FUN_PARAM)); } else if (state.isCurrentContext(objectField)) { // < |>x<| : y; .. > state.add(mark(builder, object, objectFieldNamed, m_types.C_OBJECT_FIELD)); } else if (state.isCurrentResolution(functionParameter) && !state.isInScopeExpression()) { // Start of a new parameter // .. ( xxx |>yyy<| ) .. state.complete().popEnd(). add(mark(builder, function, functionParameter, m_types.C_FUN_PARAM)); } state.wrapWith(m_types.C_LOWER_SYMBOL); } private void transitionToLetNamed(@NotNull PsiBuilder builder, @NotNull ParserState state) { state.updateCurrentResolution(letNamed).complete(). wrapWith(m_types.C_LOWER_SYMBOL); IElementType tokenType = builder.getTokenType(); if (tokenType != m_types.EQ && tokenType != m_types.COLON) { state.add(mark(builder, letBinding, letNamedBinding, m_types.C_LET_BINDING).complete()).add(mark(builder, function, m_types.C_FUN_EXPR).complete()) .add(mark(builder, function, functionParameters, m_types.C_FUN_PARAMS).complete()); } } private void parseUIdent(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (DUMMY_IDENTIFIER_TRIMMED.equals(builder.getTokenText())) { return; } if (state.isCurrentResolution(open) || state.isCurrentResolution(include)) { // It is a module name/path, or might be a functor call // open/include |>M<| ... state.complete(); state.add(mark(builder, state.currentContext(), maybeFunctorCall, m_types.C_FUNCTOR_CALL)); state.wrapWith(m_types.C_UPPER_SYMBOL); IElementType tokenType = builder.getTokenType(); if (tokenType != m_types.DOT && tokenType != m_types.LPAREN) { state.popCancel(); state.popEnd(); } return; } if (state.isCurrentResolution(exception)) { state.complete(); state.updateCurrentResolution(exceptionNamed); builder.remapCurrentToken(m_types.EXCEPTION_NAME); } else if (state.isCurrentResolution(module)) { state.updateCurrentResolution(moduleNamed); } else if (state.isCurrentResolution(moduleNamedEq)) { // It might be a functor call // module M = |>X<| ( ... ) state.add(mark(builder, state.currentContext(), maybeFunctorCall, m_types.C_FUNCTOR_CALL)); } else if (state.isCurrentResolution(typeNamedEq)) { // Might be a variant without a pipe IElementType nextTokenType = builder.lookAhead(1); if (nextTokenType == m_types.OF || nextTokenType == m_types.PIPE) { // type t = |>X<| | .. or type t = |>X<| of .. builder.remapCurrentToken(m_types.VARIANT_NAME); state.add(mark(builder, state.currentContext(), typeNamedEqVariant, m_types.C_VARIANT_DECL).complete()); state.wrapWith(m_types.C_VARIANT); return; } } else if (state.isCurrentResolution(typeNamedEqVariant)) { // Declaring a variant // type t = | |>X<| .. builder.remapCurrentToken(m_types.VARIANT_NAME); state.wrapWith(m_types.C_VARIANT); return; } else { IElementType nextTokenType = builder.lookAhead(1); if (((state.isCurrentResolution(patternMatch)) || !state.isCurrentContext(moduleDeclaration)) && nextTokenType != m_types.DOT) { // Pattern matching a variant // match c with | |>X<| .. builder.remapCurrentToken(m_types.VARIANT_NAME); state.wrapWith(m_types.C_VARIANT); return; } } state.wrapWith(m_types.C_UPPER_SYMBOL); } private void parseOpen(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(let)) { // let open X (coq/indtypes.ml) state.updateCurrentResolution(open); state.updateCurrentCompositeElementType(m_types.C_OPEN); } else { endLikeSemi(state); state.add(mark(builder, open, m_types.C_OPEN)); } } private void parseInclude(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, include, m_types.C_INCLUDE)); } private void parseExternal(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, external, m_types.C_EXTERNAL_STMT)); } private void parseType(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (!state.isCurrentResolution(module) && !state.isCurrentResolution(clazz)) { if (state.isCurrentResolution(moduleNamedColon) || state.isCurrentResolution(moduleNamedColonWith)) { state.updateCurrentResolution(moduleNamedWithType); } else if (state.isCurrentResolution(functorConstraints)) { state.add(mark(builder, functorConstraints, functorConstraint, m_types.C_CONSTRAINT)); } else if (state.isCurrentResolution(includeConstraints)) { state.add(mark(builder, includeConstraints, includeConstraint, m_types.C_CONSTRAINT)); } else { endLikeSemi(state); state.add(mark(builder, type, m_types.C_EXP_TYPE)); state.advance(); state.add(mark(builder, typeConstrName, m_types.C_TYPE_CONSTR_NAME)); } } } private void parseException(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.previousElementType1 != m_types.PIPE) { endLikeSemi(state); state.add(mark(builder, exception, m_types.C_EXCEPTION_EXPR)); } } private void parseDirectiveIf(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, directive, m_types.C_DIRECTIVE).setIsStart(true)); } private void parseDirectiveElse(/*@NotNull PsiBuilder builder,*/ @NotNull ParserState state) { endLikeSemi(state); } private void parseDirectiveElif(/*@NotNull PsiBuilder builder,*/ @NotNull ParserState state) { endLikeSemi(state); } private void parseDirectiveEnd(/*@NotNull PsiBuilder builder,*/ @NotNull ParserState state) { state.popEndUntilContext(directive); if (state.isCurrentContext(directive)) { state.complete().advance().popEnd(); } } private void parseVal(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, val, state.isCurrentContext(clazzBodyScope) ? m_types.C_CLASS_FIELD : m_types.C_VAL_EXPR)); } private void parseMethod(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, val, m_types.C_CLASS_METHOD)); } private void parseLet(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, let, m_types.C_LET_STMT)); } private void parseModule(@NotNull PsiBuilder builder, @NotNull ParserState state) { if (state.isCurrentResolution(let)) { state.updateCurrentContext(moduleDeclaration). updateCurrentResolution(module). updateCurrentCompositeElementType(m_types.C_MODULE_STMT); } else if (!state.isCurrentResolution(annotationName)) { endLikeSemi(state); state.add(mark(builder, moduleDeclaration, module, m_types.C_MODULE_STMT)); } } private void parseClass(@NotNull PsiBuilder builder, @NotNull ParserState state) { endLikeSemi(state); state.add(mark(builder, clazzDeclaration, clazz, m_types.C_CLASS_STMT)); } private void endLikeSemi(@NotNull ParserState state) { if (state.isCurrentResolution(includeConstraint)) { state.complete().popEnd().popEnd(); } if (state.previousElementType1 != m_types.EQ && state.previousElementType1 != m_types.RIGHT_ARROW && state.previousElementType1 != m_types.TRY && state.previousElementType1 != m_types.SEMI && state.previousElementType1 != m_types.THEN && state.previousElementType1 != m_types.ELSE && state.previousElementType1 != m_types.IN && state.previousElementType1 != m_types.LPAREN && state.previousElementType1 != m_types.DO && state.previousElementType1 != m_types.STRUCT && state.previousElementType1 != m_types.SIG && state.previousElementType1 != m_types.COLON) { state.popEndUntilStartScope(); ParserScope parserScope = state.getLatestScope(); while (parserScope != null && (parserScope.isContext(function) || parserScope.isContext(match))) { state.popEnd(); state.popEndUntilStartScope(); parserScope = state.getLatestScope(); } } } }