Intellij Grammar Kit - 基于索引的语言

问题描述 投票:0回答:0

我正在使用 Intellij IDEA Grammar-Kit 插件创建一种语言,并且希望块是基于缩进的,而不是基于大括号的。到目前为止,我发现这样做的唯一方法是使用

https://github.com/kandeshvari/idea-nim/blob/master/src/org/dmitrigb/ideanim/parser/中的
<<indent ...>>函数ParserUtil.java.

我已将该链接中的代码最小化为:

package org.intellij.sdk.language;

import com.intellij.lang.LighterASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiParser;
import com.intellij.lang.impl.PsiBuilderImpl;
import com.intellij.lang.parser.GeneratedParserUtilBase;
import com.intellij.openapi.util.Key;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.containers.IntIntHashMap;


// https://github.com/kandeshvari/idea-nim/blob/master/src/org/dmitrigb/ideanim/parser/ParserUtil.java


public class SPPParserUtil extends GeneratedParserUtilBase {
    private static class ParserState {
        enum PrimaryMode {
            NORMAL, TYPE_DEF, TYPE_DESC
        }

        private PsiBuilder builder;
        private int currentIndent = 0;
        private int pragmaCount = 0;
        private PrimaryMode primaryMode = PrimaryMode.NORMAL;
        private int semiStmtListCount = 0;

        private IntIntHashMap tokIndentCache = new IntIntHashMap();

        ParserState(PsiBuilder builder) {
            this.builder = builder;
        }

        private String getPrecedingWhiteSpace() {
            int wsOffset = 0;
            while (builder.rawLookup(wsOffset - 1) == TokenType.WHITE_SPACE)
                --wsOffset;
            int wsStart = builder.rawTokenTypeStart(wsOffset);
            return builder.getOriginalText().subSequence(wsStart, builder.getCurrentOffset()).toString();
        }

        int getTokenIndent() {
            int tokStart = builder.getCurrentOffset();
            if (tokIndentCache.containsKey(tokStart))
                return tokIndentCache.get(tokStart);

            int indent = -1;
            String ws = getPrecedingWhiteSpace();
            int nlPos = ws.lastIndexOf('\n');
            if (nlPos != -1)
                indent = ws.length() - nlPos - 1;
            tokIndentCache.put(tokStart, indent);
            return indent;
        }
    }

    private static Key<ParserState> parserStateKey = new Key<>("parser-state");

    private static ParserState getParserState(PsiBuilder builder) {
        return builder.getUserData(parserStateKey);
    }

    public static boolean indented(PsiBuilder builder, int level, Parser parser) {
        ParserState state = getParserState(builder);
        int tokIndent = state.getTokenIndent();
        if (tokIndent > state.currentIndent) {
            int prevIndent = state.currentIndent;
            state.currentIndent = tokIndent;
            boolean result = parser.parse(builder, level + 1);
            state.currentIndent = prevIndent;
            return result;
        }
        return false;
    }
}

另存为

SPPParserUtil.java


这是我目前最小的 BNF:

{
    parserUtilClass='org.intellij.sdk.language.SPPParserUtil'

    tokens=[
        TK_DOT = '.'
        TK_ARROW = '->'
        TK_STAR = '*'
        TK_COLON = ':'

        KW_FILE = 'file'
        KW_IMPORT = 'import'

        TK_EOL = 'regexp:[\n|\r]*'
        TK_IDENTIFIERS = 'regexp:[a-zA-Z_][a-zA-Z0-9_]*(,\s+[a-zA-Z_][a-zA-Z0-9_]*)*'
        TK_SCOPED_IDENTIFIER = 'regexp:[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*'
        TK_SPACE = 'regexp:\s+'
    ]
}



root ::= Program


Program ::=
    ProgramContents <<eof>>
ProgramContents ::=
    FileDefinition ImportBlock? TK_EOL

FileDefinition ::=
    KW_FILE TK_SPACE ScopedIdentifier TK_EOL


ImportLocation ::=
    TK_DOT* ScopedIdentifier
ImportDefinition ::=
    ImportLocation TK_SPACE TK_ARROW TK_SPACE (Identifiers | TK_STAR) TK_EOL
ImportBlock ::=
    KW_IMPORT TK_COLON <<indented ImportDefinition+>>


ScopedIdentifier ::=
    TK_SCOPED_IDENTIFIER
Identifiers ::=
    TK_IDENTIFIERS


这里是一些应该通过的示例代码:

file src.classes.class1


import:
    src.classes.class2 -> class2, e2
    src.classes.class3 -> class3, e3
    src.classes.class4 -> *

但是,每当我尝试在我的 BNF 中使用

<<indent ...>>
时,总是会出现错误:所描述的错误是
':' expected, got ':'
,在“导入”之后的冒号上。基本上
<<indent ...>>
之前的任何东西似乎都被
<<indent ...>>
消耗了。我将如何更改 BNF /
ParseUtil
的使用来解决这个问题?

intellij-idea indentation grammar-kit
© www.soinside.com 2019 - 2024. All rights reserved.