diff --git a/build.gradle.kts b/build.gradle.kts index 4e2ae5c..da7b15f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,9 +8,11 @@ plugins { } // Grammar-Kit output. Committed so diffs are reviewable, never hand-edited. +val generatedSourceDir = file("src/main/gen") + sourceSets { main { - java.srcDirs("src/main/gen") + java.srcDirs(generatedSourceDir) } } @@ -28,20 +30,25 @@ dependencies { } } +// purgeOldFiles is not enough: Grammar-Kit rewrites only the files whose rule +// changed, so a PSI interface can keep an accessor its regenerated Impl no longer has +// (`JaiDeclaration.getArgumentList()` with no override) and the build then fails +// inside generated code. Wiping first makes every generation self-consistent. +// +// This is a separate Delete task rather than a doFirst, because any lambda added to a +// task from a Kotlin build script captures the script object, which the configuration +// cache cannot serialize. +val cleanGeneratedSources by tasks.registering(Delete::class) { + delete(generatedSourceDir) +} + tasks.generateParser { + dependsOn(cleanGeneratedSources) sourceFile.set(file("src/main/grammar/Jai.bnf")) - targetRootOutputDir.set(file("src/main/gen")) + targetRootOutputDir.set(generatedSourceDir) pathToParser.set("dev/hgh/jai/parser/JaiParser.java") pathToPsiRoot.set("dev/hgh/jai/psi") purgeOldFiles.set(true) - - // purgeOldFiles is not enough: Grammar-Kit rewrites only the files whose rule - // changed, so a PSI interface can keep an accessor its regenerated Impl no longer - // has (`JaiDeclaration.getArgumentList()` with no override) and the build fails on - // generated code. Always regenerate the whole tree. - doFirst { - delete(file("src/main/gen")) - } } // Without this the compile tasks read src/main/gen with no ordering guarantee, so an diff --git a/src/main/gen/dev/hgh/jai/parser/JaiParser.java b/src/main/gen/dev/hgh/jai/parser/JaiParser.java index fe8580d..9047f4f 100644 --- a/src/main/gen/dev/hgh/jai/parser/JaiParser.java +++ b/src/main/gen/dev/hgh/jai/parser/JaiParser.java @@ -2509,7 +2509,8 @@ public class JaiParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // <> returnGroup | returnItem (',' returnItem)* + // <> returnGroup + // | returnItem (',' <> returnItem)* static boolean returnTypes_(PsiBuilder builder_, int level_) { if (!recursion_guard_(builder_, level_, "returnTypes_")) return false; boolean result_; @@ -2531,7 +2532,7 @@ public class JaiParser implements PsiParser, LightPsiParser { return result_; } - // returnItem (',' returnItem)* + // returnItem (',' <> returnItem)* private static boolean returnTypes__1(PsiBuilder builder_, int level_) { if (!recursion_guard_(builder_, level_, "returnTypes__1")) return false; boolean result_; @@ -2542,7 +2543,7 @@ public class JaiParser implements PsiParser, LightPsiParser { return result_; } - // (',' returnItem)* + // (',' <> returnItem)* private static boolean returnTypes__1_1(PsiBuilder builder_, int level_) { if (!recursion_guard_(builder_, level_, "returnTypes__1_1")) return false; while (true) { @@ -2553,12 +2554,13 @@ public class JaiParser implements PsiParser, LightPsiParser { return true; } - // ',' returnItem + // ',' <> returnItem private static boolean returnTypes__1_1_0(PsiBuilder builder_, int level_) { if (!recursion_guard_(builder_, level_, "returnTypes__1_1_0")) return false; boolean result_; Marker marker_ = enter_section_(builder_); result_ = consumeToken(builder_, COMMA); + result_ = result_ && notPolyParamAhead(builder_, level_ + 1); result_ = result_ && returnItem(builder_, level_ + 1); exit_section_(builder_, marker_, null, result_); return result_; @@ -3222,65 +3224,61 @@ public class JaiParser implements PsiParser, LightPsiParser { return result_; } - // 'cast' directiveFlag_* '(' [expr (',' expr)*] ')' [expr] + // 'cast' directiveFlag_* '(' expr ',' expr (',' expr)* ')' + // | 'cast' directiveFlag_* '(' [expr] ')' expr public static boolean castExpr(PsiBuilder builder_, int level_) { if (!recursion_guard_(builder_, level_, "castExpr")) return false; if (!nextTokenIsSmart(builder_, KW_CAST)) return false; boolean result_; Marker marker_ = enter_section_(builder_); - result_ = consumeTokenSmart(builder_, KW_CAST); - result_ = result_ && castExpr_1(builder_, level_ + 1); - result_ = result_ && consumeToken(builder_, LPAREN); - result_ = result_ && castExpr_3(builder_, level_ + 1); - result_ = result_ && consumeToken(builder_, RPAREN); - result_ = result_ && castExpr_5(builder_, level_ + 1); + result_ = castExpr_0(builder_, level_ + 1); + if (!result_) result_ = castExpr_1(builder_, level_ + 1); exit_section_(builder_, marker_, CAST_EXPR, result_); return result_; } - // directiveFlag_* - private static boolean castExpr_1(PsiBuilder builder_, int level_) { - if (!recursion_guard_(builder_, level_, "castExpr_1")) return false; - while (true) { - int pos_ = current_position_(builder_); - if (!directiveFlag_(builder_, level_ + 1)) break; - if (!empty_element_parsed_guard_(builder_, "castExpr_1", pos_)) break; - } - return true; - } - - // [expr (',' expr)*] - private static boolean castExpr_3(PsiBuilder builder_, int level_) { - if (!recursion_guard_(builder_, level_, "castExpr_3")) return false; - castExpr_3_0(builder_, level_ + 1); - return true; - } - - // expr (',' expr)* - private static boolean castExpr_3_0(PsiBuilder builder_, int level_) { - if (!recursion_guard_(builder_, level_, "castExpr_3_0")) return false; + // 'cast' directiveFlag_* '(' expr ',' expr (',' expr)* ')' + private static boolean castExpr_0(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_0")) return false; boolean result_; Marker marker_ = enter_section_(builder_); - result_ = expr(builder_, level_ + 1, -1); - result_ = result_ && castExpr_3_0_1(builder_, level_ + 1); + result_ = consumeTokenSmart(builder_, KW_CAST); + result_ = result_ && castExpr_0_1(builder_, level_ + 1); + result_ = result_ && consumeToken(builder_, LPAREN); + result_ = result_ && expr(builder_, level_ + 1, -1); + result_ = result_ && consumeToken(builder_, COMMA); + result_ = result_ && expr(builder_, level_ + 1, -1); + result_ = result_ && castExpr_0_6(builder_, level_ + 1); + result_ = result_ && consumeToken(builder_, RPAREN); exit_section_(builder_, marker_, null, result_); return result_; } - // (',' expr)* - private static boolean castExpr_3_0_1(PsiBuilder builder_, int level_) { - if (!recursion_guard_(builder_, level_, "castExpr_3_0_1")) return false; + // directiveFlag_* + private static boolean castExpr_0_1(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_0_1")) return false; while (true) { int pos_ = current_position_(builder_); - if (!castExpr_3_0_1_0(builder_, level_ + 1)) break; - if (!empty_element_parsed_guard_(builder_, "castExpr_3_0_1", pos_)) break; + if (!directiveFlag_(builder_, level_ + 1)) break; + if (!empty_element_parsed_guard_(builder_, "castExpr_0_1", pos_)) break; + } + return true; + } + + // (',' expr)* + private static boolean castExpr_0_6(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_0_6")) return false; + while (true) { + int pos_ = current_position_(builder_); + if (!castExpr_0_6_0(builder_, level_ + 1)) break; + if (!empty_element_parsed_guard_(builder_, "castExpr_0_6", pos_)) break; } return true; } // ',' expr - private static boolean castExpr_3_0_1_0(PsiBuilder builder_, int level_) { - if (!recursion_guard_(builder_, level_, "castExpr_3_0_1_0")) return false; + private static boolean castExpr_0_6_0(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_0_6_0")) return false; boolean result_; Marker marker_ = enter_section_(builder_); result_ = consumeTokenSmart(builder_, COMMA); @@ -3289,9 +3287,35 @@ public class JaiParser implements PsiParser, LightPsiParser { return result_; } + // 'cast' directiveFlag_* '(' [expr] ')' expr + private static boolean castExpr_1(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_1")) return false; + boolean result_; + Marker marker_ = enter_section_(builder_); + result_ = consumeTokenSmart(builder_, KW_CAST); + result_ = result_ && castExpr_1_1(builder_, level_ + 1); + result_ = result_ && consumeToken(builder_, LPAREN); + result_ = result_ && castExpr_1_3(builder_, level_ + 1); + result_ = result_ && consumeToken(builder_, RPAREN); + result_ = result_ && expr(builder_, level_ + 1, -1); + exit_section_(builder_, marker_, null, result_); + return result_; + } + + // directiveFlag_* + private static boolean castExpr_1_1(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_1_1")) return false; + while (true) { + int pos_ = current_position_(builder_); + if (!directiveFlag_(builder_, level_ + 1)) break; + if (!empty_element_parsed_guard_(builder_, "castExpr_1_1", pos_)) break; + } + return true; + } + // [expr] - private static boolean castExpr_5(PsiBuilder builder_, int level_) { - if (!recursion_guard_(builder_, level_, "castExpr_5")) return false; + private static boolean castExpr_1_3(PsiBuilder builder_, int level_) { + if (!recursion_guard_(builder_, level_, "castExpr_1_3")) return false; expr(builder_, level_ + 1, -1); return true; } diff --git a/src/main/grammar/Jai.bnf b/src/main/grammar/Jai.bnf index 9167719..f672247 100644 --- a/src/main/grammar/Jai.bnf +++ b/src/main/grammar/Jai.bnf @@ -305,7 +305,8 @@ arrayTypeExpr ::= '[' ['..' | expr] ']' expr // (modules/Shared_Memory_Channel/module.jai:113). derefCastExpr ::= '(' '.*' ')' expr -castExpr ::= 'cast' directiveFlag_* '(' [expr (',' expr)*] ')' [expr] +castExpr ::= 'cast' directiveFlag_* '(' expr ',' expr (',' expr)* ')' + | 'cast' directiveFlag_* '(' [expr] ')' expr autoCastExpr ::= 'xx' [',' IDENT] expr inlineExpr ::= ('inline' | 'no_inline') expr ifxExpr ::= ifxKeyword_ expr ['then'] [ifxBranch_] ['else' ifxBranch_] @@ -385,7 +386,8 @@ private paramTypeTail_ ::= ':' [<>] ['=' initializer] | ':=' initializer | '::' initializer -private returnTypes_ ::= <> returnGroup | returnItem (',' returnItem)* +private returnTypes_ ::= <> returnGroup + | returnItem (',' <> returnItem)* returnGroup ::= '(' [returnItem (',' returnItem)*] ')' returnItem ::= <> IDENT (':' [<>] ['=' returnDefault_] | ':=' returnDefault_) | <> diff --git a/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt b/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt index fdd9ac5..3f2c84e 100644 --- a/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt +++ b/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt @@ -91,6 +91,17 @@ object JaiParserUtil : GeneratedParserUtilBase() { "this", ) + /** + * Directives that modify the declaration that follows them, rather than standing + * alone as a statement. + * + * The distinction matters for the tree shape: `#scope_file` changes visibility for + * everything *after* it, so attaching it to the next declaration would misreport + * that declaration's scope. Taken from the corpus, where only these four appear + * directly in front of a `name :` / `name ::` / `name :=`. + */ + private val DIRECTIVES_ON_DECLARATIONS = setOf("as", "overlay", "add_context", "no_reset") + // ---------------------------------------------------------------- directives /** @@ -343,7 +354,13 @@ object JaiParserUtil : GeneratedParserUtilBase() { var inPrefix = false loop@ while (true) { when (b.lookAhead(i)) { - T.DIRECTIVE, T.KW_USING -> { + T.DIRECTIVE -> { + if (!isDeclarationDirective(b, i)) break@loop + i++ + inPrefix = true + } + + T.KW_USING -> { i++ inPrefix = true } @@ -378,6 +395,20 @@ object JaiParserUtil : GeneratedParserUtilBase() { } } + /** + * Whether the DIRECTIVE at lookahead [index] modifies the declaration that + * follows. Only the first token can be read as text through the builder, which is + * enough: a declaration-modifying directive is always the first thing we look at. + */ + private fun isDeclarationDirective( + b: PsiBuilder, + index: Int, + ): Boolean { + if (index != 0) return true + val text = b.tokenText ?: return false + return text.removePrefix("#") in DIRECTIVES_ON_DECLARATIONS + } + /** * Index just past the closer matching the bracket at [start], or -1 if unbalanced. * Covers `(…)`, `[…]`, `.[…]` and `.{…}`, which all appear in declaration @@ -479,6 +510,22 @@ object JaiParserUtil : GeneratedParserUtilBase() { } } + /** + * True when the next token cannot start a polymorph capture. + * + * An unparenthesised return list is comma-separated, and so is the parameter list + * that may enclose it. A `$T` after the comma can only be a parameter, so the + * return list has to stop there. + */ + @JvmStatic + fun notPolyParamAhead( + b: PsiBuilder, + level: Int, + ): Boolean { + val t = b.tokenType + return t !== T.DOLLAR && t !== T.DOUBLE_DOLLAR + } + /** `IDENT ':'` — a loop label. */ @JvmStatic fun isLabelAhead( diff --git a/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt b/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt index 04ddfae..b6d9a84 100644 --- a/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt +++ b/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt @@ -1,7 +1,6 @@ package dev.hgh.jai.parser import com.intellij.psi.PsiErrorElement -import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiRecursiveElementWalkingVisitor import com.intellij.testFramework.fixtures.BasePlatformTestCase @@ -9,70 +8,77 @@ import dev.hgh.jai.JaiLanguage import java.io.File /** - * Scratch harness for grammar work. Not a gate — the gate is [JaiCorpusParserTest]. - * Edit [snippets] and [corpusFiles] freely while iterating on `Jai.bnf`. + * Scratch harness for grammar work. **Not a gate** — the gate is [JaiCorpusParserTest]. + * + * Both lists are empty on purpose, so this is silent until someone is working on + * `Jai.bnf`. To iterate: paste failing snippets into [snippets] or corpus-relative + * paths into [corpusFiles], run `./jaitest`, and read the printed first error. Add + * `-Djai.debug.tree=1` to dump the PSI tree as well. + * + * The loop this supports is: read the sample errors printed by [JaiCorpusParserTest], + * reduce one to a snippet here, fix the grammar, then re-check the corpus percentage. */ class DebugParseTest : BasePlatformTestCase() { - private val snippets = - listOf( - "T :: struct {\n p := .06;\n b: BG;\n b.shape.kind = .ABS;\n b.color = V4.{.00, .10, 1};\n}\n", - "T :: struct {\n orientation: enum u8 {\n H :: 0;\n V :: 1;\n }\n\n d: BT;\n}\n", - "T :: struct {\n using,except .[\"x\"] orientation: Quaternion;\n}\n", - "operator *[] :: (b: *Bucket, index: int) -> *int { return null; }\n", - "code :: #code a := Vector3.{1, 1, 1};\n", - ) + /** Jai source snippets to parse. */ + private val snippets = emptyList() - /** Corpus files to dump the first error of. */ - private val corpusFiles = - listOf( - "modules/GetRect/widgets/color_picker.jai", - "modules/GetRect/widgets/slidable_region.jai", - "how_to/094_array_operators.jai", - "how_to/044_using_advanced/main.jai", - "how_to/630_compiler_get_nodes.jai", - "modules/Bucket_Array.jai", - "modules/Android/Toolchain/adb.jai", - "modules/Hash_Table.jai", - ) + /** Paths under `~/.local/jai` to parse. */ + private val corpusFiles = emptyList() + + fun testSnippets() { + val factory = PsiFileFactory.getInstance(project) + for (text in snippets) { + val file = factory.createFileFromText("scratch.jai", JaiLanguage, text) + val error = errorsIn(file).firstOrNull() + val label = text.replace("\n", "\\n") + if (error == null) { + println("ok $label") + } else { + println("FAIL $label") + println(" ${error.errorDescription} | at '${around(text, error.textOffset)}'") + } + if (System.getProperty("jai.debug.tree") != null) { + println( + com.intellij.psi.impl.DebugUtil + .psiToString(file, true, false), + ) + } + } + } fun testCorpusFiles() { val root = File(System.getProperty("user.home"), ".local/jai") if (!root.exists()) return for (relative in corpusFiles) { val file = File(root, relative) - if (file.exists()) dumpFile(file) else println("missing: $relative") - } - } - - fun testSnippets() { - val factory = PsiFileFactory.getInstance(project) - var failures = 0 - for (text in snippets) { - val file = factory.createFileFromText("t.jai", JaiLanguage, text) - val error = firstError(file) - if (error == null) { - println("ok ${text.replace("\n", "\\n")}") - if (System.getProperty("jai.debug.tree") != null) { - println(com.intellij.psi.impl.DebugUtil.psiToString(file, true, false)) - } - } else { - failures++ - val at = text.substring(error.textOffset).take(28).replace("\n", "\\n") - println("FAIL ${text.replace("\n", "\\n")}") - println(" ${error.errorDescription} | at '$at'") - if (System.getProperty("jai.debug.tree") != null) { - println(com.intellij.psi.impl.DebugUtil.psiToString(file, true, false)) - } + if (!file.exists()) { + println("missing: $relative") + continue + } + val text = file.readText() + val psi = PsiFileFactory.getInstance(project).createFileFromText(file.name, JaiLanguage, text) + val errors = errorsIn(psi) + if (errors.isEmpty()) { + println("$relative: clean") + continue + } + println("$relative: ${errors.size} error(s)") + for (error in errors.take(REPORTED_ERRORS)) { + val line = text.substring(0, error.textOffset).count { it == '\n' } + 1 + println(" :$line ${error.errorDescription}") + println(" at '${around(text, error.textOffset)}'") } } - println("$failures/${snippets.size} snippets failed") } - private fun dumpFile(file: File) { - val text = file.readText() - val psi = PsiFileFactory.getInstance(project).createFileFromText(file.name, JaiLanguage, text) + private fun around( + text: String, + offset: Int, + ): String = text.substring(offset).take(SNIPPET_WIDTH).replace("\n", "\\n") + + private fun errorsIn(file: com.intellij.psi.PsiFile): List { val errors = mutableListOf() - psi.accept( + file.accept( object : PsiRecursiveElementWalkingVisitor() { override fun visitErrorElement(element: PsiErrorElement) { errors.add(element) @@ -80,28 +86,11 @@ class DebugParseTest : BasePlatformTestCase() { } }, ) - if (errors.isEmpty()) { - println("${file.name}: clean") - return - } - println("${file.name}: ${errors.size} error(s)") - for (error in errors.take(6)) { - val line = text.substring(0, error.textOffset).count { it == '\n' } + 1 - println(" :$line ${error.errorDescription}") - println(" at '${text.substring(error.textOffset).take(70).replace("\n", "\\n")}'") - } + return errors } - private fun firstError(file: PsiFile): PsiErrorElement? { - var first: PsiErrorElement? = null - file.accept( - object : PsiRecursiveElementWalkingVisitor() { - override fun visitErrorElement(element: PsiErrorElement) { - if (first == null) first = element - super.visitErrorElement(element) - } - }, - ) - return first + private companion object { + const val REPORTED_ERRORS = 6 + const val SNIPPET_WIDTH = 70 } } diff --git a/src/test/kotlin/dev/hgh/jai/parser/JaiParserGoldenTest.kt b/src/test/kotlin/dev/hgh/jai/parser/JaiParserGoldenTest.kt index af4fd6e..dad1be5 100644 --- a/src/test/kotlin/dev/hgh/jai/parser/JaiParserGoldenTest.kt +++ b/src/test/kotlin/dev/hgh/jai/parser/JaiParserGoldenTest.kt @@ -1,11 +1,24 @@ package dev.hgh.jai.parser +/** + * Tier 2 (docs/BUILD_PLAN.md §3): golden PSI trees for the constructs listed as + * gotchas in `docs/JAI_LANGUAGE_REFERENCE.md` §14. + * + * The corpus gate proves the grammar *accepts* real code; these prove it builds the + * tree we intend, so a refactor that quietly reshapes the PSI shows up as a diff. + * + * `ParsingTestCase` writes the expected `.txt` when it is missing, which makes adding + * a case cheap — but the generated tree must be read before committing, or the test + * asserts nothing. + */ class JaiParserGoldenTest : JaiParsingTestCase() { - fun testSimpleDeclarations() { - doTest(true) - } + fun testDeclarations() = doTest(true) - fun testExpressions() { - doTest(true) - } + fun testProcedures() = doTest(true) + + fun testTypes() = doTest(true) + + fun testControlFlow() = doTest(true) + + fun testDirectives() = doTest(true) } diff --git a/src/test/testData/parsing/ControlFlow.jai b/src/test/testData/parsing/ControlFlow.jai new file mode 100644 index 0000000..8490bea --- /dev/null +++ b/src/test/testData/parsing/ControlFlow.jai @@ -0,0 +1,15 @@ +run :: () { + if cond { } else if other { } else { } + if flag then quit = true; + if value == { + case .BANANA; print("b"); + case; print("d"); + } + while running { break; } + for 1..7 { print("%", it); } + for < * v, i: array { remove v; } + for :expansion holder { } + defer free(p); + push_context ctx { work(); } + s := ifx a then b else c; +} diff --git a/src/test/testData/parsing/ControlFlow.txt b/src/test/testData/parsing/ControlFlow.txt new file mode 100644 index 0000000..175807f --- /dev/null +++ b/src/test/testData/parsing/ControlFlow.txt @@ -0,0 +1,221 @@ +Jai File(0,390) + JaiStatementImpl(STATEMENT)(0,390) + JaiDeclarationImpl(DECLARATION)(0,390) + JaiDeclNamesImpl(DECL_NAMES)(0,3) + JaiDeclNameImpl(DECL_NAME)(0,3) + PsiElement(Jai:IDENT)('run')(0,3) + PsiElement(Jai:::)('::')(4,6) + JaiInitializerImpl(INITIALIZER)(7,390) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(7,390) + PsiElement(Jai:()('(')(7,8) + PsiElement(Jai:))(')')(8,9) + JaiBlockImpl(BLOCK)(10,390) + PsiElement(Jai:{)('{')(10,11) + JaiStatementImpl(STATEMENT)(16,54) + JaiIfStatementImpl(IF_STATEMENT)(16,54) + PsiElement(Jai:if)('if')(16,18) + JaiRefExprImpl(REF_EXPR)(19,23) + PsiElement(Jai:IDENT)('cond')(19,23) + JaiStatementImpl(STATEMENT)(24,27) + JaiBlockImpl(BLOCK)(24,27) + PsiElement(Jai:{)('{')(24,25) + PsiElement(Jai:})('}')(26,27) + JaiElseClauseImpl(ELSE_CLAUSE)(28,54) + PsiElement(Jai:else)('else')(28,32) + JaiStatementImpl(STATEMENT)(33,54) + JaiIfStatementImpl(IF_STATEMENT)(33,54) + PsiElement(Jai:if)('if')(33,35) + JaiRefExprImpl(REF_EXPR)(36,41) + PsiElement(Jai:IDENT)('other')(36,41) + JaiStatementImpl(STATEMENT)(42,45) + JaiBlockImpl(BLOCK)(42,45) + PsiElement(Jai:{)('{')(42,43) + PsiElement(Jai:})('}')(44,45) + JaiElseClauseImpl(ELSE_CLAUSE)(46,54) + PsiElement(Jai:else)('else')(46,50) + JaiStatementImpl(STATEMENT)(51,54) + JaiBlockImpl(BLOCK)(51,54) + PsiElement(Jai:{)('{')(51,52) + PsiElement(Jai:})('}')(53,54) + JaiStatementImpl(STATEMENT)(59,84) + JaiIfStatementImpl(IF_STATEMENT)(59,84) + PsiElement(Jai:if)('if')(59,61) + JaiRefExprImpl(REF_EXPR)(62,66) + PsiElement(Jai:IDENT)('flag')(62,66) + PsiElement(Jai:then)('then')(67,71) + JaiStatementImpl(STATEMENT)(72,84) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(72,84) + JaiAssignExprImpl(ASSIGN_EXPR)(72,83) + JaiRefExprImpl(REF_EXPR)(72,76) + PsiElement(Jai:IDENT)('quit')(72,76) + PsiElement(Jai:=)('=')(77,78) + JaiLiteralExprImpl(LITERAL_EXPR)(79,83) + PsiElement(Jai:true)('true')(79,83) + PsiElement(Jai:;)(';')(83,84) + JaiStatementImpl(STATEMENT)(89,176) + JaiIfStatementImpl(IF_STATEMENT)(89,176) + PsiElement(Jai:if)('if')(89,91) + JaiRefExprImpl(REF_EXPR)(92,97) + PsiElement(Jai:IDENT)('value')(92,97) + JaiSwitchBodyImpl(SWITCH_BODY)(98,176) + PsiElement(Jai:==)('==')(98,100) + PsiElement(Jai:{)('{')(101,102) + JaiCaseClauseImpl(CASE_CLAUSE)(111,136) + PsiElement(Jai:case)('case')(111,115) + JaiUnaryDotExprImpl(UNARY_DOT_EXPR)(116,123) + PsiElement(Jai:.)('.')(116,117) + JaiMemberNameImpl(MEMBER_NAME)(117,123) + PsiElement(Jai:IDENT)('BANANA')(117,123) + PsiElement(Jai:;)(';')(123,124) + JaiStatementImpl(STATEMENT)(125,136) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(125,136) + JaiCallExprImpl(CALL_EXPR)(125,135) + JaiRefExprImpl(REF_EXPR)(125,130) + PsiElement(Jai:IDENT)('print')(125,130) + PsiElement(Jai:()('(')(130,131) + JaiArgumentImpl(ARGUMENT)(131,134) + JaiLiteralExprImpl(LITERAL_EXPR)(131,134) + PsiElement(Jai:STRING)('"b"')(131,134) + PsiElement(Jai:))(')')(134,135) + PsiElement(Jai:;)(';')(135,136) + JaiCaseClauseImpl(CASE_CLAUSE)(145,170) + PsiElement(Jai:case)('case')(145,149) + PsiElement(Jai:;)(';')(149,150) + JaiStatementImpl(STATEMENT)(159,170) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(159,170) + JaiCallExprImpl(CALL_EXPR)(159,169) + JaiRefExprImpl(REF_EXPR)(159,164) + PsiElement(Jai:IDENT)('print')(159,164) + PsiElement(Jai:()('(')(164,165) + JaiArgumentImpl(ARGUMENT)(165,168) + JaiLiteralExprImpl(LITERAL_EXPR)(165,168) + PsiElement(Jai:STRING)('"d"')(165,168) + PsiElement(Jai:))(')')(168,169) + PsiElement(Jai:;)(';')(169,170) + PsiElement(Jai:})('}')(175,176) + JaiStatementImpl(STATEMENT)(181,205) + JaiWhileStatementImpl(WHILE_STATEMENT)(181,205) + PsiElement(Jai:while)('while')(181,186) + JaiRefExprImpl(REF_EXPR)(187,194) + PsiElement(Jai:IDENT)('running')(187,194) + JaiStatementImpl(STATEMENT)(195,205) + JaiBlockImpl(BLOCK)(195,205) + PsiElement(Jai:{)('{')(195,196) + JaiStatementImpl(STATEMENT)(197,203) + JaiBreakStatementImpl(BREAK_STATEMENT)(197,203) + PsiElement(Jai:break)('break')(197,202) + PsiElement(Jai:;)(';')(202,203) + PsiElement(Jai:})('}')(204,205) + JaiStatementImpl(STATEMENT)(210,238) + JaiForStatementImpl(FOR_STATEMENT)(210,238) + PsiElement(Jai:for)('for')(210,213) + JaiRangeExprImpl(RANGE_EXPR)(214,218) + JaiLiteralExprImpl(LITERAL_EXPR)(214,215) + PsiElement(Jai:NUMBER)('1')(214,215) + PsiElement(Jai:..)('..')(215,217) + JaiLiteralExprImpl(LITERAL_EXPR)(217,218) + PsiElement(Jai:NUMBER)('7')(217,218) + JaiStatementImpl(STATEMENT)(219,238) + JaiBlockImpl(BLOCK)(219,238) + PsiElement(Jai:{)('{')(219,220) + JaiStatementImpl(STATEMENT)(221,236) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(221,236) + JaiCallExprImpl(CALL_EXPR)(221,235) + JaiRefExprImpl(REF_EXPR)(221,226) + PsiElement(Jai:IDENT)('print')(221,226) + PsiElement(Jai:()('(')(226,227) + JaiArgumentImpl(ARGUMENT)(227,230) + JaiLiteralExprImpl(LITERAL_EXPR)(227,230) + PsiElement(Jai:STRING)('"%"')(227,230) + PsiElement(Jai:,)(',')(230,231) + JaiArgumentImpl(ARGUMENT)(232,234) + JaiRefExprImpl(REF_EXPR)(232,234) + PsiElement(Jai:IDENT)('it')(232,234) + PsiElement(Jai:))(')')(234,235) + PsiElement(Jai:;)(';')(235,236) + PsiElement(Jai:})('}')(237,238) + JaiStatementImpl(STATEMENT)(243,276) + JaiForStatementImpl(FOR_STATEMENT)(243,276) + PsiElement(Jai:for)('for')(243,246) + PsiElement(Jai:<)('<')(247,248) + PsiElement(Jai:*)('*')(249,250) + JaiForNamesImpl(FOR_NAMES)(251,255) + JaiForNameImpl(FOR_NAME)(251,252) + PsiElement(Jai:IDENT)('v')(251,252) + PsiElement(Jai:,)(',')(252,253) + JaiForNameImpl(FOR_NAME)(254,255) + PsiElement(Jai:IDENT)('i')(254,255) + PsiElement(Jai::)(':')(255,256) + JaiRefExprImpl(REF_EXPR)(257,262) + PsiElement(Jai:IDENT)('array')(257,262) + JaiStatementImpl(STATEMENT)(263,276) + JaiBlockImpl(BLOCK)(263,276) + PsiElement(Jai:{)('{')(263,264) + JaiStatementImpl(STATEMENT)(265,274) + JaiRemoveStatementImpl(REMOVE_STATEMENT)(265,274) + PsiElement(Jai:remove)('remove')(265,271) + JaiRefExprImpl(REF_EXPR)(272,273) + PsiElement(Jai:IDENT)('v')(272,273) + PsiElement(Jai:;)(';')(273,274) + PsiElement(Jai:})('}')(275,276) + JaiStatementImpl(STATEMENT)(281,306) + JaiForStatementImpl(FOR_STATEMENT)(281,306) + PsiElement(Jai:for)('for')(281,284) + PsiElement(Jai::)(':')(285,286) + JaiRefExprImpl(REF_EXPR)(286,295) + PsiElement(Jai:IDENT)('expansion')(286,295) + JaiRefExprImpl(REF_EXPR)(296,302) + PsiElement(Jai:IDENT)('holder')(296,302) + JaiStatementImpl(STATEMENT)(303,306) + JaiBlockImpl(BLOCK)(303,306) + PsiElement(Jai:{)('{')(303,304) + PsiElement(Jai:})('}')(305,306) + JaiStatementImpl(STATEMENT)(311,325) + JaiDeferStatementImpl(DEFER_STATEMENT)(311,325) + PsiElement(Jai:defer)('defer')(311,316) + JaiStatementImpl(STATEMENT)(317,325) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(317,325) + JaiCallExprImpl(CALL_EXPR)(317,324) + JaiRefExprImpl(REF_EXPR)(317,321) + PsiElement(Jai:IDENT)('free')(317,321) + PsiElement(Jai:()('(')(321,322) + JaiArgumentImpl(ARGUMENT)(322,323) + JaiRefExprImpl(REF_EXPR)(322,323) + PsiElement(Jai:IDENT)('p')(322,323) + PsiElement(Jai:))(')')(323,324) + PsiElement(Jai:;)(';')(324,325) + JaiStatementImpl(STATEMENT)(330,358) + JaiPushContextStatementImpl(PUSH_CONTEXT_STATEMENT)(330,358) + PsiElement(Jai:push_context)('push_context')(330,342) + JaiRefExprImpl(REF_EXPR)(343,346) + PsiElement(Jai:IDENT)('ctx')(343,346) + JaiBlockImpl(BLOCK)(347,358) + PsiElement(Jai:{)('{')(347,348) + JaiStatementImpl(STATEMENT)(349,356) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(349,356) + JaiCallExprImpl(CALL_EXPR)(349,355) + JaiRefExprImpl(REF_EXPR)(349,353) + PsiElement(Jai:IDENT)('work')(349,353) + PsiElement(Jai:()('(')(353,354) + PsiElement(Jai:))(')')(354,355) + PsiElement(Jai:;)(';')(355,356) + PsiElement(Jai:})('}')(357,358) + JaiStatementImpl(STATEMENT)(363,388) + JaiDeclarationImpl(DECLARATION)(363,388) + JaiDeclNamesImpl(DECL_NAMES)(363,364) + JaiDeclNameImpl(DECL_NAME)(363,364) + PsiElement(Jai:IDENT)('s')(363,364) + PsiElement(Jai::=)(':=')(365,367) + JaiInitializerImpl(INITIALIZER)(368,387) + JaiIfxExprImpl(IFX_EXPR)(368,387) + PsiElement(Jai:ifx)('ifx')(368,371) + JaiRefExprImpl(REF_EXPR)(372,373) + PsiElement(Jai:IDENT)('a')(372,373) + PsiElement(Jai:then)('then')(374,378) + JaiRefExprImpl(REF_EXPR)(379,380) + PsiElement(Jai:IDENT)('b')(379,380) + PsiElement(Jai:else)('else')(381,385) + JaiRefExprImpl(REF_EXPR)(386,387) + PsiElement(Jai:IDENT)('c')(386,387) + PsiElement(Jai:;)(';')(387,388) + PsiElement(Jai:})('}')(389,390) \ No newline at end of file diff --git a/src/test/testData/parsing/Declarations.jai b/src/test/testData/parsing/Declarations.jai new file mode 100644 index 0000000..b98581f --- /dev/null +++ b/src/test/testData/parsing/Declarations.jai @@ -0,0 +1,7 @@ +a : float = 37.0; +b : float; +c := 111.0; +d : float : -123.45; +e :: 42; +f : Vector3 = ---; +x, y, z: float; diff --git a/src/test/testData/parsing/Declarations.txt b/src/test/testData/parsing/Declarations.txt new file mode 100644 index 0000000..143da33 --- /dev/null +++ b/src/test/testData/parsing/Declarations.txt @@ -0,0 +1,85 @@ +Jai File(0,105) + JaiStatementImpl(STATEMENT)(0,17) + JaiDeclarationImpl(DECLARATION)(0,17) + JaiDeclNamesImpl(DECL_NAMES)(0,1) + JaiDeclNameImpl(DECL_NAME)(0,1) + PsiElement(Jai:IDENT)('a')(0,1) + PsiElement(Jai::)(':')(2,3) + JaiRefExprImpl(REF_EXPR)(4,9) + PsiElement(Jai:IDENT)('float')(4,9) + PsiElement(Jai:=)('=')(10,11) + JaiInitializerImpl(INITIALIZER)(12,16) + JaiLiteralExprImpl(LITERAL_EXPR)(12,16) + PsiElement(Jai:NUMBER)('37.0')(12,16) + PsiElement(Jai:;)(';')(16,17) + JaiStatementImpl(STATEMENT)(18,28) + JaiDeclarationImpl(DECLARATION)(18,28) + JaiDeclNamesImpl(DECL_NAMES)(18,19) + JaiDeclNameImpl(DECL_NAME)(18,19) + PsiElement(Jai:IDENT)('b')(18,19) + PsiElement(Jai::)(':')(20,21) + JaiRefExprImpl(REF_EXPR)(22,27) + PsiElement(Jai:IDENT)('float')(22,27) + PsiElement(Jai:;)(';')(27,28) + JaiStatementImpl(STATEMENT)(29,40) + JaiDeclarationImpl(DECLARATION)(29,40) + JaiDeclNamesImpl(DECL_NAMES)(29,30) + JaiDeclNameImpl(DECL_NAME)(29,30) + PsiElement(Jai:IDENT)('c')(29,30) + PsiElement(Jai::=)(':=')(31,33) + JaiInitializerImpl(INITIALIZER)(34,39) + JaiLiteralExprImpl(LITERAL_EXPR)(34,39) + PsiElement(Jai:NUMBER)('111.0')(34,39) + PsiElement(Jai:;)(';')(39,40) + JaiStatementImpl(STATEMENT)(41,61) + JaiDeclarationImpl(DECLARATION)(41,61) + JaiDeclNamesImpl(DECL_NAMES)(41,42) + JaiDeclNameImpl(DECL_NAME)(41,42) + PsiElement(Jai:IDENT)('d')(41,42) + PsiElement(Jai::)(':')(43,44) + JaiRefExprImpl(REF_EXPR)(45,50) + PsiElement(Jai:IDENT)('float')(45,50) + PsiElement(Jai::)(':')(51,52) + JaiInitializerImpl(INITIALIZER)(53,60) + JaiPrefixExprImpl(PREFIX_EXPR)(53,60) + PsiElement(Jai:-)('-')(53,54) + JaiLiteralExprImpl(LITERAL_EXPR)(54,60) + PsiElement(Jai:NUMBER)('123.45')(54,60) + PsiElement(Jai:;)(';')(60,61) + JaiStatementImpl(STATEMENT)(62,70) + JaiDeclarationImpl(DECLARATION)(62,70) + JaiDeclNamesImpl(DECL_NAMES)(62,63) + JaiDeclNameImpl(DECL_NAME)(62,63) + PsiElement(Jai:IDENT)('e')(62,63) + PsiElement(Jai:::)('::')(64,66) + JaiInitializerImpl(INITIALIZER)(67,69) + JaiLiteralExprImpl(LITERAL_EXPR)(67,69) + PsiElement(Jai:NUMBER)('42')(67,69) + PsiElement(Jai:;)(';')(69,70) + JaiStatementImpl(STATEMENT)(71,89) + JaiDeclarationImpl(DECLARATION)(71,89) + JaiDeclNamesImpl(DECL_NAMES)(71,72) + JaiDeclNameImpl(DECL_NAME)(71,72) + PsiElement(Jai:IDENT)('f')(71,72) + PsiElement(Jai::)(':')(73,74) + JaiRefExprImpl(REF_EXPR)(75,82) + PsiElement(Jai:IDENT)('Vector3')(75,82) + PsiElement(Jai:=)('=')(83,84) + JaiInitializerImpl(INITIALIZER)(85,88) + PsiElement(Jai:---)('---')(85,88) + PsiElement(Jai:;)(';')(88,89) + JaiStatementImpl(STATEMENT)(90,105) + JaiDeclarationImpl(DECLARATION)(90,105) + JaiDeclNamesImpl(DECL_NAMES)(90,97) + JaiDeclNameImpl(DECL_NAME)(90,91) + PsiElement(Jai:IDENT)('x')(90,91) + PsiElement(Jai:,)(',')(91,92) + JaiDeclNameImpl(DECL_NAME)(93,94) + PsiElement(Jai:IDENT)('y')(93,94) + PsiElement(Jai:,)(',')(94,95) + JaiDeclNameImpl(DECL_NAME)(96,97) + PsiElement(Jai:IDENT)('z')(96,97) + PsiElement(Jai::)(':')(97,98) + JaiRefExprImpl(REF_EXPR)(99,104) + PsiElement(Jai:IDENT)('float')(99,104) + PsiElement(Jai:;)(';')(104,105) \ No newline at end of file diff --git a/src/test/testData/parsing/Directives.jai b/src/test/testData/parsing/Directives.jai new file mode 100644 index 0000000..8e9397d --- /dev/null +++ b/src/test/testData/parsing/Directives.jai @@ -0,0 +1,13 @@ +#import "Basic"; +#load "other.jai"; +#scope_file +Sort :: #import "Sort"; +BODY :: #string DONE +raw text +DONE +#if OS == .WINDOWS { + lib :: #library,system,link_always "user32"; +} else { + #assert false "unsupported"; +} +c :: #char "a"; diff --git a/src/test/testData/parsing/Directives.txt b/src/test/testData/parsing/Directives.txt new file mode 100644 index 0000000..36c75fa --- /dev/null +++ b/src/test/testData/parsing/Directives.txt @@ -0,0 +1,97 @@ +Jai File(0,236) + JaiStatementImpl(STATEMENT)(0,16) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(0,16) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(0,15) + PsiElement(Jai:DIRECTIVE)('#import')(0,7) + JaiLiteralExprImpl(LITERAL_EXPR)(8,15) + PsiElement(Jai:STRING)('"Basic"')(8,15) + PsiElement(Jai:;)(';')(15,16) + JaiStatementImpl(STATEMENT)(17,35) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(17,35) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(17,34) + PsiElement(Jai:DIRECTIVE)('#load')(17,22) + JaiLiteralExprImpl(LITERAL_EXPR)(23,34) + PsiElement(Jai:STRING)('"other.jai"')(23,34) + PsiElement(Jai:;)(';')(34,35) + JaiStatementImpl(STATEMENT)(36,47) + JaiDirectiveStatementImpl(DIRECTIVE_STATEMENT)(36,47) + PsiElement(Jai:DIRECTIVE)('#scope_file')(36,47) + JaiStatementImpl(STATEMENT)(48,71) + JaiDeclarationImpl(DECLARATION)(48,71) + JaiDeclNamesImpl(DECL_NAMES)(48,52) + JaiDeclNameImpl(DECL_NAME)(48,52) + PsiElement(Jai:IDENT)('Sort')(48,52) + PsiElement(Jai:::)('::')(53,55) + JaiInitializerImpl(INITIALIZER)(56,70) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(56,70) + PsiElement(Jai:DIRECTIVE)('#import')(56,63) + JaiLiteralExprImpl(LITERAL_EXPR)(64,70) + PsiElement(Jai:STRING)('"Sort"')(64,70) + PsiElement(Jai:;)(';')(70,71) + JaiStatementImpl(STATEMENT)(72,106) + JaiDeclarationImpl(DECLARATION)(72,106) + JaiDeclNamesImpl(DECL_NAMES)(72,76) + JaiDeclNameImpl(DECL_NAME)(72,76) + PsiElement(Jai:IDENT)('BODY')(72,76) + PsiElement(Jai:::)('::')(77,79) + JaiInitializerImpl(INITIALIZER)(80,106) + JaiLiteralExprImpl(LITERAL_EXPR)(80,106) + PsiElement(Jai:HERE_STRING)('#string DONE\nraw text\nDONE')(80,106) + JaiStatementImpl(STATEMENT)(107,220) + JaiIfStatementImpl(IF_STATEMENT)(107,220) + PsiElement(Jai:DIRECTIVE)('#if')(107,110) + JaiEqualityExprImpl(EQUALITY_EXPR)(111,125) + JaiRefExprImpl(REF_EXPR)(111,113) + PsiElement(Jai:IDENT)('OS')(111,113) + PsiElement(Jai:==)('==')(114,116) + JaiUnaryDotExprImpl(UNARY_DOT_EXPR)(117,125) + PsiElement(Jai:.)('.')(117,118) + JaiMemberNameImpl(MEMBER_NAME)(118,125) + PsiElement(Jai:IDENT)('WINDOWS')(118,125) + JaiStatementImpl(STATEMENT)(126,178) + JaiBlockImpl(BLOCK)(126,178) + PsiElement(Jai:{)('{')(126,127) + JaiStatementImpl(STATEMENT)(132,176) + JaiDeclarationImpl(DECLARATION)(132,176) + JaiDeclNamesImpl(DECL_NAMES)(132,135) + JaiDeclNameImpl(DECL_NAME)(132,135) + PsiElement(Jai:IDENT)('lib')(132,135) + PsiElement(Jai:::)('::')(136,138) + JaiInitializerImpl(INITIALIZER)(139,175) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(139,175) + PsiElement(Jai:DIRECTIVE)('#library')(139,147) + PsiElement(Jai:,)(',')(147,148) + PsiElement(Jai:IDENT)('system')(148,154) + PsiElement(Jai:,)(',')(154,155) + PsiElement(Jai:IDENT)('link_always')(155,166) + JaiLiteralExprImpl(LITERAL_EXPR)(167,175) + PsiElement(Jai:STRING)('"user32"')(167,175) + PsiElement(Jai:;)(';')(175,176) + PsiElement(Jai:})('}')(177,178) + JaiElseClauseImpl(ELSE_CLAUSE)(179,220) + PsiElement(Jai:else)('else')(179,183) + JaiStatementImpl(STATEMENT)(184,220) + JaiBlockImpl(BLOCK)(184,220) + PsiElement(Jai:{)('{')(184,185) + JaiStatementImpl(STATEMENT)(190,218) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(190,218) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(190,217) + PsiElement(Jai:DIRECTIVE)('#assert')(190,197) + JaiLiteralExprImpl(LITERAL_EXPR)(198,203) + PsiElement(Jai:false)('false')(198,203) + JaiLiteralExprImpl(LITERAL_EXPR)(204,217) + PsiElement(Jai:STRING)('"unsupported"')(204,217) + PsiElement(Jai:;)(';')(217,218) + PsiElement(Jai:})('}')(219,220) + JaiStatementImpl(STATEMENT)(221,236) + JaiDeclarationImpl(DECLARATION)(221,236) + JaiDeclNamesImpl(DECL_NAMES)(221,222) + JaiDeclNameImpl(DECL_NAME)(221,222) + PsiElement(Jai:IDENT)('c')(221,222) + PsiElement(Jai:::)('::')(223,225) + JaiInitializerImpl(INITIALIZER)(226,235) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(226,235) + PsiElement(Jai:DIRECTIVE)('#char')(226,231) + JaiLiteralExprImpl(LITERAL_EXPR)(232,235) + PsiElement(Jai:STRING)('"a"')(232,235) + PsiElement(Jai:;)(';')(235,236) \ No newline at end of file diff --git a/src/test/testData/parsing/Expressions.jai b/src/test/testData/parsing/Expressions.jai deleted file mode 100644 index 6670eb2..0000000 --- a/src/test/testData/parsing/Expressions.jai +++ /dev/null @@ -1,2 +0,0 @@ -x = a + b * c; -foo(x, y + 1); diff --git a/src/test/testData/parsing/Expressions.txt b/src/test/testData/parsing/Expressions.txt deleted file mode 100644 index 83ec6dd..0000000 --- a/src/test/testData/parsing/Expressions.txt +++ /dev/null @@ -1,37 +0,0 @@ -Jai File(0,29) - JaiStatementImpl(STATEMENT)(0,14) - JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(0,14) - JaiAssignExprImpl(ASSIGN_EXPR)(0,13) - JaiRefExprImpl(REF_EXPR)(0,1) - PsiElement(Jai:IDENT)('x')(0,1) - PsiElement(Jai:=)('=')(2,3) - JaiAddExprImpl(ADD_EXPR)(4,13) - JaiRefExprImpl(REF_EXPR)(4,5) - PsiElement(Jai:IDENT)('a')(4,5) - PsiElement(Jai:+)('+')(6,7) - JaiMulExprImpl(MUL_EXPR)(8,13) - JaiRefExprImpl(REF_EXPR)(8,9) - PsiElement(Jai:IDENT)('b')(8,9) - PsiElement(Jai:*)('*')(10,11) - JaiRefExprImpl(REF_EXPR)(12,13) - PsiElement(Jai:IDENT)('c')(12,13) - PsiElement(Jai:;)(';')(13,14) - JaiStatementImpl(STATEMENT)(15,29) - JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(15,29) - JaiCallExprImpl(CALL_EXPR)(15,28) - JaiRefExprImpl(REF_EXPR)(15,18) - PsiElement(Jai:IDENT)('foo')(15,18) - PsiElement(Jai:()('(')(18,19) - JaiArgumentImpl(ARGUMENT)(19,20) - JaiRefExprImpl(REF_EXPR)(19,20) - PsiElement(Jai:IDENT)('x')(19,20) - PsiElement(Jai:,)(',')(20,21) - JaiArgumentImpl(ARGUMENT)(22,27) - JaiAddExprImpl(ADD_EXPR)(22,27) - JaiRefExprImpl(REF_EXPR)(22,23) - PsiElement(Jai:IDENT)('y')(22,23) - PsiElement(Jai:+)('+')(24,25) - JaiLiteralExprImpl(LITERAL_EXPR)(26,27) - PsiElement(Jai:NUMBER)('1')(26,27) - PsiElement(Jai:))(')')(27,28) - PsiElement(Jai:;)(';')(28,29) \ No newline at end of file diff --git a/src/test/testData/parsing/Procedures.jai b/src/test/testData/parsing/Procedures.jai new file mode 100644 index 0000000..ee09da8 --- /dev/null +++ b/src/test/testData/parsing/Procedures.jai @@ -0,0 +1,7 @@ +main :: () { } +named :: (a: int) -> named: string { return "x"; } +multi :: () -> A, B { return a, b; } +variadic :: (fmt: string, args: ..Any) { } +polymorph :: (x: $T/interface Matchable) -> T { return x; } +foreign_proc :: (fd: s32) -> s32 #foreign libc "inotify_init1"; +lambda :: x => x.count; diff --git a/src/test/testData/parsing/Procedures.txt b/src/test/testData/parsing/Procedures.txt new file mode 100644 index 0000000..064f8fd --- /dev/null +++ b/src/test/testData/parsing/Procedures.txt @@ -0,0 +1,190 @@ +Jai File(0,293) + JaiStatementImpl(STATEMENT)(0,14) + JaiDeclarationImpl(DECLARATION)(0,14) + JaiDeclNamesImpl(DECL_NAMES)(0,4) + JaiDeclNameImpl(DECL_NAME)(0,4) + PsiElement(Jai:IDENT)('main')(0,4) + PsiElement(Jai:::)('::')(5,7) + JaiInitializerImpl(INITIALIZER)(8,14) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(8,14) + PsiElement(Jai:()('(')(8,9) + PsiElement(Jai:))(')')(9,10) + JaiBlockImpl(BLOCK)(11,14) + PsiElement(Jai:{)('{')(11,12) + PsiElement(Jai:})('}')(13,14) + JaiStatementImpl(STATEMENT)(15,65) + JaiDeclarationImpl(DECLARATION)(15,65) + JaiDeclNamesImpl(DECL_NAMES)(15,20) + JaiDeclNameImpl(DECL_NAME)(15,20) + PsiElement(Jai:IDENT)('named')(15,20) + PsiElement(Jai:::)('::')(21,23) + JaiInitializerImpl(INITIALIZER)(24,65) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(24,65) + PsiElement(Jai:()('(')(24,25) + JaiParameterImpl(PARAMETER)(25,31) + JaiParamNamesImpl(PARAM_NAMES)(25,26) + JaiParamNameImpl(PARAM_NAME)(25,26) + PsiElement(Jai:IDENT)('a')(25,26) + PsiElement(Jai::)(':')(26,27) + JaiRefExprImpl(REF_EXPR)(28,31) + PsiElement(Jai:IDENT)('int')(28,31) + PsiElement(Jai:))(')')(31,32) + PsiElement(Jai:->)('->')(33,35) + JaiReturnItemImpl(RETURN_ITEM)(36,49) + PsiElement(Jai:IDENT)('named')(36,41) + PsiElement(Jai::)(':')(41,42) + JaiRefExprImpl(REF_EXPR)(43,49) + PsiElement(Jai:IDENT)('string')(43,49) + JaiBlockImpl(BLOCK)(50,65) + PsiElement(Jai:{)('{')(50,51) + JaiStatementImpl(STATEMENT)(52,63) + JaiReturnStatementImpl(RETURN_STATEMENT)(52,63) + PsiElement(Jai:return)('return')(52,58) + JaiLiteralExprImpl(LITERAL_EXPR)(59,62) + PsiElement(Jai:STRING)('"x"')(59,62) + PsiElement(Jai:;)(';')(62,63) + PsiElement(Jai:})('}')(64,65) + JaiStatementImpl(STATEMENT)(66,102) + JaiDeclarationImpl(DECLARATION)(66,102) + JaiDeclNamesImpl(DECL_NAMES)(66,71) + JaiDeclNameImpl(DECL_NAME)(66,71) + PsiElement(Jai:IDENT)('multi')(66,71) + PsiElement(Jai:::)('::')(72,74) + JaiInitializerImpl(INITIALIZER)(75,102) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(75,102) + PsiElement(Jai:()('(')(75,76) + PsiElement(Jai:))(')')(76,77) + PsiElement(Jai:->)('->')(78,80) + JaiReturnItemImpl(RETURN_ITEM)(81,82) + JaiRefExprImpl(REF_EXPR)(81,82) + PsiElement(Jai:IDENT)('A')(81,82) + PsiElement(Jai:,)(',')(82,83) + JaiReturnItemImpl(RETURN_ITEM)(84,85) + JaiRefExprImpl(REF_EXPR)(84,85) + PsiElement(Jai:IDENT)('B')(84,85) + JaiBlockImpl(BLOCK)(86,102) + PsiElement(Jai:{)('{')(86,87) + JaiStatementImpl(STATEMENT)(88,100) + JaiReturnStatementImpl(RETURN_STATEMENT)(88,100) + PsiElement(Jai:return)('return')(88,94) + JaiRefExprImpl(REF_EXPR)(95,96) + PsiElement(Jai:IDENT)('a')(95,96) + PsiElement(Jai:,)(',')(96,97) + JaiRefExprImpl(REF_EXPR)(98,99) + PsiElement(Jai:IDENT)('b')(98,99) + PsiElement(Jai:;)(';')(99,100) + PsiElement(Jai:})('}')(101,102) + JaiStatementImpl(STATEMENT)(103,145) + JaiDeclarationImpl(DECLARATION)(103,145) + JaiDeclNamesImpl(DECL_NAMES)(103,111) + JaiDeclNameImpl(DECL_NAME)(103,111) + PsiElement(Jai:IDENT)('variadic')(103,111) + PsiElement(Jai:::)('::')(112,114) + JaiInitializerImpl(INITIALIZER)(115,145) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(115,145) + PsiElement(Jai:()('(')(115,116) + JaiParameterImpl(PARAMETER)(116,127) + JaiParamNamesImpl(PARAM_NAMES)(116,119) + JaiParamNameImpl(PARAM_NAME)(116,119) + PsiElement(Jai:IDENT)('fmt')(116,119) + PsiElement(Jai::)(':')(119,120) + JaiRefExprImpl(REF_EXPR)(121,127) + PsiElement(Jai:IDENT)('string')(121,127) + PsiElement(Jai:,)(',')(127,128) + JaiParameterImpl(PARAMETER)(129,140) + JaiParamNamesImpl(PARAM_NAMES)(129,133) + JaiParamNameImpl(PARAM_NAME)(129,133) + PsiElement(Jai:IDENT)('args')(129,133) + PsiElement(Jai::)(':')(133,134) + JaiPrefixExprImpl(PREFIX_EXPR)(135,140) + PsiElement(Jai:..)('..')(135,137) + JaiRefExprImpl(REF_EXPR)(137,140) + PsiElement(Jai:IDENT)('Any')(137,140) + PsiElement(Jai:))(')')(140,141) + JaiBlockImpl(BLOCK)(142,145) + PsiElement(Jai:{)('{')(142,143) + PsiElement(Jai:})('}')(144,145) + JaiStatementImpl(STATEMENT)(146,205) + JaiDeclarationImpl(DECLARATION)(146,205) + JaiDeclNamesImpl(DECL_NAMES)(146,155) + JaiDeclNameImpl(DECL_NAME)(146,155) + PsiElement(Jai:IDENT)('polymorph')(146,155) + PsiElement(Jai:::)('::')(156,158) + JaiInitializerImpl(INITIALIZER)(159,205) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(159,205) + PsiElement(Jai:()('(')(159,160) + JaiParameterImpl(PARAMETER)(160,185) + JaiParamNamesImpl(PARAM_NAMES)(160,161) + JaiParamNameImpl(PARAM_NAME)(160,161) + PsiElement(Jai:IDENT)('x')(160,161) + PsiElement(Jai::)(':')(161,162) + JaiMulExprImpl(MUL_EXPR)(163,185) + JaiPrefixExprImpl(PREFIX_EXPR)(163,165) + PsiElement(Jai:$)('$')(163,164) + JaiRefExprImpl(REF_EXPR)(164,165) + PsiElement(Jai:IDENT)('T')(164,165) + PsiElement(Jai:/)('/')(165,166) + JaiInterfaceExprImpl(INTERFACE_EXPR)(166,185) + PsiElement(Jai:interface)('interface')(166,175) + JaiRefExprImpl(REF_EXPR)(176,185) + PsiElement(Jai:IDENT)('Matchable')(176,185) + PsiElement(Jai:))(')')(185,186) + PsiElement(Jai:->)('->')(187,189) + JaiReturnItemImpl(RETURN_ITEM)(190,191) + JaiRefExprImpl(REF_EXPR)(190,191) + PsiElement(Jai:IDENT)('T')(190,191) + JaiBlockImpl(BLOCK)(192,205) + PsiElement(Jai:{)('{')(192,193) + JaiStatementImpl(STATEMENT)(194,203) + JaiReturnStatementImpl(RETURN_STATEMENT)(194,203) + PsiElement(Jai:return)('return')(194,200) + JaiRefExprImpl(REF_EXPR)(201,202) + PsiElement(Jai:IDENT)('x')(201,202) + PsiElement(Jai:;)(';')(202,203) + PsiElement(Jai:})('}')(204,205) + JaiStatementImpl(STATEMENT)(206,269) + JaiDeclarationImpl(DECLARATION)(206,269) + JaiDeclNamesImpl(DECL_NAMES)(206,218) + JaiDeclNameImpl(DECL_NAME)(206,218) + PsiElement(Jai:IDENT)('foreign_proc')(206,218) + PsiElement(Jai:::)('::')(219,221) + JaiInitializerImpl(INITIALIZER)(222,268) + JaiProcLiteralExprImpl(PROC_LITERAL_EXPR)(222,268) + PsiElement(Jai:()('(')(222,223) + JaiParameterImpl(PARAMETER)(223,230) + JaiParamNamesImpl(PARAM_NAMES)(223,225) + JaiParamNameImpl(PARAM_NAME)(223,225) + PsiElement(Jai:IDENT)('fd')(223,225) + PsiElement(Jai::)(':')(225,226) + JaiRefExprImpl(REF_EXPR)(227,230) + PsiElement(Jai:IDENT)('s32')(227,230) + PsiElement(Jai:))(')')(230,231) + PsiElement(Jai:->)('->')(232,234) + JaiReturnItemImpl(RETURN_ITEM)(235,238) + JaiRefExprImpl(REF_EXPR)(235,238) + PsiElement(Jai:IDENT)('s32')(235,238) + JaiProcModifierImpl(PROC_MODIFIER)(239,268) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(239,268) + PsiElement(Jai:DIRECTIVE)('#foreign')(239,247) + JaiRefExprImpl(REF_EXPR)(248,252) + PsiElement(Jai:IDENT)('libc')(248,252) + PsiElement(Jai:STRING)('"inotify_init1"')(253,268) + PsiElement(Jai:;)(';')(268,269) + JaiStatementImpl(STATEMENT)(270,293) + JaiDeclarationImpl(DECLARATION)(270,293) + JaiDeclNamesImpl(DECL_NAMES)(270,276) + JaiDeclNameImpl(DECL_NAME)(270,276) + PsiElement(Jai:IDENT)('lambda')(270,276) + PsiElement(Jai:::)('::')(277,279) + JaiInitializerImpl(INITIALIZER)(280,292) + JaiLambdaExprImpl(LAMBDA_EXPR)(280,292) + JaiRefExprImpl(REF_EXPR)(280,281) + PsiElement(Jai:IDENT)('x')(280,281) + PsiElement(Jai:=>)('=>')(282,284) + JaiMemberExprImpl(MEMBER_EXPR)(285,292) + JaiRefExprImpl(REF_EXPR)(285,286) + PsiElement(Jai:IDENT)('x')(285,286) + PsiElement(Jai:.)('.')(286,287) + JaiMemberNameImpl(MEMBER_NAME)(287,292) + PsiElement(Jai:IDENT)('count')(287,292) + PsiElement(Jai:;)(';')(292,293) \ No newline at end of file diff --git a/src/test/testData/parsing/SimpleDeclarations.jai b/src/test/testData/parsing/SimpleDeclarations.jai deleted file mode 100644 index 6835eac..0000000 --- a/src/test/testData/parsing/SimpleDeclarations.jai +++ /dev/null @@ -1,4 +0,0 @@ -a : float = 37.0; -b := 10; -c :: 42; -return a + b; diff --git a/src/test/testData/parsing/SimpleDeclarations.txt b/src/test/testData/parsing/SimpleDeclarations.txt deleted file mode 100644 index 84b4d0f..0000000 --- a/src/test/testData/parsing/SimpleDeclarations.txt +++ /dev/null @@ -1,44 +0,0 @@ -Jai File(0,49) - JaiStatementImpl(STATEMENT)(0,17) - JaiDeclarationImpl(DECLARATION)(0,17) - JaiDeclNamesImpl(DECL_NAMES)(0,1) - JaiDeclNameImpl(DECL_NAME)(0,1) - PsiElement(Jai:IDENT)('a')(0,1) - PsiElement(Jai::)(':')(2,3) - JaiRefExprImpl(REF_EXPR)(4,9) - PsiElement(Jai:IDENT)('float')(4,9) - PsiElement(Jai:=)('=')(10,11) - JaiInitializerImpl(INITIALIZER)(12,16) - JaiLiteralExprImpl(LITERAL_EXPR)(12,16) - PsiElement(Jai:NUMBER)('37.0')(12,16) - PsiElement(Jai:;)(';')(16,17) - JaiStatementImpl(STATEMENT)(18,26) - JaiDeclarationImpl(DECLARATION)(18,26) - JaiDeclNamesImpl(DECL_NAMES)(18,19) - JaiDeclNameImpl(DECL_NAME)(18,19) - PsiElement(Jai:IDENT)('b')(18,19) - PsiElement(Jai::=)(':=')(20,22) - JaiInitializerImpl(INITIALIZER)(23,25) - JaiLiteralExprImpl(LITERAL_EXPR)(23,25) - PsiElement(Jai:NUMBER)('10')(23,25) - PsiElement(Jai:;)(';')(25,26) - JaiStatementImpl(STATEMENT)(27,35) - JaiDeclarationImpl(DECLARATION)(27,35) - JaiDeclNamesImpl(DECL_NAMES)(27,28) - JaiDeclNameImpl(DECL_NAME)(27,28) - PsiElement(Jai:IDENT)('c')(27,28) - PsiElement(Jai:::)('::')(29,31) - JaiInitializerImpl(INITIALIZER)(32,34) - JaiLiteralExprImpl(LITERAL_EXPR)(32,34) - PsiElement(Jai:NUMBER)('42')(32,34) - PsiElement(Jai:;)(';')(34,35) - JaiStatementImpl(STATEMENT)(36,49) - JaiReturnStatementImpl(RETURN_STATEMENT)(36,49) - PsiElement(Jai:return)('return')(36,42) - JaiAddExprImpl(ADD_EXPR)(43,48) - JaiRefExprImpl(REF_EXPR)(43,44) - PsiElement(Jai:IDENT)('a')(43,44) - PsiElement(Jai:+)('+')(45,46) - JaiRefExprImpl(REF_EXPR)(47,48) - PsiElement(Jai:IDENT)('b')(47,48) - PsiElement(Jai:;)(';')(48,49) \ No newline at end of file diff --git a/src/test/testData/parsing/Types.jai b/src/test/testData/parsing/Types.jai new file mode 100644 index 0000000..f1a3337 --- /dev/null +++ b/src/test/testData/parsing/Types.jai @@ -0,0 +1,9 @@ +Person :: struct { name: string; } +Holder :: struct ($T: Type, $N: s64) { } +Fruits :: enum u32 #specified { BANANA :: 5; APPLE; } +Flags :: enum_flags u8 { A :: 0x1; } +U :: union { a: int; b: float; } +Phone :: [9] u8; +view: [] float; +dynamic: [..] int; +pointer: *Person; diff --git a/src/test/testData/parsing/Types.txt b/src/test/testData/parsing/Types.txt new file mode 100644 index 0000000..f37c4a8 --- /dev/null +++ b/src/test/testData/parsing/Types.txt @@ -0,0 +1,190 @@ +Jai File(0,269) + JaiStatementImpl(STATEMENT)(0,34) + JaiDeclarationImpl(DECLARATION)(0,34) + JaiDeclNamesImpl(DECL_NAMES)(0,6) + JaiDeclNameImpl(DECL_NAME)(0,6) + PsiElement(Jai:IDENT)('Person')(0,6) + PsiElement(Jai:::)('::')(7,9) + JaiInitializerImpl(INITIALIZER)(10,34) + JaiStructExprImpl(STRUCT_EXPR)(10,34) + PsiElement(Jai:struct)('struct')(10,16) + JaiBlockImpl(BLOCK)(17,34) + PsiElement(Jai:{)('{')(17,18) + JaiStatementImpl(STATEMENT)(19,32) + JaiDeclarationImpl(DECLARATION)(19,32) + JaiDeclNamesImpl(DECL_NAMES)(19,23) + JaiDeclNameImpl(DECL_NAME)(19,23) + PsiElement(Jai:IDENT)('name')(19,23) + PsiElement(Jai::)(':')(23,24) + JaiRefExprImpl(REF_EXPR)(25,31) + PsiElement(Jai:IDENT)('string')(25,31) + PsiElement(Jai:;)(';')(31,32) + PsiElement(Jai:})('}')(33,34) + JaiStatementImpl(STATEMENT)(35,75) + JaiDeclarationImpl(DECLARATION)(35,75) + JaiDeclNamesImpl(DECL_NAMES)(35,41) + JaiDeclNameImpl(DECL_NAME)(35,41) + PsiElement(Jai:IDENT)('Holder')(35,41) + PsiElement(Jai:::)('::')(42,44) + JaiInitializerImpl(INITIALIZER)(45,75) + JaiStructExprImpl(STRUCT_EXPR)(45,75) + PsiElement(Jai:struct)('struct')(45,51) + PsiElement(Jai:()('(')(52,53) + JaiParameterImpl(PARAMETER)(53,61) + JaiParamNamesImpl(PARAM_NAMES)(53,55) + JaiParamNameImpl(PARAM_NAME)(53,55) + PsiElement(Jai:$)('$')(53,54) + PsiElement(Jai:IDENT)('T')(54,55) + PsiElement(Jai::)(':')(55,56) + JaiRefExprImpl(REF_EXPR)(57,61) + PsiElement(Jai:IDENT)('Type')(57,61) + PsiElement(Jai:,)(',')(61,62) + JaiParameterImpl(PARAMETER)(63,70) + JaiParamNamesImpl(PARAM_NAMES)(63,65) + JaiParamNameImpl(PARAM_NAME)(63,65) + PsiElement(Jai:$)('$')(63,64) + PsiElement(Jai:IDENT)('N')(64,65) + PsiElement(Jai::)(':')(65,66) + JaiRefExprImpl(REF_EXPR)(67,70) + PsiElement(Jai:IDENT)('s64')(67,70) + PsiElement(Jai:))(')')(70,71) + JaiBlockImpl(BLOCK)(72,75) + PsiElement(Jai:{)('{')(72,73) + PsiElement(Jai:})('}')(74,75) + JaiStatementImpl(STATEMENT)(76,129) + JaiDeclarationImpl(DECLARATION)(76,129) + JaiDeclNamesImpl(DECL_NAMES)(76,82) + JaiDeclNameImpl(DECL_NAME)(76,82) + PsiElement(Jai:IDENT)('Fruits')(76,82) + PsiElement(Jai:::)('::')(83,85) + JaiInitializerImpl(INITIALIZER)(86,129) + JaiEnumExprImpl(ENUM_EXPR)(86,129) + PsiElement(Jai:enum)('enum')(86,90) + JaiRefExprImpl(REF_EXPR)(91,94) + PsiElement(Jai:IDENT)('u32')(91,94) + JaiProcModifierImpl(PROC_MODIFIER)(95,105) + JaiDirectiveExprImpl(DIRECTIVE_EXPR)(95,105) + PsiElement(Jai:DIRECTIVE)('#specified')(95,105) + JaiBlockImpl(BLOCK)(106,129) + PsiElement(Jai:{)('{')(106,107) + JaiStatementImpl(STATEMENT)(108,120) + JaiDeclarationImpl(DECLARATION)(108,120) + JaiDeclNamesImpl(DECL_NAMES)(108,114) + JaiDeclNameImpl(DECL_NAME)(108,114) + PsiElement(Jai:IDENT)('BANANA')(108,114) + PsiElement(Jai:::)('::')(115,117) + JaiInitializerImpl(INITIALIZER)(118,119) + JaiLiteralExprImpl(LITERAL_EXPR)(118,119) + PsiElement(Jai:NUMBER)('5')(118,119) + PsiElement(Jai:;)(';')(119,120) + JaiStatementImpl(STATEMENT)(121,127) + JaiExpressionStatementImpl(EXPRESSION_STATEMENT)(121,127) + JaiRefExprImpl(REF_EXPR)(121,126) + PsiElement(Jai:IDENT)('APPLE')(121,126) + PsiElement(Jai:;)(';')(126,127) + PsiElement(Jai:})('}')(128,129) + JaiStatementImpl(STATEMENT)(130,166) + JaiDeclarationImpl(DECLARATION)(130,166) + JaiDeclNamesImpl(DECL_NAMES)(130,135) + JaiDeclNameImpl(DECL_NAME)(130,135) + PsiElement(Jai:IDENT)('Flags')(130,135) + PsiElement(Jai:::)('::')(136,138) + JaiInitializerImpl(INITIALIZER)(139,166) + JaiEnumExprImpl(ENUM_EXPR)(139,166) + PsiElement(Jai:enum_flags)('enum_flags')(139,149) + JaiRefExprImpl(REF_EXPR)(150,152) + PsiElement(Jai:IDENT)('u8')(150,152) + JaiBlockImpl(BLOCK)(153,166) + PsiElement(Jai:{)('{')(153,154) + JaiStatementImpl(STATEMENT)(155,164) + JaiDeclarationImpl(DECLARATION)(155,164) + JaiDeclNamesImpl(DECL_NAMES)(155,156) + JaiDeclNameImpl(DECL_NAME)(155,156) + PsiElement(Jai:IDENT)('A')(155,156) + PsiElement(Jai:::)('::')(157,159) + JaiInitializerImpl(INITIALIZER)(160,163) + JaiLiteralExprImpl(LITERAL_EXPR)(160,163) + PsiElement(Jai:NUMBER)('0x1')(160,163) + PsiElement(Jai:;)(';')(163,164) + PsiElement(Jai:})('}')(165,166) + JaiStatementImpl(STATEMENT)(167,199) + JaiDeclarationImpl(DECLARATION)(167,199) + JaiDeclNamesImpl(DECL_NAMES)(167,168) + JaiDeclNameImpl(DECL_NAME)(167,168) + PsiElement(Jai:IDENT)('U')(167,168) + PsiElement(Jai:::)('::')(169,171) + JaiInitializerImpl(INITIALIZER)(172,199) + JaiUnionExprImpl(UNION_EXPR)(172,199) + PsiElement(Jai:union)('union')(172,177) + JaiBlockImpl(BLOCK)(178,199) + PsiElement(Jai:{)('{')(178,179) + JaiStatementImpl(STATEMENT)(180,187) + JaiDeclarationImpl(DECLARATION)(180,187) + JaiDeclNamesImpl(DECL_NAMES)(180,181) + JaiDeclNameImpl(DECL_NAME)(180,181) + PsiElement(Jai:IDENT)('a')(180,181) + PsiElement(Jai::)(':')(181,182) + JaiRefExprImpl(REF_EXPR)(183,186) + PsiElement(Jai:IDENT)('int')(183,186) + PsiElement(Jai:;)(';')(186,187) + JaiStatementImpl(STATEMENT)(188,197) + JaiDeclarationImpl(DECLARATION)(188,197) + JaiDeclNamesImpl(DECL_NAMES)(188,189) + JaiDeclNameImpl(DECL_NAME)(188,189) + PsiElement(Jai:IDENT)('b')(188,189) + PsiElement(Jai::)(':')(189,190) + JaiRefExprImpl(REF_EXPR)(191,196) + PsiElement(Jai:IDENT)('float')(191,196) + PsiElement(Jai:;)(';')(196,197) + PsiElement(Jai:})('}')(198,199) + JaiStatementImpl(STATEMENT)(200,216) + JaiDeclarationImpl(DECLARATION)(200,216) + JaiDeclNamesImpl(DECL_NAMES)(200,205) + JaiDeclNameImpl(DECL_NAME)(200,205) + PsiElement(Jai:IDENT)('Phone')(200,205) + PsiElement(Jai:::)('::')(206,208) + JaiInitializerImpl(INITIALIZER)(209,215) + JaiArrayTypeExprImpl(ARRAY_TYPE_EXPR)(209,215) + PsiElement(Jai:[)('[')(209,210) + JaiLiteralExprImpl(LITERAL_EXPR)(210,211) + PsiElement(Jai:NUMBER)('9')(210,211) + PsiElement(Jai:])(']')(211,212) + JaiRefExprImpl(REF_EXPR)(213,215) + PsiElement(Jai:IDENT)('u8')(213,215) + PsiElement(Jai:;)(';')(215,216) + JaiStatementImpl(STATEMENT)(217,232) + JaiDeclarationImpl(DECLARATION)(217,232) + JaiDeclNamesImpl(DECL_NAMES)(217,221) + JaiDeclNameImpl(DECL_NAME)(217,221) + PsiElement(Jai:IDENT)('view')(217,221) + PsiElement(Jai::)(':')(221,222) + JaiArrayTypeExprImpl(ARRAY_TYPE_EXPR)(223,231) + PsiElement(Jai:[)('[')(223,224) + PsiElement(Jai:])(']')(224,225) + JaiRefExprImpl(REF_EXPR)(226,231) + PsiElement(Jai:IDENT)('float')(226,231) + PsiElement(Jai:;)(';')(231,232) + JaiStatementImpl(STATEMENT)(233,251) + JaiDeclarationImpl(DECLARATION)(233,251) + JaiDeclNamesImpl(DECL_NAMES)(233,240) + JaiDeclNameImpl(DECL_NAME)(233,240) + PsiElement(Jai:IDENT)('dynamic')(233,240) + PsiElement(Jai::)(':')(240,241) + JaiArrayTypeExprImpl(ARRAY_TYPE_EXPR)(242,250) + PsiElement(Jai:[)('[')(242,243) + PsiElement(Jai:..)('..')(243,245) + PsiElement(Jai:])(']')(245,246) + JaiRefExprImpl(REF_EXPR)(247,250) + PsiElement(Jai:IDENT)('int')(247,250) + PsiElement(Jai:;)(';')(250,251) + JaiStatementImpl(STATEMENT)(252,269) + JaiDeclarationImpl(DECLARATION)(252,269) + JaiDeclNamesImpl(DECL_NAMES)(252,259) + JaiDeclNameImpl(DECL_NAME)(252,259) + PsiElement(Jai:IDENT)('pointer')(252,259) + PsiElement(Jai::)(':')(259,260) + JaiPrefixExprImpl(PREFIX_EXPR)(261,268) + PsiElement(Jai:*)('*')(261,262) + JaiRefExprImpl(REF_EXPR)(262,268) + PsiElement(Jai:IDENT)('Person')(262,268) + PsiElement(Jai:;)(';')(268,269) \ No newline at end of file