Tier 2 golden trees, and #scope_file is a statement not a modifier

isDeclarationAhead used to skip *any* directive, so '#scope_file' was absorbed as
a modifier of the declaration after it. That misreports scope, since a scope
directive governs everything that follows it. Only #as, #overlay, #add_context
and #no_reset actually prefix a declaration in the corpus; the rest are
statements now, which the regenerated Directives.txt shows.

Golden fixtures cover the reference doc's gotcha list: declaration forms,
procedures (named/multiple/variadic/polymorphic/foreign returns), structs, enums,
unions, array and pointer types, the 'if x == { case }' switch form, for
modifiers, ifx, and directives including a here-string.

DebugParseTest is now inert by default and documented as the scratch loop.

generateParser wipes its output through a Delete task rather than a doFirst,
because a lambda added from a Kotlin build script captures the script object and
breaks the configuration cache ('./jaigradle check' failed to store it).

check and verifyPlugin (IU-253/261/262) both green.
This commit is contained in:
hgranthorner
2026-08-04 12:48:30 -04:00
parent 47a2c5805e
commit e3ff13f9f3
20 changed files with 1050 additions and 221 deletions

View File

@@ -8,9 +8,11 @@ plugins {
} }
// Grammar-Kit output. Committed so diffs are reviewable, never hand-edited. // Grammar-Kit output. Committed so diffs are reviewable, never hand-edited.
val generatedSourceDir = file("src/main/gen")
sourceSets { sourceSets {
main { 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 { tasks.generateParser {
dependsOn(cleanGeneratedSources)
sourceFile.set(file("src/main/grammar/Jai.bnf")) 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") pathToParser.set("dev/hgh/jai/parser/JaiParser.java")
pathToPsiRoot.set("dev/hgh/jai/psi") pathToPsiRoot.set("dev/hgh/jai/psi")
purgeOldFiles.set(true) 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 // Without this the compile tasks read src/main/gen with no ordering guarantee, so an

View File

@@ -2509,7 +2509,8 @@ public class JaiParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// <<isReturnGroupAhead>> returnGroup | returnItem (',' returnItem)* // <<isReturnGroupAhead>> returnGroup
// | returnItem (',' <<notPolyParamAhead>> returnItem)*
static boolean returnTypes_(PsiBuilder builder_, int level_) { static boolean returnTypes_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnTypes_")) return false; if (!recursion_guard_(builder_, level_, "returnTypes_")) return false;
boolean result_; boolean result_;
@@ -2531,7 +2532,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_; return result_;
} }
// returnItem (',' returnItem)* // returnItem (',' <<notPolyParamAhead>> returnItem)*
private static boolean returnTypes__1(PsiBuilder builder_, int level_) { private static boolean returnTypes__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnTypes__1")) return false; if (!recursion_guard_(builder_, level_, "returnTypes__1")) return false;
boolean result_; boolean result_;
@@ -2542,7 +2543,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_; return result_;
} }
// (',' returnItem)* // (',' <<notPolyParamAhead>> returnItem)*
private static boolean returnTypes__1_1(PsiBuilder builder_, int level_) { private static boolean returnTypes__1_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnTypes__1_1")) return false; if (!recursion_guard_(builder_, level_, "returnTypes__1_1")) return false;
while (true) { while (true) {
@@ -2553,12 +2554,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true; return true;
} }
// ',' returnItem // ',' <<notPolyParamAhead>> returnItem
private static boolean returnTypes__1_1_0(PsiBuilder builder_, int level_) { private static boolean returnTypes__1_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnTypes__1_1_0")) return false; if (!recursion_guard_(builder_, level_, "returnTypes__1_1_0")) return false;
boolean result_; boolean result_;
Marker marker_ = enter_section_(builder_); Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA); result_ = consumeToken(builder_, COMMA);
result_ = result_ && notPolyParamAhead(builder_, level_ + 1);
result_ = result_ && returnItem(builder_, level_ + 1); result_ = result_ && returnItem(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_); exit_section_(builder_, marker_, null, result_);
return result_; return result_;
@@ -3222,65 +3224,61 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_; return result_;
} }
// 'cast' directiveFlag_* '(' [expr (',' expr)*] ')' [expr] // 'cast' directiveFlag_* '(' expr ',' expr (',' expr)* ')'
// | 'cast' directiveFlag_* '(' [expr] ')' expr
public static boolean castExpr(PsiBuilder builder_, int level_) { public static boolean castExpr(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr")) return false; if (!recursion_guard_(builder_, level_, "castExpr")) return false;
if (!nextTokenIsSmart(builder_, KW_CAST)) return false; if (!nextTokenIsSmart(builder_, KW_CAST)) return false;
boolean result_; boolean result_;
Marker marker_ = enter_section_(builder_); Marker marker_ = enter_section_(builder_);
result_ = consumeTokenSmart(builder_, KW_CAST); result_ = castExpr_0(builder_, level_ + 1);
result_ = result_ && castExpr_1(builder_, level_ + 1); if (!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);
exit_section_(builder_, marker_, CAST_EXPR, result_); exit_section_(builder_, marker_, CAST_EXPR, result_);
return result_; return result_;
} }
// directiveFlag_* // 'cast' directiveFlag_* '(' expr ',' expr (',' expr)* ')'
private static boolean castExpr_1(PsiBuilder builder_, int level_) { private static boolean castExpr_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_1")) return false; if (!recursion_guard_(builder_, level_, "castExpr_0")) 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;
boolean result_; boolean result_;
Marker marker_ = enter_section_(builder_); Marker marker_ = enter_section_(builder_);
result_ = expr(builder_, level_ + 1, -1); result_ = consumeTokenSmart(builder_, KW_CAST);
result_ = result_ && castExpr_3_0_1(builder_, level_ + 1); 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_); exit_section_(builder_, marker_, null, result_);
return result_; return result_;
} }
// (',' expr)* // directiveFlag_*
private static boolean castExpr_3_0_1(PsiBuilder builder_, int level_) { private static boolean castExpr_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_3_0_1")) return false; if (!recursion_guard_(builder_, level_, "castExpr_0_1")) return false;
while (true) { while (true) {
int pos_ = current_position_(builder_); int pos_ = current_position_(builder_);
if (!castExpr_3_0_1_0(builder_, level_ + 1)) break; if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "castExpr_3_0_1", pos_)) 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; return true;
} }
// ',' expr // ',' expr
private static boolean castExpr_3_0_1_0(PsiBuilder builder_, int level_) { private static boolean castExpr_0_6_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_3_0_1_0")) return false; if (!recursion_guard_(builder_, level_, "castExpr_0_6_0")) return false;
boolean result_; boolean result_;
Marker marker_ = enter_section_(builder_); Marker marker_ = enter_section_(builder_);
result_ = consumeTokenSmart(builder_, COMMA); result_ = consumeTokenSmart(builder_, COMMA);
@@ -3289,9 +3287,35 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_; 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] // [expr]
private static boolean castExpr_5(PsiBuilder builder_, int level_) { private static boolean castExpr_1_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_5")) return false; if (!recursion_guard_(builder_, level_, "castExpr_1_3")) return false;
expr(builder_, level_ + 1, -1); expr(builder_, level_ + 1, -1);
return true; return true;
} }

View File

@@ -305,7 +305,8 @@ arrayTypeExpr ::= '[' ['..' | expr] ']' expr
// (modules/Shared_Memory_Channel/module.jai:113). // (modules/Shared_Memory_Channel/module.jai:113).
derefCastExpr ::= '(' '.*' ')' expr derefCastExpr ::= '(' '.*' ')' expr
castExpr ::= 'cast' directiveFlag_* '(' [expr (',' expr)*] ')' [expr] castExpr ::= 'cast' directiveFlag_* '(' expr ',' expr (',' expr)* ')'
| 'cast' directiveFlag_* '(' [expr] ')' expr
autoCastExpr ::= 'xx' [',' IDENT] expr autoCastExpr ::= 'xx' [',' IDENT] expr
inlineExpr ::= ('inline' | 'no_inline') expr inlineExpr ::= ('inline' | 'no_inline') expr
ifxExpr ::= ifxKeyword_ expr ['then'] [ifxBranch_] ['else' ifxBranch_] ifxExpr ::= ifxKeyword_ expr ['then'] [ifxBranch_] ['else' ifxBranch_]
@@ -385,7 +386,8 @@ private paramTypeTail_ ::= ':' [<<exprNoAssign>>] ['=' initializer]
| ':=' initializer | ':=' initializer
| '::' initializer | '::' initializer
private returnTypes_ ::= <<isReturnGroupAhead>> returnGroup | returnItem (',' returnItem)* private returnTypes_ ::= <<isReturnGroupAhead>> returnGroup
| returnItem (',' <<notPolyParamAhead>> returnItem)*
returnGroup ::= '(' [returnItem (',' returnItem)*] ')' returnGroup ::= '(' [returnItem (',' returnItem)*] ')'
returnItem ::= <<isParamNameAhead>> IDENT (':' [<<exprNoAssign>>] ['=' returnDefault_] | ':=' returnDefault_) returnItem ::= <<isParamNameAhead>> IDENT (':' [<<exprNoAssign>>] ['=' returnDefault_] | ':=' returnDefault_)
| <<exprNoAssign>> | <<exprNoAssign>>

View File

@@ -91,6 +91,17 @@ object JaiParserUtil : GeneratedParserUtilBase() {
"this", "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 // ---------------------------------------------------------------- directives
/** /**
@@ -343,7 +354,13 @@ object JaiParserUtil : GeneratedParserUtilBase() {
var inPrefix = false var inPrefix = false
loop@ while (true) { loop@ while (true) {
when (b.lookAhead(i)) { when (b.lookAhead(i)) {
T.DIRECTIVE, T.KW_USING -> { T.DIRECTIVE -> {
if (!isDeclarationDirective(b, i)) break@loop
i++
inPrefix = true
}
T.KW_USING -> {
i++ i++
inPrefix = true 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. * Index just past the closer matching the bracket at [start], or -1 if unbalanced.
* Covers `(…)`, `[…]`, `.[…]` and `.{…}`, which all appear in declaration * 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. */ /** `IDENT ':'` — a loop label. */
@JvmStatic @JvmStatic
fun isLabelAhead( fun isLabelAhead(

View File

@@ -1,7 +1,6 @@
package dev.hgh.jai.parser package dev.hgh.jai.parser
import com.intellij.psi.PsiErrorElement import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiFileFactory
import com.intellij.psi.PsiRecursiveElementWalkingVisitor import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import com.intellij.testFramework.fixtures.BasePlatformTestCase import com.intellij.testFramework.fixtures.BasePlatformTestCase
@@ -9,70 +8,77 @@ import dev.hgh.jai.JaiLanguage
import java.io.File import java.io.File
/** /**
* Scratch harness for grammar work. Not a gate — the gate is [JaiCorpusParserTest]. * Scratch harness for grammar work. **Not a gate** — the gate is [JaiCorpusParserTest].
* Edit [snippets] and [corpusFiles] freely while iterating on `Jai.bnf`. *
* 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() { class DebugParseTest : BasePlatformTestCase() {
private val snippets = /** Jai source snippets to parse. */
listOf( private val snippets = emptyList<String>()
"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",
)
/** Corpus files to dump the first error of. */ /** Paths under `~/.local/jai` to parse. */
private val corpusFiles = private val corpusFiles = emptyList<String>()
listOf(
"modules/GetRect/widgets/color_picker.jai", fun testSnippets() {
"modules/GetRect/widgets/slidable_region.jai", val factory = PsiFileFactory.getInstance(project)
"how_to/094_array_operators.jai", for (text in snippets) {
"how_to/044_using_advanced/main.jai", val file = factory.createFileFromText("scratch.jai", JaiLanguage, text)
"how_to/630_compiler_get_nodes.jai", val error = errorsIn(file).firstOrNull()
"modules/Bucket_Array.jai", val label = text.replace("\n", "\\n")
"modules/Android/Toolchain/adb.jai", if (error == null) {
"modules/Hash_Table.jai", 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() { fun testCorpusFiles() {
val root = File(System.getProperty("user.home"), ".local/jai") val root = File(System.getProperty("user.home"), ".local/jai")
if (!root.exists()) return if (!root.exists()) return
for (relative in corpusFiles) { for (relative in corpusFiles) {
val file = File(root, relative) val file = File(root, relative)
if (file.exists()) dumpFile(file) else println("missing: $relative") if (!file.exists()) {
} println("missing: $relative")
} continue
}
fun testSnippets() { val text = file.readText()
val factory = PsiFileFactory.getInstance(project) val psi = PsiFileFactory.getInstance(project).createFileFromText(file.name, JaiLanguage, text)
var failures = 0 val errors = errorsIn(psi)
for (text in snippets) { if (errors.isEmpty()) {
val file = factory.createFileFromText("t.jai", JaiLanguage, text) println("$relative: clean")
val error = firstError(file) continue
if (error == null) { }
println("ok ${text.replace("\n", "\\n")}") println("$relative: ${errors.size} error(s)")
if (System.getProperty("jai.debug.tree") != null) { for (error in errors.take(REPORTED_ERRORS)) {
println(com.intellij.psi.impl.DebugUtil.psiToString(file, true, false)) val line = text.substring(0, error.textOffset).count { it == '\n' } + 1
} println(" :$line ${error.errorDescription}")
} else { println(" at '${around(text, error.textOffset)}'")
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))
}
} }
} }
println("$failures/${snippets.size} snippets failed")
} }
private fun dumpFile(file: File) { private fun around(
val text = file.readText() text: String,
val psi = PsiFileFactory.getInstance(project).createFileFromText(file.name, JaiLanguage, text) offset: Int,
): String = text.substring(offset).take(SNIPPET_WIDTH).replace("\n", "\\n")
private fun errorsIn(file: com.intellij.psi.PsiFile): List<PsiErrorElement> {
val errors = mutableListOf<PsiErrorElement>() val errors = mutableListOf<PsiErrorElement>()
psi.accept( file.accept(
object : PsiRecursiveElementWalkingVisitor() { object : PsiRecursiveElementWalkingVisitor() {
override fun visitErrorElement(element: PsiErrorElement) { override fun visitErrorElement(element: PsiErrorElement) {
errors.add(element) errors.add(element)
@@ -80,28 +86,11 @@ class DebugParseTest : BasePlatformTestCase() {
} }
}, },
) )
if (errors.isEmpty()) { return errors
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")}'")
}
} }
private fun firstError(file: PsiFile): PsiErrorElement? { private companion object {
var first: PsiErrorElement? = null const val REPORTED_ERRORS = 6
file.accept( const val SNIPPET_WIDTH = 70
object : PsiRecursiveElementWalkingVisitor() {
override fun visitErrorElement(element: PsiErrorElement) {
if (first == null) first = element
super.visitErrorElement(element)
}
},
)
return first
} }
} }

View File

@@ -1,11 +1,24 @@
package dev.hgh.jai.parser 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() { class JaiParserGoldenTest : JaiParsingTestCase() {
fun testSimpleDeclarations() { fun testDeclarations() = doTest(true)
doTest(true)
}
fun testExpressions() { fun testProcedures() = doTest(true)
doTest(true)
} fun testTypes() = doTest(true)
fun testControlFlow() = doTest(true)
fun testDirectives() = doTest(true)
} }

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)

View File

@@ -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";

View File

@@ -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)

View File

@@ -1,2 +0,0 @@
x = a + b * c;
foo(x, y + 1);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)

View File

@@ -1,4 +0,0 @@
a : float = 37.0;
b := 10;
c :: 42;
return a + b;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)