/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * This source file is part of the Cangjie project, licensed under Apache-2.0
 * with Runtime Library Exception.
 *
 * See https://cangjie-lang.cn/pages/LICENSE for license information.
 */

package stdx.syntax

import std.collection.{ArrayList, ArrayStack, HashSet, HashMap}

// Expr/Decl on each line is indented with four spaces after format
let FORMAT_INDENTATION = 4

class SyntaxNodeImplCreator {
    private init() {
    }

    static unsafe func checkIdentifier(identifier: String, paramName: String, nodeName: String, useContext!: Bool = true): Unit {
        var textPtr: CString = CString(CPointer<UInt8>())
        try {
            textPtr = LibC.mallocCString(identifier)
            if (textPtr.isNull()) {
                throw Exception("malloc failed")
            }
            let checkRes = unsafe { CJ_CheckIdentifier(textPtr, useContext) }
            if (!checkRes) {
                throw Exception("InitException: Invalid input '${paramName}' for '${nodeName}' init.")
            }
        } finally {
            if (!textPtr.isNull()) {
                unsafe { LibC.free(textPtr) }
            }
        }
    }

    static func createCommentGroup(comments: Array<Comment>) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        for (i in 0..comments.size) {
            ret.add(comments[i].nodeImpl)
            if (i < comments.size - 1) {
                ret.add(builder.buildNewline(1))
            }
        }

        builder.buildNonTerminal(SyntaxNodeKind.CommentGroup, ret.toArray())
    }

    static func createCommentGroupList(comments: Array<Comment>) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        ret.add(createCommentGroup(comments))

        builder.buildNonTerminal(SyntaxNodeKind.CommentGroupList, ret.toArray())
    }

    static func addCommentToNode(ret: ArrayList<SyntaxNodeImpl>, comments: Array<Comment>) {
        let builder = SyntaxNodeBuilder()
        if (comments.size > 0) {
            // the CommentGroupList is placed to the beginning of the Node
            ret.add(createCommentGroupList(comments))
            ret.add(builder.buildNewline(1))
        }
    }

    static func createAnnotationList(annotations: Array<Annotation>) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        for (i in 0..annotations.size) {
            ret.add(annotations[i].nodeImpl)
            if (i < annotations.size - 1) {
                ret.add(builder.buildNewline(1))
            }
        }

        builder.buildNonTerminal(SyntaxNodeKind.AnnotationList, ret.toArray())
    }

    static func createModifierList(modifiers: Array<Modifier>, hasForeign!: Bool = false) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        if (hasForeign) {
            let modifierRet = ArrayList<SyntaxNodeImpl>()
            modifierRet.add(builder.buildBasicTerminal(SyntaxNodeKind.ForeignToken))
            ret.add(builder.buildNonTerminal(SyntaxNodeKind.Modifier, modifierRet.toArray()))

            if (modifiers.size > 0) {
                ret.add(builder.buildSpace(1))
            }
        }

        for (i in 0..modifiers.size) {
            ret.add(modifiers[i].nodeImpl)
            if (i < modifiers.size - 1) {
                ret.add(builder.buildSpace(1))
            }
        }

        builder.buildNonTerminal(SyntaxNodeKind.ModifierList, ret.toArray())
    }

    private static func createDeclLikePrefix(annotations: Array<Annotation>, modifiers: Array<Modifier>,
        comments: Array<Comment>) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
            ret.add(builder.buildNewline(1))
        }

        if (modifiers.size != 0) {
            ret.add(createModifierList(modifiers))
            ret.add(builder.buildSpace(1))
        }

        return (builder, ret)
    }

    private static func addNamedGenericDeclHead(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>,
        name: String, genericParams: Array<GenericParam>) {
        ret.add(builder.buildSpace(1))
        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))

        if (genericParams.size > 0) {
            ret.add(createTyepArguments(genericParams))
        }
    }

    private static func addSuperTyAnnotations(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>,
        superTyAnnotations: Array<TypeAnnotation>) {
        if (superTyAnnotations.size > 0) {
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.UpperBoundToken))
            ret.add(builder.buildSpace(1))
            for (i in 0..superTyAnnotations.size) {
                ret.add(superTyAnnotations[i].nodeImpl)
                if (i < superTyAnnotations.size - 1) {
                    ret.add(builder.buildSpace(1))
                    ret.add(builder.buildBasicTerminal(SyntaxNodeKind.BitAndToken))
                    ret.add(builder.buildSpace(1))
                }
            }
        }
    }

    private static func addGenericConstraints(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>,
        genericConstraints: Option<GenericConstraints>) {
        if (let Some(constraints) <- genericConstraints) {
            ret.add(builder.buildSpace(1))
            ret.add(constraints.nodeImpl)
        }
    }

    private static func addDeclBody(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>, body: Body) {
        ret.add(builder.buildSpace(1))
        ret.add(body.nodeImpl)
    }

    private static func addDelimitedTokenList(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>, tks: Tokens,
        leftToken: SyntaxNodeKind, rightToken: SyntaxNodeKind) {
        ret.add(builder.buildBasicTerminal(leftToken))
        var tokBytes: CPointer<UInt8> = unsafePointerCastFromUint8Array((tks).toBytes())
        var spaceFlag: CPointer<Bool> = unsafe { LibC.malloc<Bool>(count: tks.size) }
        if (spaceFlag.isNull()) {
            unsafe { LibC.free(tokBytes) }
            throw IllegalMemoryException("malloc failed!")
        }
        unsafe { CJ_CheckAddSpaces(tokBytes, spaceFlag) }
        let attrArray = unsafe { tokensToImplArray(tks, tokBytes, spaceFlag) }
        ret.add(builder.buildNonTerminal(SyntaxNodeKind.TokenList, attrArray))
        ret.add(builder.buildBasicTerminal(rightToken))
    }

    private static func addMacroExpandAnnotations(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>,
        comments: Array<Comment>, annotations: Array<Annotation>) {
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
            ret.add(builder.buildNewline(1))
        }
    }

    private static func addMacroCalleeAndAttrs(builder: SyntaxNodeBuilder, ret: ArrayList<SyntaxNodeImpl>,
        calleeMacro: Expr, macroAttrs: Tokens) {
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.AtToken))
        ret.add(calleeMacro.nodeImpl)

        if (macroAttrs.size != 0) {
            addDelimitedTokenList(builder, ret, macroAttrs, SyntaxNodeKind.LSquareToken, SyntaxNodeKind.RSquareToken)
        }
    }

    static func createAnnotationImpl(
        arguments: Array<Argument>,
        identifier: String,
        opKind: AtOpKind,
        comments!: Array<Comment> = []
    ) {
        unsafe { checkIdentifier(identifier, "identifier", "Annotation") }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        match (opKind) {
            case AtOpKind.At => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.AtToken))
            case AtOpKind.AtExcl => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.AtExclToken))
            case _ => throw Exception("InitException: Invalid input 'opKind' for 'Annotation' init.")
        }
        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, identifier))
        if (arguments.size > 0) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LSquareToken))
            for (i in 0..arguments.size) {
                ret.add(arguments[i].nodeImpl)
                if (i < arguments.size - 1) {
                    ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    ret.add(builder.buildSpace(1))
                }
            }
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RSquareToken))
        }

        builder.buildNonTerminal(SyntaxNodeKind.Annotation, ret.toArray())
    }

    static func createArgumentImpl(identifier: Option<String>, isInOut: Bool, value: Expr,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)
        if (let Some(name) <- identifier) {
            unsafe { checkIdentifier(name, "identifier", "Argument") }
            ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            ret.add(builder.buildSpace(1))
        }

        if (isInOut) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.InoutToken))
            ret.add(builder.buildSpace(1))
        }
        ret.add(value.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.Argument, ret.toArray())
    }

    static func createBlockImpl(nodes: Array<SyntaxTreeNode>, comments!: Array<Comment> = []) {
        for (node in nodes) {
            if (node.nodeImpl.kind != SyntaxNodeKind.VarDecl && node.nodeImpl.kind != SyntaxNodeKind.FuncDecl &&
                !node.nodeImpl.kind.isExpr()) {
                throw Exception("InitException: Invalid input 'nodes' for 'Block' init.")
            }
        }

        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        ret.add(builder.buildNewline(1))
        for (i in 0..nodes.size) {
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(nodes[i].nodeImpl)
            ret.add(builder.buildNewline(1))
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.Block, ret.toArray())
    }

    static func createBodyImpl(memberDecls: Array<Decl>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        ret.add(builder.buildNewline(1))
        for (i in 0..memberDecls.size) {
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(memberDecls[i].nodeImpl)
            ret.add(builder.buildNewline(1))
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.Body, ret.toArray())
    }

    static func createGenericConstraintImpl(typeArgument: TypeAnnotation, upperTypes: Array<TypeAnnotation>,
        comments!: Array<Comment> = []) {
        if (upperTypes.isEmpty()) {
            throw Exception("InitException: The input 'upperTypes' cannot be empty for 'GenericConstraint' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(typeArgument.nodeImpl)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.UpperBoundToken))
        for (i in 0..upperTypes.size) {
            ret.add(upperTypes[i].nodeImpl)
            if (i < upperTypes.size - 1) {
                ret.add(builder.buildSpace(1))
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.BitAndToken))
                ret.add(builder.buildSpace(1))
            }
        }

        builder.buildNonTerminal(SyntaxNodeKind.GenericConstraint, ret.toArray())
    }

    static func createGenericConstraintsImpl(constraints: Array<GenericConstraint>, comments!: Array<Comment> = []) {
        if (constraints.isEmpty()) {
            throw Exception("InitException: The input 'Constraints' cannot be empty for 'GenericConstraints' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.WhereToken))
        ret.add(builder.buildSpace(1))
        for (i in 0..constraints.size) {
            ret.add(constraints[i].nodeImpl)
            if (i < constraints.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }

        builder.buildNonTerminal(SyntaxNodeKind.GenericConstraints, ret.toArray())
    }

    static func createModifierImpl(kind: ModifierKind, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        let modiToken = match (kind) {
            case ModifierKind.Abstract => SyntaxNodeKind.AbstractToken
            case ModifierKind.Internal => SyntaxNodeKind.InternalToken
            case ModifierKind.Mut => SyntaxNodeKind.MutToken
            case ModifierKind.Open => SyntaxNodeKind.OpenToken
            case ModifierKind.Operator => SyntaxNodeKind.OperatorToken
            case ModifierKind.Override => SyntaxNodeKind.OverrideToken
            case ModifierKind.Private => SyntaxNodeKind.PrivateToken
            case ModifierKind.Protected => SyntaxNodeKind.ProtectedToken
            case ModifierKind.Public => SyntaxNodeKind.PublicToken
            case ModifierKind.Redef => SyntaxNodeKind.RedefToken
            case ModifierKind.Sealed => SyntaxNodeKind.SealedToken
            case ModifierKind.Static => SyntaxNodeKind.StaticToken
            case ModifierKind.Unsafe => SyntaxNodeKind.UnsafeToken
            case ModifierKind.Const => SyntaxNodeKind.ConstToken
            case _ => throw Exception("InitException: Invalid input 'kind' for 'Modifier' init.")
        }

        ret.add(builder.buildBasicTerminal(modiToken))
        builder.buildNonTerminal(SyntaxNodeKind.Modifier, ret.toArray())
    }

    // Decl
    static func checkGenericParamAndGenericConstraints(genericConstraints: Option<GenericConstraints>,
        genericParams: Array<GenericParam>) {
        if (genericParams.isEmpty() && let Some(_) <- genericConstraints) {
            throw Exception(
                "InitException: The input 'genericConstraints' must be None when input 'genericParams' are empty.")
        }
        let paramSet = HashSet<String>()
        for (param in genericParams) {
            paramSet.add(param.name)
        }
        if (let Some(constraints) <- genericConstraints) {
            for (constraint in constraints.constraints) {
                if (!paramSet.contains(constraint.typeArgument.toString())) {
                    throw Exception("InitException: The input 'genericConstraints' mismatch with input 'genericParams'")
                }
            }
        }
    }

    static func createTyepArguments(genericParams: Array<GenericParam>) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LtToken))
        for (i in 0..genericParams.size) {
            ret.add(genericParams[i].nodeImpl)
            if (i < genericParams.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.GtToken))

        builder.buildNonTerminal(SyntaxNodeKind.TypeArguments, ret.toArray())
    }

    static func checkClassOrStructDeclBody(body: Body, declType: String) {
        for (decl in body.memberDecls) {
            if (decl.nodeImpl.kind != SyntaxNodeKind.FuncDecl && decl.nodeImpl.kind != SyntaxNodeKind.VarDecl &&
                decl.nodeImpl.kind != SyntaxNodeKind.StaticInit && decl.nodeImpl.kind != SyntaxNodeKind.MacroExpandDecl &&
                decl.nodeImpl.kind != SyntaxNodeKind.PropDecl) {
                throw Exception("InitException: Invalid input 'body.memberDecls' for '${declType}' init.")
            }
        }
    }

    static func createClassDeclImpl(body: Body, genericConstraints: Option<GenericConstraints>,
        genericParams: Array<GenericParam>, name: String, superTyAnnotations: Array<TypeAnnotation>,
        annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = []) {
        checkGenericParamAndGenericConstraints(genericConstraints, genericParams)
        checkClassOrStructDeclBody(body, "ClassDecl")
        unsafe { checkIdentifier(name, "name", "ClassDecl") }
        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ClassToken))
        addNamedGenericDeclHead(builder, ret, name, genericParams)

        addSuperTyAnnotations(builder, ret, superTyAnnotations)

        addGenericConstraints(builder, ret, genericConstraints)

        addDeclBody(builder, ret, body)

        builder.buildNonTerminal(SyntaxNodeKind.ClassDecl, ret.toArray())
    }

    static func hasModifier(modifiers: Array<Modifier>, modiKind: ModifierKind) {
        for (modifier in modifiers) {
            if (modifier.kind == modiKind) {
                return true
            }
        }
        false
    }

    static func createFuncDeclImpl(body: Option<Block>, genericConstraints: Option<GenericConstraints>,
        genericParams: Array<GenericParam>, kind: FuncKind, name: String, params: ParameterList,
        retTyAnnotation: Option<TypeAnnotation>, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = []) {
        checkGenericParamAndGenericConstraints(genericConstraints, genericParams)
        match (kind) {
            case FuncKind.Foreign | FuncKind.Normal | FuncKind.PrimaryConstructor => unsafe { checkIdentifier(name,
                "name", "FuncDecl") }
            case _ => ()
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
            ret.add(builder.buildNewline(1))
        }

        match (kind) {
            case FuncKind.Foreign =>
                ret.add(createModifierList(modifiers, hasForeign: true))
                ret.add(builder.buildSpace(1))
            case _ =>
                if (modifiers.size != 0) {
                    ret.add(createModifierList(modifiers))
                    ret.add(builder.buildSpace(1))
                }
        }

        match (kind) {
            case FuncKind.Constructor =>
                if (hasModifier(modifiers, ModifierKind.Operator)) {
                    throw Exception("InitException: The input 'kind' not correspond to input 'modifiers'.")
                }
                if (genericParams.size > 0 || !retTyAnnotation.isNone() || !genericConstraints.isNone()) {
                    throw Exception(
                        "InitException: The input 'genericParams', 'retTyAnnotation' and 'genericConstraints' are not allowed for 'FuncDecl.Constructor' init.")
                }
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.InitToken))
            case FuncKind.Foreign =>
                if (hasModifier(modifiers, ModifierKind.Operator)) {
                    throw Exception("InitException: The input 'kind' not correspond to input 'modifiers'.")
                }
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.FuncToken))
                ret.add(builder.buildSpace(1))
                ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
            case FuncKind.Normal =>
                if (hasModifier(modifiers, ModifierKind.Operator)) {
                    throw Exception("InitException: The input 'kind' not correspond to input 'modifiers'.")
                }
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.FuncToken))
                ret.add(builder.buildSpace(1))
                ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
            case FuncKind.Operator =>
                if (!hasModifier(modifiers, ModifierKind.Operator)) {
                    throw Exception("InitException: The input 'kind' not correspond to input 'modifiers'.")
                }
                if (!genericConstraints.isNone() || !genericParams.isEmpty()) {
                    throw Exception(
                        "InitException: The input 'genericParams' and 'genericConstraints' are not allowed for 'FuncDecl.Operator' init.")
                }
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.FuncToken))
                ret.add(builder.buildSpace(1))
                ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
            case FuncKind.PrimaryConstructor =>
                if (hasModifier(modifiers, ModifierKind.Operator)) {
                    throw Exception("InitException: The input 'kind' not correspond to input 'modifiers'.")
                }
                if (genericParams.size > 0 || !retTyAnnotation.isNone() || !genericConstraints.isNone()) {
                    throw Exception(
                        "The input 'genericParams', 'retTyAnnotation' and 'genericConstraints' are not allowed for 'FuncDecl.PrimaryConstructor' init.")
                }
                ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
            case FuncKind.Finalizer =>
                if (!annotations.isEmpty() || !modifiers.isEmpty() || !genericConstraints.isNone() ||
                    !genericParams.isEmpty() || !retTyAnnotation.isNone() || !params.params.isEmpty()) {
                    throw Exception(
                        "InitException: The input 'annotations', 'modifiers', 'genericConstraints', 'genericParams' and 'retTyAnnotation' are not allowed for 'FuncDecl.Finalizer' init.")
                }
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.BitNotToken))
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.InitToken))
            case _ => throw Exception("InitException: Invalid input 'kind' for 'FuncDecl' init.")
        }

        if (genericParams.size > 0) {
            ret.add(createTyepArguments(genericParams))
        }

        ret.add(params.nodeImpl)

        if (let Some(typeAnno) <- retTyAnnotation) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            ret.add(builder.buildSpace(1))
            ret.add(typeAnno.nodeImpl)
        }

        if (let Some(constraints) <- genericConstraints) {
            ret.add(builder.buildSpace(1))
            ret.add(constraints.nodeImpl)
        }

        if (let Some(bd) <- body) {
            ret.add(builder.buildSpace(1))
            ret.add(bd.nodeImpl)
        }

        builder.buildNonTerminal(SyntaxNodeKind.FuncDecl, ret.toArray())
    }

    static func createStructDeclImpl(body: Body, genericConstraints: Option<GenericConstraints>,
        genericParams: Array<GenericParam>, name: String, superTyAnnotations: Array<TypeAnnotation>,
        annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = []) {
        checkGenericParamAndGenericConstraints(genericConstraints, genericParams)
        checkClassOrStructDeclBody(body, "StructDecl")
        unsafe { checkIdentifier(name, "name", "StructDecl") }
        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.StructToken))
        addNamedGenericDeclHead(builder, ret, name, genericParams)

        addSuperTyAnnotations(builder, ret, superTyAnnotations)

        addGenericConstraints(builder, ret, genericConstraints)

        addDeclBody(builder, ret, body)

        builder.buildNonTerminal(SyntaxNodeKind.StructDecl, ret.toArray())
    }

    static func createInterfaceDeclImpl(body: Body, genericConstraints: Option<GenericConstraints>,
        genericParams: Array<GenericParam>, name: String, superTyAnnotations: Array<TypeAnnotation>,
        annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [], comments!: Array<Comment> = []) {
        checkGenericParamAndGenericConstraints(genericConstraints, genericParams)
        unsafe { checkIdentifier(name, "name", "InterfaceDecl") }
        for (decl in body.memberDecls) {
            if (decl.nodeImpl.kind != SyntaxNodeKind.FuncDecl && decl.nodeImpl.kind != SyntaxNodeKind.MacroExpandDecl) {
                throw Exception("InitException: Invalid input 'body.memberDecls' for 'InterfaceDecl' init.")
            }
        }

        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.InterfaceToken))
        addNamedGenericDeclHead(builder, ret, name, genericParams)

        addSuperTyAnnotations(builder, ret, superTyAnnotations)

        addGenericConstraints(builder, ret, genericConstraints)

        addDeclBody(builder, ret, body)

        builder.buildNonTerminal(SyntaxNodeKind.InterfaceDecl, ret.toArray())
    }

    static func createEnumBody(body: Body, constructors: Array<EnumConstructor>, isNonExhaustive: Bool) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        for (constructor in constructors) {
            ret.add(builder.buildNewline(1))
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.BitOrToken))
            ret.add(builder.buildSpace(1))
            ret.add(constructor.nodeImpl)
        }
        if (isNonExhaustive) {
            ret.add(builder.buildNewline(1))
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.BitOrToken))
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.EllipsisToken))
        }
        for (decl in body.memberDecls) {
            if (decl.nodeImpl.kind != SyntaxNodeKind.FuncDecl && decl.nodeImpl.kind != SyntaxNodeKind.PropDecl &&
                decl.nodeImpl.kind != SyntaxNodeKind.MacroExpandDecl) {
                throw Exception("InitException: Invalid 'body.memberDecls' for 'EnumDecl' init.")
            }
            ret.add(builder.buildNewline(1))
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(decl.nodeImpl)
        }
        ret.add(builder.buildNewline(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.Body, ret.toArray())
    }

    static func createEnumDeclImpl(body: Body, constructors: Array<EnumConstructor>,
        genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>, isNonExhaustive: Bool,
        name: String, superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [],
        modifiers!: Array<Modifier> = [], comments!: Array<Comment> = []) {
        checkGenericParamAndGenericConstraints(genericConstraints, genericParams)
        unsafe { checkIdentifier(name, "name", "EnumDecl") }
        if (constructors.size == 0) {
            throw Exception("InitException: The input 'constructors' cannot be empty for 'EnumDecl' init.")
        }
        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.EnumToken))
        addNamedGenericDeclHead(builder, ret, name, genericParams)

        addSuperTyAnnotations(builder, ret, superTyAnnotations)

        addGenericConstraints(builder, ret, genericConstraints)

        ret.add(builder.buildSpace(1))
        ret.add(createEnumBody(body, constructors, isNonExhaustive))

        builder.buildNonTerminal(SyntaxNodeKind.EnumDecl, ret.toArray())
    }

    static func createPropDeclImpl(getter: Option<PropGetterOrSetter>, name: String, setter: Option<PropGetterOrSetter>,
        tyAnnotation: TypeAnnotation, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "PropDecl") }
        if (let Some(_) <- setter && getter.isNone()) {
            throw Exception(
                "InitException: The input 'getter' cannot be None if input 'setter' exists during 'PropDecl' init.")
        }
        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.PropToken))
        ret.add(builder.buildSpace(1))

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
        ret.add(builder.buildSpace(1))
        ret.add(tyAnnotation.nodeImpl)
        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        ret.add(builder.buildNewline(1))

        if (let Some(get) <- getter) {
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(get.nodeImpl)
        }
        ret.add(builder.buildNewline(1))
        if (let Some(set) <- setter) {
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(set.nodeImpl)
        }
        ret.add(builder.buildNewline(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.PropDecl, ret.toArray())
    }

    static func createExtendDeclImpl(body: Body, extendedTyAnnotation: TypeAnnotation,
        genericConstraints: Option<GenericConstraints>, genericParams: Array<GenericParam>,
        superTyAnnotations: Array<TypeAnnotation>, annotations!: Array<Annotation> = [], comments!: Array<Comment> = []) {
        checkGenericParamAndGenericConstraints(genericConstraints, genericParams)
        for (decl in body.memberDecls) {
            if (decl.nodeImpl.kind != SyntaxNodeKind.FuncDecl && decl.nodeImpl.kind != SyntaxNodeKind.MacroExpandDecl &&
                decl.nodeImpl.kind != SyntaxNodeKind.PropDecl) {
                throw Exception("InitException: Invalid input 'body.memberDecls' for 'ExtendDecl' init.")
            }
        }

        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
            ret.add(builder.buildNewline(1))
        }

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ExtendToken))

        if (genericParams.size > 0) {
            ret.add(createTyepArguments(genericParams))
        }

        ret.add(builder.buildSpace(1))
        ret.add(extendedTyAnnotation.nodeImpl)

        addSuperTyAnnotations(builder, ret, superTyAnnotations)

        addGenericConstraints(builder, ret, genericConstraints)

        addDeclBody(builder, ret, body)

        builder.buildNonTerminal(SyntaxNodeKind.ExtendDecl, ret.toArray())
    }

    static func createMacroExpandDeclImpl(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = []) {
        if (calleeMacro.nodeImpl.kind != SyntaxNodeKind.MemberAccess && calleeMacro.nodeImpl.kind != SyntaxNodeKind
            .RefExpr) {
            throw Exception("InitException: Invalid input 'calleeMacro' for 'MacroExpandDecl' init.")
        }

        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addMacroExpandAnnotations(builder, ret, comments, annotations)
        addMacroCalleeAndAttrs(builder, ret, calleeMacro, macroAttrs)

        match (macroInputs) {
            case MacroExpandInput.WithoutParens(decl) =>
                ret.add(builder.buildNewline(1))
                ret.add(decl.nodeImpl)
            case MacroExpandInput.WithParens(toks) =>
                addDelimitedTokenList(builder, ret, toks, SyntaxNodeKind.LParenToken, SyntaxNodeKind.RParenToken)
            case _ => throw Exception("InitException: Invalid input 'macroInputs' for 'MacroExpandDecl' init.")
        }

        builder.buildNonTerminal(SyntaxNodeKind.MacroExpandDecl, ret.toArray())
    }

    static func createEnumConstructorImpl(name: String, paramTyAnnotations: Array<TypeAnnotation>,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "EnumConstructor") }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
            ret.add(builder.buildNewline(1))
        }

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))

        if (!paramTyAnnotations.isEmpty()) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            for (i in 0..paramTyAnnotations.size) {
                ret.add(paramTyAnnotations[i].nodeImpl)
                if (i < paramTyAnnotations.size - 1) {
                    ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    ret.add(builder.buildSpace(1))
                }
            }
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        }

        builder.buildNonTerminal(SyntaxNodeKind.EnumConstructor, ret.toArray())
    }

    static func createMacroDeclImpl(body: Block, name: String, params: ParameterList,
        retTyAnnotation: Option<TypeAnnotation>, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "MacroDecl") }
        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.MacroToken))
        ret.add(builder.buildSpace(1))

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))

        ret.add(params.nodeImpl)

        if (let Some(tyAnno) <- retTyAnnotation) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            ret.add(builder.buildSpace(1))
            ret.add(tyAnno.nodeImpl)
        }

        ret.add(builder.buildSpace(1))
        ret.add(body.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.MacroDecl, ret.toArray())
    }

    static func createMainDeclImpl(body: Block, params: ParameterList, retTyAnnotation: Option<TypeAnnotation>,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.MainToken))
        ret.add(params.nodeImpl)

        if (let Some(tyAnno) <- retTyAnnotation) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            ret.add(builder.buildSpace(1))
            ret.add(tyAnno.nodeImpl)
        }

        ret.add(builder.buildSpace(1))
        ret.add(body.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.MainDecl, ret.toArray())
    }

    static func createStaticInitImpl(body: Block, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        let modifierRet = ArrayList<SyntaxNodeImpl>()
        modifierRet.add(builder.buildBasicTerminal(SyntaxNodeKind.StaticToken))
        let staticModifier = builder.buildNonTerminal(SyntaxNodeKind.Modifier, modifierRet.toArray())

        let modifierListRet = ArrayList<SyntaxNodeImpl>()
        modifierListRet.add(staticModifier)
        let modifierList = builder.buildNonTerminal(SyntaxNodeKind.ModifierList, modifierListRet.toArray())

        ret.add(modifierList)
        ret.add(builder.buildSpace(1))

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.InitToken))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))

        ret.add(builder.buildSpace(1))
        ret.add(body.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.StaticInit, ret.toArray())
    }

    static func createTypeAliasImpl(aliasName: String, originalTyAnnotation: TypeAnnotation,
        typeParameters: Array<GenericParam>, modifiers!: Array<Modifier> = [], comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(aliasName, "aliasName", "TypeAlias") }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (modifiers.size != 0) {
            ret.add(createModifierList(modifiers))
            ret.add(builder.buildSpace(1))
        }

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.TypeToken))
        ret.add(builder.buildSpace(1))

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, aliasName))

        if (typeParameters.size > 0) {
            ret.add(createTyepArguments(typeParameters))
        }

        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.AssignToken))
        ret.add(builder.buildSpace(1))
        ret.add(originalTyAnnotation.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.TypeAlias, ret.toArray())
    }

    static func createVarDeclImpl(initializer: Option<Expr>, kind: VarKind, name: String, pattern: Pattern,
        tyAnnotation: Option<TypeAnnotation>, annotations!: Array<Annotation> = [], modifiers!: Array<Modifier> = [],
        comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "VarDecl") }
        if (pattern.nodeImpl.kind != SyntaxNodeKind.WildcardPattern && pattern.nodeImpl.kind != SyntaxNodeKind
            .VarBindingPattern && pattern.nodeImpl.kind != SyntaxNodeKind.TuplePattern && pattern.nodeImpl.kind != SyntaxNodeKind
            .EnumPattern) {
            throw Exception("InitException: Invalid input 'pattern' for 'VarDecl' init.")
        }

        if (hasModifier(modifiers, ModifierKind.Const)) {
            throw Exception("InitException: The input 'modifiers' cannot have 'Const' for 'VarDecl' init.")
        }

        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        match (kind) {
            case VarKind.Var => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.VarToken))
            case VarKind.Let => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LetToken))
            case VarKind.Const => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ConstToken))
            case _ => throw Exception("InitException: Invalid input 'kind' for 'VarDecl' init.")
        }

        ret.add(builder.buildSpace(1))

        ret.add(pattern.nodeImpl)

        if (let Some(tyAnno) <- tyAnnotation) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            ret.add(builder.buildSpace(1))
            ret.add(tyAnno.nodeImpl)
        }

        if (let Some(initEx) <- initializer) {
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.AssignToken))
            ret.add(builder.buildSpace(1))
            ret.add(initEx.nodeImpl)
        }

        builder.buildNonTerminal(SyntaxNodeKind.VarDecl, ret.toArray())
    }

    static func createFuncParamImpl(defaultValue: Option<Expr>, kind: Option<VarKind>, name: String,
        typeAnnotation: TypeAnnotation, isNamed!: Bool = false, annotations!: Array<Annotation> = [],
        modifiers!: Array<Modifier> = [], comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "FuncParam") }
        if (modifiers.size > 0 && kind.isNone()) {
            throw Exception(
                "InitException: The input 'modifiers' is only supported when input 'kind' exists for 'FuncParam' init.")
        }
        let (builder, ret) = createDeclLikePrefix(annotations, modifiers, comments)

        if (let Some(varKind) <- kind) {
            match (varKind) {
                case VarKind.Var => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.VarToken))
                case VarKind.Let => ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LetToken))
                case _ => throw Exception("InitException: Invalid input 'kind' for 'FuncParam' init.")
            }
            ret.add(builder.buildSpace(1))
        }

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
        if (isNamed) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.NotToken))
        }

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
        ret.add(builder.buildSpace(1))

        ret.add(typeAnnotation.nodeImpl)

        if (let Some(value) <- defaultValue) {
            if (!isNamed) {
                throw Exception(
                    "InitException: The input 'isNamed' must be true when 'defaultValue' given during 'FuncParam' init.")
            }
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.AssignToken))
            ret.add(builder.buildSpace(1))
            ret.add(value.nodeImpl)
        }

        builder.buildNonTerminal(SyntaxNodeKind.FuncParam, ret.toArray())
    }

    static func createGenericParamImpl(name: String, comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "GenericParam") }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))

        builder.buildNonTerminal(SyntaxNodeKind.GenericParam, ret.toArray())
    }

    static func createMacroExpandParamImpl(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = []) {
        if (calleeMacro.nodeImpl.kind != SyntaxNodeKind.MemberAccess && calleeMacro.nodeImpl.kind != SyntaxNodeKind
            .RefExpr) {
            throw Exception("InitException: Invalid input 'calleeMacro' for 'MacroExpandParam' init.")
        }

        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addMacroExpandAnnotations(builder, ret, comments, annotations)
        addMacroCalleeAndAttrs(builder, ret, calleeMacro, macroAttrs)

        match (macroInputs) {
            case MacroExpandInput.WithoutParens(decl) =>
                ret.add(builder.buildSpace(1))
                ret.add(decl.nodeImpl)
            case MacroExpandInput.WithParens(toks) =>
                addDelimitedTokenList(builder, ret, toks, SyntaxNodeKind.LParenToken, SyntaxNodeKind.RParenToken)
            case _ => throw Exception("InitException: Invalid input 'macroInputs' for 'MacroExpandParam' init.")
        }

        builder.buildNonTerminal(SyntaxNodeKind.MacroExpandParam, ret.toArray())
    }

    static func createLitConstExprImpl(kind: LitConstKind, value: String, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        match (kind) {
            case LitConstKind.BoolLiteral => ret.add(
                builder.buildValuedTerminal(SyntaxNodeKind.BooleanLiteralToken, value))
            case LitConstKind.FloatLiteral => ret.add(
                builder.buildValuedTerminal(SyntaxNodeKind.FloatLiteralToken, value))
            case LitConstKind.IntergerLiteral => ret.add(
                builder.buildValuedTerminal(SyntaxNodeKind.IntegerLiteralToken, value))
            case LitConstKind.UnitLiteral =>
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
                ret.add(builder.buildSpace(value.size - SyntaxNodeKind.LParenToken.size - SyntaxNodeKind.RParenToken.size))
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
                return builder.buildNonTerminal(SyntaxNodeKind.UnitLiteral, ret.toArray())
            case _ => throw Exception("InitException: Invalid input 'kind' for 'LitConstExpr' init.")
        }

        builder.buildNonTerminal(SyntaxNodeKind.ValuedLiteral, ret.toArray())
    }

    static func createLitConstStrExprImpl(kind: LitConstKind, rawValue: String, delimiterNum: Int64,
        isSingleQuote: Bool, strKind: LitConstStrKind, strPartExprs: Array<StrLiteralPart>,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        let litToken = builder.buildValuedTerminal(SyntaxNodeKind.StringLiteralToken, rawValue)

        match (kind) {
            case LitConstKind.StringLiteral => SyntaxNodeKind.LineStringLiteral
            case _ => throw Exception("InitException: Invalid input 'kind' for 'LitConstStrExpr' init.")
        }

        match (strKind) {
            case LitConstStrKind.StringLiteral => return createStringLiteralImpl(kind, rawValue, delimiterNum,
                isSingleQuote, strKind, strPartExprs, comments: comments)
            case LitConstStrKind.MultiLineString => return createMultiLineStringImpl(kind, rawValue, delimiterNum,
                isSingleQuote, strKind, strPartExprs, comments: comments)
            case LitConstStrKind.MultiLineRawString =>
                if (delimiterNum == 0) {
                    throw Exception(
                        "InitException: The input 'delimiterNum' cannot be zero for LitConstStrExpr.MultiLineRawString init.")
                }
                let quoteToken = builder.buildQuote(isSingleQuote)
                let hashToken = builder.buildHash(delimiterNum)
                ret.add(all: [hashToken, quoteToken, litToken, quoteToken, hashToken])
                return builder.buildNonTerminal(SyntaxNodeKind.MultiLineRawStringLiteral, ret.toArray())

            case _ => throw Exception("InitException: Invalid input 'strKind' for 'LitConstStrExpr' init.")
        }

        builder.buildNonTerminal(SyntaxNodeKind.LineStringLiteral, ret.toArray())
    }

    static func createStringLiteralImpl(kind: LitConstKind, rawValue: String, delimiterNum: Int64, isSingleQuote: Bool,
        strKind: LitConstStrKind, strPartExprs: Array<StrLiteralPart>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        let quoteToken = builder.buildQuote(isSingleQuote)
        ret.add(quoteToken)
        if (strPartExprs.size > 0) {
            for (strPart in strPartExprs) {
                match (strPart) {
                    case StrInterpolation(strInterExpr) => ret.add(strInterExpr.nodeImpl)
                    case LitConstPart(litConstExpr) => ret.add(litConstExpr.nodeImpl)
                    case _ => throw Exception(
                        "InitException: Invalid input 'strPart' for 'LitConstStrExpr.StringLiteral' init.")
                }
            }
        } else {
            ret.add(builder.buildValuedTerminal(SyntaxNodeKind.StringLiteralToken, rawValue))
        }
        ret.add(quoteToken)
        builder.buildNonTerminal(SyntaxNodeKind.LineStringLiteral, ret.toArray())
    }

    static func createMultiLineStringImpl(kind: LitConstKind, rawValue: String, delimiterNum: Int64,
        isSingleQuote: Bool, strKind: LitConstStrKind, strPartExprs: Array<StrLiteralPart>,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        let quoteToken = builder.buildTripleQuote(isSingleQuote)
        ret.add(quoteToken)
        ret.add(builder.buildNewline(1))
        if (strPartExprs.size > 0) {
            for (strPart in strPartExprs) {
                match (strPart) {
                    case StrInterpolation(strInterExpr) => ret.add(strInterExpr.nodeImpl)
                    case LitConstPart(litConstExpr) => ret.add(litConstExpr.nodeImpl)
                    case _ => throw Exception(
                        "InitException: Invalid input 'strPart' for 'LitConstStrExpr.MultiLineString' init.")
                }
            }
        } else {
            ret.add(builder.buildValuedTerminal(SyntaxNodeKind.StringLiteralToken, rawValue))
        }
        ret.add(quoteToken)
        builder.buildNonTerminal(SyntaxNodeKind.MultiLineStringLiteral, ret.toArray())
    }

    static func createLitConstRuneExprImpl(kind: LitConstKind, rawValue: String, isSingleQuote: Bool,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        match (kind) {
            case LitConstKind.RuneLiteral =>
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RunePrefixToken))
                ret.add(builder.buildQuote(isSingleQuote))
                ret.add(builder.buildValuedTerminal(SyntaxNodeKind.StringLiteralToken, rawValue))
                ret.add(builder.buildQuote(isSingleQuote))
            case _ => throw Exception("InitException: Invalid input 'kind' for 'LitConstRuneExpr' init.")
        }

        builder.buildNonTerminal(SyntaxNodeKind.RuneLiteral, ret.toArray())
    }

    static func createArrayLiteralImpl(elements: Array<Expr>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LSquareToken))
        for (i in 0..elements.size) {
            ret.add(elements[i].nodeImpl)
            if (i < elements.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RSquareToken))

        builder.buildNonTerminal(SyntaxNodeKind.ArrayLiteral, ret.toArray())
    }

    static func createTupleLiteralImpl(elements: Array<SyntaxTreeNode>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        for (i in 0..elements.size) {
            ret.add(elements[i].nodeImpl)
            if (i < elements.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))

        builder.buildNonTerminal(SyntaxNodeKind.TupleLiteral, ret.toArray())
    }

    static func createSymbolRefTyepArguments(typeArguments: Array<TypeAnnotation>) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LtToken))
        for (i in 0..typeArguments.size) {
            ret.add(typeArguments[i].nodeImpl)
            if (i < typeArguments.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.GtToken))

        builder.buildNonTerminal(SyntaxNodeKind.TypeArguments, ret.toArray())
    }

    static func createSymbolRefImpl(name: String, typeArguments: Array<TypeAnnotation>, comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "SymbolRef") }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))

        if (typeArguments.size > 0) {
            ret.add(createSymbolRefTyepArguments(typeArguments))
        }

        builder.buildNonTerminal(SyntaxNodeKind.RefExpr, ret.toArray())
    }

    static func createMemberAccessImpl(base: SyntaxTreeNode, field: SymbolRef, comments!: Array<Comment> = []) {
        if (!base.nodeImpl.kind.isTypeAnnotation() && !base.nodeImpl.kind.isExpr()) {
            throw Exception("InitException: Invalid input 'base' for 'MemberAccess' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(base.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        ret.add(field.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.MemberAccess, ret.toArray())
    }

    static func createOptionalExprImpl(base: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(base.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.QuestToken))

        builder.buildNonTerminal(SyntaxNodeKind.OptionalExpr, ret.toArray())
    }

    static func createAssignExprImpl(assignOpKind: AssignOpKind, lhs: SyntaxTreeNode, rhs: Expr,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(lhs.nodeImpl)
        ret.add(builder.buildSpace(1))

        let opToken = match (assignOpKind) {
            case AssignOpKind.AddAssign => SyntaxNodeKind.AddAssignToken
            case AssignOpKind.AndAssign => SyntaxNodeKind.AndAssignToken
            case AssignOpKind.Assign => SyntaxNodeKind.AssignToken
            case AssignOpKind.BitAndAssign => SyntaxNodeKind.BitAndAssignToken
            case AssignOpKind.BitOrAssign => SyntaxNodeKind.BitOrAssignToken
            case AssignOpKind.BitXorAssign => SyntaxNodeKind.BitXorAssignToken
            case AssignOpKind.DivAssign => SyntaxNodeKind.DivAssignToken
            case AssignOpKind.ExpAssign => SyntaxNodeKind.ExpAssignToken
            case AssignOpKind.LShiftAssign => SyntaxNodeKind.LShiftAssignToken
            case AssignOpKind.ModAssign => SyntaxNodeKind.ModAssignToken
            case AssignOpKind.MulAssign => SyntaxNodeKind.MulAssignToken
            case AssignOpKind.OrAssign => SyntaxNodeKind.OrAssignToken
            case AssignOpKind.RShiftAssign => SyntaxNodeKind.RShiftAssignToken
            case AssignOpKind.SubAssign => SyntaxNodeKind.SubAssignToken
            case _ => throw Exception("InitException: Invalid input 'assignOpKind' for 'AssignExpr' init.")
        }

        ret.add(builder.buildBasicTerminal(opToken))
        ret.add(builder.buildSpace(1))
        ret.add(rhs.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.AssignExpr, ret.toArray())
    }

    static func createUnsafeExprImpl(body: Block, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.UnsafeToken))
        ret.add(builder.buildSpace(1))
        ret.add(body.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.UnsafeExpr, ret.toArray())
    }

    static func createSubscriptExprImpl(base: Expr, indexs: Array<Expr>, comments!: Array<Comment> = []) {
        if (indexs.size == 0) {
            throw Exception("InitException: The input 'indexs' cannot be empty for 'SubscriptExpr' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(base.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LSquareToken))

        for (i in 0..indexs.size) {
            ret.add(indexs[i].nodeImpl)
            if (i < indexs.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RSquareToken))

        builder.buildNonTerminal(SyntaxNodeKind.SubscriptExpr, ret.toArray())
    }

    static func createLambdaImpl(body: Array<SyntaxTreeNode>, params: ParameterList, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        ret.add(builder.buildSpace(1))

        if (!params.getParamsLParenPos().isNone()) {
            throw Exception("InitException: The input 'params' should not have parens for 'Lambda' init.")
        }
        ret.add(params.nodeImpl)
        ret.add(builder.buildSpace(1))

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.DoubleArrowToken))
        ret.add(builder.buildSpace(1))

        for (i in 0..body.size) {
            ret.add(body[i].nodeImpl)
            if (i < body.size - 1) {
                ret.add(builder.buildNewline(1))
            }
        }

        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.Lambda, ret.toArray())
    }

    static func createMatchExprImpl(matchCases: Array<MatchCase>, selector: Option<Expr>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.MatchToken))
        ret.add(builder.buildSpace(1))

        if (let Some(sel) <- selector) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            ret.add(sel.nodeImpl)
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
            ret.add(builder.buildSpace(1))
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        for (i in 0..matchCases.size) {
            ret.add(builder.buildNewline(1))
            ret.add(builder.buildSpace(FORMAT_INDENTATION))
            ret.add(matchCases[i].nodeImpl)
        }
        ret.add(builder.buildNewline(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.MatchExpr, ret.toArray())
    }

    static func createTryCatchImpl(catchBlocks: Array<Block>, catchPatterns: Array<CatchPattern>,
        finallyBlock: Option<Block>, resourceSpec: Array<VarDecl>, tryBlock: Block, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.TryToken))
        if (!resourceSpec.isEmpty()) {
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))

            for (i in 0..resourceSpec.size) {
                ret.add(resourceSpec[i].nodeImpl)
                if (i < resourceSpec.size - 1) {
                    ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    ret.add(builder.buildSpace(1))
                }
            }
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        } else if (catchPatterns.isEmpty() && finallyBlock.isNone()) {
            throw Exception(
                "InitException: The input 'catchPatterns' or 'finallyBlock' must exist if 'resourceSpec' is empty when 'SubscriptExpr' init.")
        }

        ret.add(builder.buildSpace(1))
        ret.add(tryBlock.nodeImpl)

        for (i in 0..catchPatterns.size) {
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CatchToken))
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            ret.add(catchPatterns[i].nodeImpl)
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
            ret.add(builder.buildSpace(1))
            ret.add(catchBlocks[i].nodeImpl)
        }

        if (let Some(finalBlock) <- finallyBlock) {
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.FinallyToken))
            ret.add(builder.buildSpace(1))
            ret.add(finalBlock.nodeImpl)
        }

        builder.buildNonTerminal(SyntaxNodeKind.TryExpr, ret.toArray())
    }

    static func createThrowExprImpl(throwVal: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ThrowToken))
        ret.add(builder.buildSpace(1))
        ret.add(throwVal.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.ThrowExpr, ret.toArray())
    }

    static func createSynchronizedExprImpl(block: Block, structuredMutex: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.SynchronizedToken))
        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        ret.add(structuredMutex.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        ret.add(builder.buildSpace(1))
        ret.add(block.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.SynchronizedExpr, ret.toArray())
    }

    static func createSpawnExprImpl(threadContext: Option<Expr>, trailingLambdaExpr: Lambda,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.SpawnToken))
        ret.add(builder.buildSpace(1))
        if (let Some(context) <- threadContext) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            ret.add(context.nodeImpl)
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        }
        ret.add(builder.buildSpace(1))
        ret.add(trailingLambdaExpr.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.SpawnExpr, ret.toArray())
    }

    static func createIfExprImpl(condition: DisjunctionCondition, elseBlock: Option<Block>, elseIf: Option<IfExpr>,
        ifBlock: Block, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.IfToken))
        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        ret.add(condition.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        ret.add(builder.buildSpace(1))
        ret.add(ifBlock.nodeImpl)

        if (let Some(elseIfExpr) <- elseIf) {
            if (!elseIfExpr.elseBlock.isNone() && !elseBlock.isNone()) {
                throw Exception("InitException: IfExpr only support one elseBlock when IfExpr Init")
            }
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ElseToken))
            ret.add(builder.buildSpace(1))
            ret.add(elseIfExpr.nodeImpl)
        }

        if (let Some(elBlock) <- elseBlock) {
            ret.add(builder.buildSpace(1))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ElseToken))
            ret.add(builder.buildSpace(1))
            ret.add(elBlock.nodeImpl)
        }

        builder.buildNonTerminal(SyntaxNodeKind.IfExpr, ret.toArray())
    }

    static func createWhileExprImpl(body: Block, condition: DisjunctionCondition, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.WhileToken))
        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        ret.add(condition.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        ret.add(builder.buildSpace(1))
        ret.add(body.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.WhileExpr, ret.toArray())
    }

    static func createDoWhileExprImpl(body: Block, condition: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.DoToken))
        ret.add(builder.buildSpace(1))

        ret.add(body.nodeImpl)

        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.WhileToken))
        ret.add(builder.buildSpace(1))
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        ret.add(condition.nodeImpl)
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))

        builder.buildNonTerminal(SyntaxNodeKind.DoWhileExpr, ret.toArray())
    }

    static func createLambdaParamImpl(name: String, typeAnnotation: Option<TypeAnnotation>, comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "LambdaParam") }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))

        if (let Some(tyAnn) <- typeAnnotation) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            ret.add(builder.buildSpace(1))
            ret.add(tyAnn.nodeImpl)
        }

        builder.buildNonTerminal(SyntaxNodeKind.LambdaParam, ret.toArray())
    }

    static func createPropGetterOrSetterImpl(block: Block, identifier: Option<String>, isGetter: Bool,
        annotations!: Array<Annotation> = [], comments!: Array<Comment> = []) {
        if (isGetter && (annotations.size != 0 || let Some(_) <- identifier)) {
            throw Exception(
                "InitException: The input 'identifier' and 'annotations' not supported when 'PropGetterOrSetter.Getter' init.")
        }

        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
            ret.add(builder.buildNewline(1))
        }

        if (isGetter) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.GetToken))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        } else {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.SetToken))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            if (let Some(ident) <- identifier) {
                unsafe { checkIdentifier(ident, "identifier", "PropGetterOrSetter") }
                ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, ident))
            } else {
                throw Exception(
                    "InitException: The input 'identifier' cannot be None when 'PropGetterOrSetter.Setter' init.")
            }
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        }

        ret.add(builder.buildSpace(1))
        ret.add(block.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.PropGetterOrSetter, ret.toArray())
    }

    static func createFeatureIdImpl(featureNameIdentifiers: Array<String>, comments!: Array<Comment> = []) {
        if (featureNameIdentifiers.size == 0) {
            throw Exception(
                "InitException: The input 'featureNameIdentifiers' cannot be empty for 'FeatureId' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        for (i in 0..featureNameIdentifiers.size) {
            unsafe { checkIdentifier(featureNameIdentifiers[i], "identifier", "FeatureId") }
            ret.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, featureNameIdentifiers[i]))
            if (i + 1 < featureNameIdentifiers.size) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
            }
        }

        builder.buildNonTerminal(SyntaxNodeKind.FeatureId, ret.toArray())
    }

    static func createFeaturesSetImpl(features: Array<FeatureId>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        for (i in 0..features.size) {
            ret.add(features[i].nodeImpl)
            if (i + 1 < features.size) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                ret.add(builder.buildSpace(1))
            }
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))

        builder.buildNonTerminal(SyntaxNodeKind.FeaturesSet, ret.toArray())
    }

    static func createFeaturesDirectiveImpl(annotations: Array<Annotation>, set: FeaturesSet,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (annotations.size != 0) {
            ret.add(createAnnotationList(annotations))
        }

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.FeaturesToken))
        ret.add(builder.buildSpace(1))
        ret.add(set.nodeImpl)

        builder.buildNonTerminal(SyntaxNodeKind.FeaturesDirective, ret.toArray())
    }

    static func getPackageIndentKind(s: String): SyntaxNodeKind {
        let isPkgIdent = s.contains(".") || s.contains("-") || s.contains(" ")
        if (isPkgIdent) {
            return SyntaxNodeKind.PackageIdentifierToken
        } else {
            return SyntaxNodeKind.IdentToken
        }
    }

    static func transPackagePrefixes(prefixPaths: Array<String>) {
        let ret = ArrayList<SyntaxNodeImpl>()
        let builder = SyntaxNodeBuilder()
        for (i in 0..prefixPaths.size) {
            ret.add(builder.buildValuedTerminal(getPackageIndentKind(prefixPaths[i]), prefixPaths[i]))
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        builder.buildNonTerminal(SyntaxNodeKind.PackagePrefixes, ret.toArray())
    }

    static func createPackageHeaderImpl(accessModifier: Option<Modifier>, isMacroPkg: Bool,
        packageNameIdentifiers: Array<String>, comments!: Array<Comment> = []) {
        if (packageNameIdentifiers.size == 0) {
            throw Exception(
                "InitException: The input 'packageNameIdentifiers' cannot be empty for 'PackageHeader' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(ret, comments)

        if (let Some(modifier) <- accessModifier) {
            match (modifier.kind) {
                case ModifierKind.Internal => SyntaxNodeKind.InternalToken
                case ModifierKind.Protected => SyntaxNodeKind.ProtectedToken
                case ModifierKind.Public => SyntaxNodeKind.PublicToken
                case _ => throw Exception("InitException: Invalid input 'accessModifier' for 'PackageHeader' init.")
            }
            ret.add(modifier.nodeImpl)
            ret.add(builder.buildSpace(1))
        }

        if (isMacroPkg) {
            ret.add(builder.buildBasicTerminal(SyntaxNodeKind.MacroToken))
            ret.add(builder.buildSpace(1))
        }

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.PackageToken))
        ret.add(builder.buildSpace(1))

        let packageName = packageNameIdentifiers[packageNameIdentifiers.size - 1]

        if (packageNameIdentifiers.size > 1) {
            ret.add(transPackagePrefixes(packageNameIdentifiers[0..packageNameIdentifiers.size - 1]))
        }
        ret.add(builder.buildValuedTerminal(getPackageIndentKind(packageName), packageName))

        builder.buildNonTerminal(SyntaxNodeKind.PackageSpec, ret.toArray())
    }

    static func checkCommentContent(content: String) {
        if (content.startsWith("/*") && content.endsWith("*/") && content != "/*/") {
            return true
        } else if (content.startsWith("//") && !content.contains("\n")) {
            return true
        }
        return false
    }

    static func createCommentImpl(content: String) {
        if (!checkCommentContent(content)) {
            throw Exception("InitException: Invalid input 'content' for 'Comment' init.")
        }
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        ret.add(builder.buildTokenTerminal(TokenKind.COMMENT, content, hasEscape: false))

        builder.buildNonTerminal(SyntaxNodeKind.Comment, ret.toArray())
    }

    static func createParameterListImpl(parameters: Array<Parameter>, hasParen!: Bool = true,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        if (hasParen) {
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            for (i in 0..parameters.size) {
                parts.add(parameters[i].nodeImpl)
                if (i < parameters.size - 1) {
                    parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    parts.add(builder.buildSpace(1))
                }
            }
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        } else {
            for (i in 0..parameters.size) {
                parts.add(parameters[i].nodeImpl)
                if (i < parameters.size - 1) {
                    parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    parts.add(builder.buildSpace(1))
                }
            }
        }
        builder.buildNonTerminal(SyntaxNodeKind.ParameterList, parts.toArray())
    }

    static func createImportListImpl(contents: ImportContent, modifier: Option<Modifier>, comments!: Array<Comment> = []) {
        if (let Some(m) <- modifier) {
            match (m.kind) {
                case ModifierKind.Public | ModifierKind.Private | ModifierKind.Protected | ModifierKind.Internal => ()
                case _ => throw Exception("InitException: Invalid input 'modifier' for 'ImportList' init.")
            }
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        if (let Some(m) <- modifier) {
            parts.add(m.nodeImpl)
            parts.add(builder.buildSpace(1))
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ImportToken))
        parts.add(builder.buildSpace(1))
        parts.add(contents.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.ImportSpec, parts.toArray())
    }

    static func createImportSingleImpl(prefixes: Array<String>, identifier: String, comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(identifier, "identifier", "ImportSingle") }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..prefixes.size) {
            parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, prefixes[i]))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, identifier))
        builder.buildNonTerminal(SyntaxNodeKind.ImportSingle, parts.toArray())
    }

    static func createImportAliasImpl(prefixes: Array<String>, identifier: String, alias: String,
        comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(identifier, "identifier", "ImportAlias") }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..prefixes.size) {
            parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, prefixes[i]))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, identifier))
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.AsToken))
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, alias))
        builder.buildNonTerminal(SyntaxNodeKind.ImportAlias, parts.toArray())
    }

    static func createImportAllImpl(prefixes: Array<String>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..prefixes.size) {
            parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, prefixes[i]))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.MulToken))
        builder.buildNonTerminal(SyntaxNodeKind.ImportAll, parts.toArray())
    }

    static func createImportMultiImpl(prefixes: Array<String>, contents: Array<ImportContent>,
        comments!: Array<Comment> = []) {
        if (contents.isEmpty()) {
            throw Exception("InitException: The input 'contents' cannot be empty for 'ImportMulti' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..prefixes.size) {
            parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, prefixes[i]))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        for (i in 0..contents.size) {
            parts.add(contents[i].nodeImpl)
            if (i < contents.size - 1) {
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                parts.add(builder.buildSpace(1))
            }
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))
        builder.buildNonTerminal(SyntaxNodeKind.ImportMulti, parts.toArray())
    }

    // expr
    static func createForInExprImpl(body: Block, expr: Expr, pattern: Pattern, patternGuard: Option<Expr>,
        comments!: Array<Comment> = []) {
        if (pattern.nodeImpl.kind != SyntaxNodeKind.WildcardPattern && pattern.nodeImpl.kind != SyntaxNodeKind
            .VarBindingPattern && pattern.nodeImpl.kind != SyntaxNodeKind.TuplePattern && pattern.nodeImpl.kind != SyntaxNodeKind
            .EnumPattern) {
            throw Exception("InitException: Invalid input 'pattern' for 'ForInExpr' init.")
        }

        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ForToken))
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        parts.add(pattern.nodeImpl)
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.InToken))
        parts.add(builder.buildSpace(1))
        parts.add(expr.nodeImpl)
        if (let Some(p) <- patternGuard) {
            parts.add(builder.buildSpace(1))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.WhereToken))
            parts.add(builder.buildSpace(1))
            parts.add(p.nodeImpl)
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        parts.add(builder.buildSpace(1))
        parts.add(body.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.ForInExpr, parts.toArray())
    }

    static func createReturnExprImpl(retVal: Option<Expr>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ReturnToken))
        if (let Some(v) <- retVal) {
            parts.add(builder.buildSpace(1))
            parts.add(v.nodeImpl)
        }
        builder.buildNonTerminal(SyntaxNodeKind.ReturnExpr, parts.toArray())
    }

    static func createVArrayExprImpl(argument: Argument, vArrayType: VArrayType, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(vArrayType.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        parts.add(argument.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.VArrayExpr, parts.toArray())
    }

    static func createUnaryExprImpl(opKind: UnaryOpKind, operand: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        match (opKind) {
            case UnaryOpKind.Not => parts.add(builder.buildBasicTerminal(SyntaxNodeKind.NotToken))
            case UnaryOpKind.Sub => parts.add(builder.buildBasicTerminal(SyntaxNodeKind.SubToken))
            case _ => throw Exception("InitException: Invalid input 'opKind' for 'UnaryExpr' init.")
        }
        parts.add(operand.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.UnaryExpr, parts.toArray())
    }

    static func createQuoteExprImpl(tokensOrRefExpr: Array<QuoteExprContent>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.QuoteToken))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        for (i in 0..tokensOrRefExpr.size) {
            match (tokensOrRefExpr[i]) {
                case QuoteExprContent.TokenPart(t) => parts.add(t.nodeImpl)
                case QuoteExprContent.QuoteInterpolation(q) => parts.add(q.nodeImpl)
                case _ => throw Exception("InitException: Invalid input 'tokensOrRefExpr' for 'QuoteExpr' init.")
            }
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.QuoteExpr, parts.toArray())
    }

    static func createQuoteTokenImpl(content: Tokens, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        let tokenArray = ArrayList<SyntaxNodeImpl>()
        var tokBytes: CPointer<UInt8> = unsafePointerCastFromUint8Array((content).toBytes())
        var spaceFlag: CPointer<Bool> = unsafe { LibC.malloc<Bool>(count: content.size) }
        if (spaceFlag.isNull()) {
            unsafe { LibC.free(tokBytes) }
            throw IllegalMemoryException("malloc failed!")
        }
        unsafe { CJ_CheckAddSpaces(tokBytes, spaceFlag) }
        try {
            for (i in 0..content.size) {
                parts.add(builder.buildTokenTerminal(content[i].kind, content[i].value))
                if (unsafe { spaceFlag.read(i) }) {
                    parts.add(builder.buildSpace(1))
                }
            }
        } finally {
            unsafe { LibC.free(tokBytes) }
            unsafe { LibC.free(spaceFlag) }
        }
        builder.buildNonTerminal(SyntaxNodeKind.QuoteTokenExpr, parts.toArray())
    }

    static func createQuoteInterpolationExprImpl(expr: Expr, hasParen!: Bool = false, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DollarToken))
        if (hasParen) {
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            parts.add(expr.nodeImpl)
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        } else {
            parts.add(expr.nodeImpl)
        }
        builder.buildNonTerminal(SyntaxNodeKind.QuoteInterpolationExpr, parts.toArray())
    }

    static func createTrailingClosureExprImpl(callee: Expr, arguments: Array<Argument>, trailingLambdaExpr: Lambda,
        comments!: Array<Comment> = []) {
        if (callee.nodeImpl.kind != SyntaxNodeKind.MemberAccess && callee.nodeImpl.kind != SyntaxNodeKind.RefExpr) {
            throw Exception("InitException: Invalid input 'callee' for 'TrailingClosureExpr' init.")
        }

        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(callee.nodeImpl)
        if (!arguments.isEmpty()) {
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            for (i in 0..arguments.size) {
                parts.add(arguments[i].nodeImpl)
                if (i < arguments.size - 1) {
                    parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    parts.add(builder.buildSpace(1))
                }
            }
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        }
        parts.add(builder.buildSpace(1))
        parts.add(trailingLambdaExpr.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.TrailingClosureExpr, parts.toArray())
    }

    static unsafe func tokensToImplArray(tks: Tokens, tokBytes: CPointer<UInt8>, spaceFlag: CPointer<Bool>): Array<SyntaxNodeImpl> {
        try {
            let builder = SyntaxNodeBuilder()
            let arr = ArrayList<SyntaxNodeImpl>()
            for (i in 0..tks.size) {
                arr.add(builder.buildTokenTerminal(tks[i].kind, tks[i].value))
                if (spaceFlag.read(i)) {
                    arr.add(builder.buildSpace(1))
                }
            }
            return arr.toArray()
        } finally {
            LibC.free(tokBytes)
            LibC.free(spaceFlag)
        }
    }

    static unsafe func createMacroExpandExprImpl(calleeMacro: Expr, macroAttrs: Tokens, macroInputs: MacroExpandInput,
        comments!: Array<Comment> = []) {
        if (calleeMacro.nodeImpl.kind != SyntaxNodeKind.MemberAccess && calleeMacro.nodeImpl.kind != SyntaxNodeKind
            .RefExpr) {
            throw Exception("InitException: Invalid input 'calleeMacro' for 'MacroExpandExpr' init.")
        }

        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.AtToken))
        parts.add(calleeMacro.nodeImpl)
        if (macroAttrs.size != 0) {
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LSquareToken))
            var tokBytes: CPointer<UInt8> = unsafePointerCastFromUint8Array((macroAttrs).toBytes())
            var spaceFlag: CPointer<Bool> = LibC.malloc<Bool>(count: macroAttrs.size)
            if (spaceFlag.isNull()) {
                LibC.free(tokBytes)
                throw IllegalMemoryException("malloc failed!")
            }
            CJ_CheckAddSpaces(tokBytes, spaceFlag)
            let attrArray = tokensToImplArray(macroAttrs, tokBytes, spaceFlag)
            parts.add(builder.buildNonTerminal(SyntaxNodeKind.TokenList, attrArray))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RSquareToken))
        }
        match (macroInputs) {
            case MacroExpandInput.WithParens(toks) =>
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
                var tokBytes: CPointer<UInt8> = unsafePointerCastFromUint8Array((toks).toBytes())
                var spaceFlag: CPointer<Bool> = LibC.malloc<Bool>(count: toks.size)
                if (spaceFlag.isNull()) {
                    LibC.free(tokBytes)
                    throw IllegalMemoryException("malloc failed!")
                }
                CJ_CheckAddSpaces(tokBytes, spaceFlag)
                let attrArray = tokensToImplArray(toks, tokBytes, spaceFlag)
                parts.add(builder.buildNonTerminal(SyntaxNodeKind.TokenList, attrArray))
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
            case MacroExpandInput.WithoutParens(decl) =>
                parts.add(builder.buildNewline(1))
                parts.add(decl.nodeImpl)
            case _ => throw Exception("InitException: Invalid input 'macroInputs' for 'MacroExpandExpr' init.")
        }
        builder.buildNonTerminal(SyntaxNodeKind.MacroExpandExpr, parts.toArray())
    }

    static func createBinaryExprImpl(lhs: Expr, opKind: BinaryOpKind, rhs: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(lhs.nodeImpl)
        parts.add(builder.buildSpace(1))
        let opToken = match (opKind) {
            case BinaryOpKind.Add => SyntaxNodeKind.AddToken
            case BinaryOpKind.And => SyntaxNodeKind.AndToken
            case BinaryOpKind.BitAnd => SyntaxNodeKind.BitAndToken
            case BinaryOpKind.BitOr => SyntaxNodeKind.BitOrToken
            case BinaryOpKind.BitXor => SyntaxNodeKind.BitXorToken
            case BinaryOpKind.Coalescing => SyntaxNodeKind.CoalescingToken
            case BinaryOpKind.Composition => SyntaxNodeKind.CompositionToken
            case BinaryOpKind.Div => SyntaxNodeKind.DivToken
            case BinaryOpKind.Equal => SyntaxNodeKind.EqualToken
            case BinaryOpKind.Exp => SyntaxNodeKind.ExpToken
            case BinaryOpKind.Ge => SyntaxNodeKind.GeToken
            case BinaryOpKind.Gt => SyntaxNodeKind.GtToken
            case BinaryOpKind.Le => SyntaxNodeKind.LeToken
            case BinaryOpKind.LShift => SyntaxNodeKind.LShiftToken
            case BinaryOpKind.Lt => SyntaxNodeKind.LtToken
            case BinaryOpKind.Mod => SyntaxNodeKind.ModToken
            case BinaryOpKind.Mul => SyntaxNodeKind.MulToken
            case BinaryOpKind.NotEq => SyntaxNodeKind.NotEqToken
            case BinaryOpKind.Or => SyntaxNodeKind.OrToken
            case BinaryOpKind.Pipeline => SyntaxNodeKind.PipelineToken
            case BinaryOpKind.RShift => SyntaxNodeKind.RShiftToken
            case BinaryOpKind.Sub => SyntaxNodeKind.SubToken
            case _ => throw Exception("InitException: Invalid input 'opKind' for 'BinaryExpr' init.")
        }
        parts.add(builder.buildBasicTerminal(opToken))
        parts.add(builder.buildSpace(1))
        parts.add(rhs.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.BinaryExpr, parts.toArray())
    }

    // RangeExpr: start .. end : step   or   start ..= end : step
    static func createRangeExprImpl(start: Option<Expr>, kind: RangeKind, end: Option<Expr>, step: Option<Expr>,
        comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        if (let Some(s) <- start) {
            parts.add(s.nodeImpl)
        }
        let rangeToken = match (kind) {
            case RangeKind.RangeOp => SyntaxNodeKind.RangeOpToken
            case RangeKind.ClosedRangeOp => SyntaxNodeKind.ClosedRangeOpToken
            case _ => throw Exception("InitException: Invalid input 'RangeKind' for 'RangeExpr' init.")
        }
        parts.add(builder.buildBasicTerminal(rangeToken))
        if (let Some(e) <- end) {
            parts.add(e.nodeImpl)
        }
        if (let Some(st) <- step) {
            parts.add(builder.buildSpace(1))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            parts.add(builder.buildSpace(1))
            parts.add(st.nodeImpl)
        }
        builder.buildNonTerminal(SyntaxNodeKind.RangeExpr, parts.toArray())
    }

    static func createIncOrDecExprImpl(kind: IncOrDecOpKind, operand: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(operand.nodeImpl)
        match (kind) {
            case IncOrDecOpKind.Incr => parts.add(builder.buildBasicTerminal(SyntaxNodeKind.IncrToken))
            case IncOrDecOpKind.Decr => parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DecrToken))
            case _ => throw Exception("InitException: Invalid input 'opKind' for 'IncOrDecExpr' init.")
        }
        builder.buildNonTerminal(SyntaxNodeKind.IncOrDecExpr, parts.toArray())
    }

    static func createParenExprImpl(subExpr: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        parts.add(subExpr.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.ParenExpr, parts.toArray())
    }

    static func createCallExprImpl(callee: Expr, arguments: Array<Argument>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        if (callee.nodeImpl.kind != SyntaxNodeKind.MemberAccess && callee.nodeImpl.kind != SyntaxNodeKind.RefExpr) {
            throw Exception("InitException: Invalid input 'callee' for 'CallExpr' init.")
        }
        parts.add(callee.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        for (i in 0..arguments.size) {
            parts.add(arguments[i].nodeImpl)
            if (i < arguments.size - 1) {
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                parts.add(builder.buildSpace(1))
            }
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.CallExpr, parts.toArray())
    }

    static func createIsExprImpl(srcVal: Expr, targetTypeAnnotation: TypeAnnotation, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(srcVal.nodeImpl)
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.IsToken))
        parts.add(builder.buildSpace(1))
        parts.add(targetTypeAnnotation.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.IsExpr, parts.toArray())
    }

    static func createAsExprImpl(srcVal: Expr, targetTypeAnnotation: TypeAnnotation, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(srcVal.nodeImpl)
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.AsToken))
        parts.add(builder.buildSpace(1))
        parts.add(targetTypeAnnotation.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.AsExpr, parts.toArray())
    }

    static func createTypeConvExprImpl(targetTypeAnnotation: AtomicType, srcVal: Expr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(targetTypeAnnotation.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        parts.add(srcVal.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.TypeConvExpr, parts.toArray())
    }

    static func createMatchCaseImpl(patterns: Array<Pattern>, patternGuardCond: Option<Expr>, caseCond: Option<Expr>,
        body: Array<SyntaxTreeNode>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CaseToken))
        parts.add(builder.buildSpace(1))
        if (!patterns.isEmpty()) {
            for (i in 0..patterns.size) {
                parts.add(patterns[i].nodeImpl)
                if (i < patterns.size - 1) {
                    parts.add(builder.buildSpace(1))
                    parts.add(builder.buildBasicTerminal(SyntaxNodeKind.BitOrToken))
                    parts.add(builder.buildSpace(1))
                }
            }
            parts.add(builder.buildSpace(1))
            if (let Some(pcond) <- patternGuardCond) {
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.WhereToken))
                parts.add(builder.buildSpace(1))
                parts.add(pcond.nodeImpl)
                parts.add(builder.buildSpace(1))
            }
        } else if (let Some(cond) <- caseCond) {
            parts.add(cond.nodeImpl)
            parts.add(builder.buildSpace(1))
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DoubleArrowToken))
        parts.add(builder.buildSpace(1))
        let matchCaseBody = ArrayList<SyntaxNodeImpl>()
        for (i in 0..body.size) {
            if (!body[i].nodeImpl.kind.isExpr() && body[i].nodeImpl.kind != SyntaxNodeKind.FuncDecl &&
                body[i].nodeImpl.kind != SyntaxNodeKind.VarDecl) {
                throw Exception("InitException: Invalid input 'body' for 'MatchCase' init.")
            }
            matchCaseBody.add(body[i].nodeImpl)
            if (i < body.size - 1) {
                matchCaseBody.add(builder.buildNewline(1))
            }
        }
        parts.add(builder.buildNonTerminal(SyntaxNodeKind.MatchCaseBody, matchCaseBody.toArray()))
        builder.buildNonTerminal(SyntaxNodeKind.MatchCase, parts.toArray())
    }

    static func createCatchPatternImpl(pattern: Pattern, exceptionType: Array<TypeAnnotation>,
        comments!: Array<Comment> = []) {
        if (pattern.nodeImpl.kind != SyntaxNodeKind.WildcardPattern && pattern.nodeImpl.kind != SyntaxNodeKind
            .VarBindingPattern) {
            throw Exception("InitException: Invalid input 'pattern' for 'CatchPattern' init.")
        }

        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(pattern.nodeImpl)
        if (!exceptionType.isEmpty()) {
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            parts.add(builder.buildSpace(1))
            for (i in 0..exceptionType.size) {
                parts.add(exceptionType[i].nodeImpl)
                if (i < exceptionType.size - 1) {
                    parts.add(builder.buildSpace(1))
                    parts.add(builder.buildBasicTerminal(SyntaxNodeKind.BitOrToken))
                    parts.add(builder.buildSpace(1))
                }
            }
        } else if (pattern.nodeImpl.kind == SyntaxNodeKind.VarBindingPattern) {
            throw Exception(
                "InitException: The input 'exceptionType' cannot be None when 'pattern' is 'VarBindingPattern' for 'CatchPattern' init.")
        }
        builder.buildNonTerminal(SyntaxNodeKind.CatchPattern, parts.toArray())
    }

    static func createBreakExprImpl(comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.BreakToken))
        builder.buildNonTerminal(SyntaxNodeKind.BreakExpr, parts.toArray())
    }

    static func createContinueExprImpl(comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ContinueToken))
        builder.buildNonTerminal(SyntaxNodeKind.ContinueExpr, parts.toArray())
    }

    static func createDisjunctionConditionImpl(cond: Array<ConjunctionCondition>, comments!: Array<Comment> = []) {
        if (cond.isEmpty()) {
            throw Exception("InitException: The input 'cond' cannot be empty for 'DisjunctionCondition' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..cond.size) {
            parts.add(cond[i].nodeImpl)
            if (i < cond.size - 1) {
                parts.add(builder.buildSpace(1))
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.OrToken))
                parts.add(builder.buildSpace(1))
            }
        }
        builder.buildNonTerminal(SyntaxNodeKind.DisjunctionCondition, parts.toArray())
    }

    static func createConjunctionConditionImpl(cond: Array<AtomicCondition>, comments!: Array<Comment> = []) {
        if (cond.isEmpty()) {
            throw Exception("InitException: The input 'cond' cannot be empty for 'conjunctionCondition' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..cond.size) {
            match (cond[i]) {
                case AtomicCondition.Expression(expr) => parts.add(expr.nodeImpl)
                case AtomicCondition.LetPatternCondition(letPattern) => parts.add(letPattern.nodeImpl)
                case AtomicCondition.ParenConditionConstructor(parenCondition) => parts.add(parenCondition.nodeImpl)
                case _ => throw Exception("InitException: Invalid input 'condition' for 'ConjunctionCondition' init.")
            }
            if (i < cond.size - 1) {
                parts.add(builder.buildSpace(1))
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.AndToken))
                parts.add(builder.buildSpace(1))
            }
        }
        builder.buildNonTerminal(SyntaxNodeKind.ConjunctionCondition, parts.toArray())
    }

    static func createParenConditionImpl(cond: DisjunctionCondition, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        parts.add(cond.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.ParenCondition, parts.toArray())
    }

    static func createLetPatternImpl(expr: Expr, patterns: Array<Pattern>, comments!: Array<Comment> = []) {
        if (patterns.isEmpty()) {
            throw Exception("InitException: The input 'patterns' cannot be empty for 'LetPattern' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LetToken))
        parts.add(builder.buildSpace(1))
        for (i in 0..patterns.size) {
            parts.add(patterns[i].nodeImpl)
            if (i < patterns.size - 1) {
                parts.add(builder.buildSpace(1))
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.BitOrToken))
                parts.add(builder.buildSpace(1))
            }
        }
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.BackArrowToken))
        parts.add(builder.buildSpace(1))
        parts.add(expr.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.LetPattern, parts.toArray())
    }

    /** 
    *   Modify the input block by converting it into a block without NewLines.
    *   Nodes in block are seperated by semiToken.
    */
    static func modifyInterpolationBlock(interpolationBlock: Block) {
        let builder = SyntaxNodeBuilder()
        let ret = ArrayList<SyntaxNodeImpl>()

        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.LCurlToken))
        for (i in 0..interpolationBlock.nodes.size) {
            ret.add(interpolationBlock.nodes[i].nodeImpl)
            if (i < interpolationBlock.nodes.size - 1) {
                ret.add(builder.buildBasicTerminal(SyntaxNodeKind.SemiToken))
                ret.add(builder.buildSpace(1))
            }
        }
        ret.add(builder.buildBasicTerminal(SyntaxNodeKind.RCurlToken))
        builder.buildNonTerminal(SyntaxNodeKind.Block, ret.toArray())
    }

    static func createStrInterpolationContentImpl(interpolationBlock: Block, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DollarToken))
        parts.add(modifyInterpolationBlock(interpolationBlock))
        builder.buildNonTerminal(SyntaxNodeKind.InterpolationExpr, parts.toArray())
    }

    static func createConstPatternImpl(litConstExpr: LitConstExpr, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(litConstExpr.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.ConstPattern, parts.toArray())
    }

    static func createVarPatternImpl(name: String, comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "VarPattern") }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
        builder.buildNonTerminal(SyntaxNodeKind.VarBindingPattern, parts.toArray())
    }

    // EnumPattern: case Year(n) => ...
    static func createEnumPatternImpl(enumConstructor: SymbolRef, enumType: Option<CompositeType>,
        subPatterns: Array<Pattern>, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)

        if (let Some(e) <- enumType) {
            parts.add(e.nodeImpl)
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        parts.add(enumConstructor.nodeImpl)
        if (!subPatterns.isEmpty()) {
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
            for (i in 0..subPatterns.size) {
                parts.add(subPatterns[i].nodeImpl)
                if (i < subPatterns.size - 1) {
                    parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    parts.add(builder.buildSpace(1))
                }
            }
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        }

        builder.buildNonTerminal(SyntaxNodeKind.EnumPattern, parts.toArray())
    }

    static func createVarOrEnumPatternImpl(identifier: String, comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(identifier, "identifier", "VarOrEnumPattern") }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, identifier))
        builder.buildNonTerminal(SyntaxNodeKind.VarOrEnumPattern, parts.toArray())
    }

    // TypePattern: case x: T => ...
    static func createTypePatternImpl(subPattern: Pattern, patternType: TypeAnnotation, comments!: Array<Comment> = []) {
        if (subPattern.nodeImpl.kind != SyntaxNodeKind.WildcardPattern && subPattern.nodeImpl.kind != SyntaxNodeKind
            .VarBindingPattern) {
            throw Exception("InitException: Invalid input 'subPattern' for 'TypePattern' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(subPattern.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
        parts.add(builder.buildSpace(1))
        parts.add(patternType.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.TypePattern, parts.toArray())
    }

    /**
    * TuplePattern: case (a, b) => ...
    * @throws Exception if the input 'subPatterns' contains less than two elements.
    */
    static func createTuplePatternImpl(subPatterns: Array<Pattern>, comments!: Array<Comment> = []) {
        if (subPatterns.size <= 1) {
            throw Exception("InitException: The input 'subPatterns' must contain more than one element for 'TuplePattern' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        for (i in 0..subPatterns.size) {
            parts.add(subPatterns[i].nodeImpl)
            if (i < subPatterns.size - 1) {
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                parts.add(builder.buildSpace(1))
            }
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.TuplePattern, parts.toArray())
    }

    // WildcardPattern: case _ => ...
    static func createWildcardPatternImpl(comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.WildcardToken))
        builder.buildNonTerminal(SyntaxNodeKind.WildcardPattern, parts.toArray())
    }

    static func createAtomicTypeImpl(kind: AtomicTypeKind, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        let tokenKind = match (kind) {
            case AtomicTypeKind.BoolType => SyntaxNodeKind.BooleanToken
            case AtomicTypeKind.Float16Type => SyntaxNodeKind.Float16Token
            case AtomicTypeKind.Float32Type => SyntaxNodeKind.Float32Token
            case AtomicTypeKind.Float64Type => SyntaxNodeKind.Float64Token
            case AtomicTypeKind.Int8Type => SyntaxNodeKind.Int8Token
            case AtomicTypeKind.Int16Type => SyntaxNodeKind.Int16Token
            case AtomicTypeKind.Int32Type => SyntaxNodeKind.Int32Token
            case AtomicTypeKind.Int64Type => SyntaxNodeKind.Int64Token
            case AtomicTypeKind.IntNativeType => SyntaxNodeKind.IntNativeToken
            case AtomicTypeKind.UInt8Type => SyntaxNodeKind.UInt8Token
            case AtomicTypeKind.UInt16Type => SyntaxNodeKind.UInt16Token
            case AtomicTypeKind.UInt32Type => SyntaxNodeKind.UInt32Token
            case AtomicTypeKind.UInt64Type => SyntaxNodeKind.UInt64Token
            case AtomicTypeKind.UIntNativeType => SyntaxNodeKind.UIntNativeToken
            case AtomicTypeKind.RuneType => SyntaxNodeKind.RuneToken
            case AtomicTypeKind.UnitType => SyntaxNodeKind.UnitToken
            case AtomicTypeKind.NothingType => SyntaxNodeKind.NothingToken
            case AtomicTypeKind.ThisType => SyntaxNodeKind.ThisTypeToken
            case _ => throw Exception("InitException: Invalid input 'kind' for 'AtomicType' init.")
        }
        parts.add(builder.buildBasicTerminal(tokenKind))
        builder.buildNonTerminal(SyntaxNodeKind.PrimitiveType, parts.toArray())
    }

    static func createTupleTypeImpl(elements: Array<TypeAnnotation>, labels: Array<String>,
        comments!: Array<Comment> = []) {
        if (elements.isEmpty()) {
            throw Exception("InitException: The input 'elements' cannot be empty for 'TupleType' init.")
        }
        if (elements.size != labels.size && labels.size != 0) {
            throw Exception("InitException: The input 'elements' and 'labels' mismatch when 'TupleType' init.")
        }

        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        for (i in 0..elements.size) {
            if (labels.size != 0) {
                parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, labels[i]))
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
                parts.add(builder.buildSpace(1))
            }
            parts.add(elements[i].nodeImpl)
            if (i < elements.size - 1) {
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                parts.add(builder.buildSpace(1))
            }
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.TupleType, parts.toArray())
    }

    static func createFuncTypeImpl(paramTypes: Array<TypeAnnotation>, labels: Array<String>, retType: TypeAnnotation,
        comments!: Array<Comment> = []) {
        if (paramTypes.size != labels.size) {
            throw Exception("InitException: The input 'paramTypes' and 'labels' mismatch when 'FuncType' init.")
        }

        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)

        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        for (i in 0..labels.size) {
            parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, labels[i]))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ColonToken))
            parts.add(builder.buildSpace(1))
            parts.add(paramTypes[i].nodeImpl)
            if (i < labels.size - 1) {
                parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                parts.add(builder.buildSpace(1))
            }
        }
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.ArrowToken))
        parts.add(builder.buildSpace(1))
        parts.add(retType.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.FuncType, parts.toArray())
    }

    static func createCompositeTypeImpl(name: String, prefixes: Array<String>, typeArguments: Array<TypeAnnotation>,
        comments!: Array<Comment> = []) {
        unsafe { checkIdentifier(name, "name", "CompositeType") }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        for (i in 0..prefixes.size) {
            parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, prefixes[i]))
            parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DotToken))
        }
        parts.add(builder.buildValuedTerminal(SyntaxNodeKind.IdentToken, name))
        if (!typeArguments.isEmpty()) {
            let subParts = ArrayList<SyntaxNodeImpl>()
            subParts.add(builder.buildBasicTerminal(SyntaxNodeKind.LtToken))
            for (i in 0..typeArguments.size) {
                subParts.add(typeArguments[i].nodeImpl)
                if (i < typeArguments.size - 1) {
                    subParts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
                    subParts.add(builder.buildSpace(1))
                }
            }
            subParts.add(builder.buildBasicTerminal(SyntaxNodeKind.GtToken))
            parts.add(builder.buildNonTerminal(SyntaxNodeKind.TypeArguments, subParts.toArray()))
        }
        builder.buildNonTerminal(SyntaxNodeKind.CompositeType, parts.toArray())
    }

    static func createVArrayTypeImpl(elementType: TypeAnnotation, size: Int64, comments!: Array<Comment> = []) {
        if (size < 0) {
            throw Exception("InitException: Invalid input 'size' for 'VArrayType' init.")
        }
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.VArrayToken))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LtToken))
        parts.add(elementType.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.CommaToken))
        parts.add(builder.buildSpace(1))
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.DollarToken))
        parts.add(LitConstExpr(LitConstKind.IntergerLiteral, size.toString()).nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.GtToken))
        builder.buildNonTerminal(SyntaxNodeKind.VArrayType, parts.toArray())
    }

    static func createParenTypeImpl(subType: TypeAnnotation, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.LParenToken))
        parts.add(subType.nodeImpl)
        parts.add(builder.buildBasicTerminal(SyntaxNodeKind.RParenToken))
        builder.buildNonTerminal(SyntaxNodeKind.ParenType, parts.toArray())
    }

    static func createPrefixTypeImpl(base: TypeAnnotation, prefixOp: PrefixTypeOpKind, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        addCommentToNode(parts, comments)
        match (prefixOp) {
            case PrefixTypeOpKind.Quest => parts.add(builder.buildBasicTerminal(SyntaxNodeKind.QuestToken))
            case _ => throw Exception("InitException: Invalid input 'prefixOp' for 'PrefixType' init.")
        }
        parts.add(base.nodeImpl)
        builder.buildNonTerminal(SyntaxNodeKind.OptionType, parts.toArray())
    }

    static func createSourceFileImpl(importLists: Array<ImportList>, pkgHeader: Option<PackageHeader>,
        topLevelDecls: Array<Decl>, ftrDirective!: Option<FeaturesDirective> = None, comments!: Array<Comment> = []) {
        let builder = SyntaxNodeBuilder()
        let parts = ArrayList<SyntaxNodeImpl>()
        if (let Some(f) <- ftrDirective) {
            parts.add(f.nodeImpl)
            parts.add(builder.buildNewline(1))
        }
        if (let Some(p) <- pkgHeader) {
            parts.add(p.nodeImpl)
            parts.add(builder.buildNewline(1))
        }
        for (i in importLists) {
            parts.add(i.nodeImpl)
            parts.add(builder.buildNewline(1))
        }
        for (d in topLevelDecls) {
            parts.add(d.nodeImpl)
            parts.add(builder.buildNewline(1))
        }
        builder.buildNonTerminal(SyntaxNodeKind.File, parts.toArray())
    }
}