/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// @generated by Hermes rustgen
// DO NOT EDIT

use super::node::*;

#[repr(u32)]
#[derive(Debug, PartialEq)]
pub enum NodeKind {
    Empty,
    Metadata,
    _FunctionLikeFirst,
    Program,
    FunctionExpression,
    ArrowFunctionExpression,
    FunctionDeclaration,
    ComponentDeclaration,
    _FunctionLikeLast,
    _StatementFirst,
    _LoopStatementFirst,
    WhileStatement,
    DoWhileStatement,
    ForInStatement,
    ForOfStatement,
    ForStatement,
    _LoopStatementLast,
    DebuggerStatement,
    EmptyStatement,
    BlockStatement,
    BreakStatement,
    ContinueStatement,
    ThrowStatement,
    ReturnStatement,
    WithStatement,
    SwitchStatement,
    LabeledStatement,
    ExpressionStatement,
    TryStatement,
    IfStatement,
    _StatementLast,
    NullLiteral,
    BooleanLiteral,
    StringLiteral,
    NumericLiteral,
    RegExpLiteral,
    BigIntLiteral,
    ThisExpression,
    Super,
    SequenceExpression,
    ObjectExpression,
    ArrayExpression,
    SpreadElement,
    NewExpression,
    YieldExpression,
    AwaitExpression,
    ImportExpression,
    _CallExpressionLikeFirst,
    CallExpression,
    OptionalCallExpression,
    _CallExpressionLikeLast,
    AssignmentExpression,
    UnaryExpression,
    UpdateExpression,
    _MemberExpressionLikeFirst,
    MemberExpression,
    OptionalMemberExpression,
    _MemberExpressionLikeLast,
    LogicalExpression,
    ConditionalExpression,
    BinaryExpression,
    Directive,
    DirectiveLiteral,
    Identifier,
    PrivateName,
    MetaProperty,
    SwitchCase,
    CatchClause,
    VariableDeclarator,
    VariableDeclaration,
    TemplateLiteral,
    TaggedTemplateExpression,
    TemplateElement,
    Property,
    ClassDeclaration,
    ClassExpression,
    ClassBody,
    ClassProperty,
    ClassPrivateProperty,
    MethodDefinition,
    ImportDeclaration,
    ImportSpecifier,
    ImportDefaultSpecifier,
    ImportNamespaceSpecifier,
    ImportAttribute,
    ExportNamedDeclaration,
    ExportSpecifier,
    ExportNamespaceSpecifier,
    ExportDefaultDeclaration,
    ExportAllDeclaration,
    _PatternFirst,
    ObjectPattern,
    ArrayPattern,
    RestElement,
    AssignmentPattern,
    _PatternLast,
    JSXIdentifier,
    JSXMemberExpression,
    JSXNamespacedName,
    JSXEmptyExpression,
    JSXExpressionContainer,
    JSXSpreadChild,
    JSXOpeningElement,
    JSXClosingElement,
    JSXAttribute,
    JSXSpreadAttribute,
    JSXStringLiteral,
    JSXText,
    JSXElement,
    JSXFragment,
    JSXOpeningFragment,
    JSXClosingFragment,
    ExistsTypeAnnotation,
    EmptyTypeAnnotation,
    StringTypeAnnotation,
    NumberTypeAnnotation,
    StringLiteralTypeAnnotation,
    NumberLiteralTypeAnnotation,
    BigIntLiteralTypeAnnotation,
    BooleanTypeAnnotation,
    BooleanLiteralTypeAnnotation,
    NullLiteralTypeAnnotation,
    SymbolTypeAnnotation,
    AnyTypeAnnotation,
    MixedTypeAnnotation,
    BigIntTypeAnnotation,
    VoidTypeAnnotation,
    FunctionTypeAnnotation,
    FunctionTypeParam,
    ComponentTypeAnnotation,
    ComponentTypeParameter,
    NullableTypeAnnotation,
    QualifiedTypeIdentifier,
    TypeofTypeAnnotation,
    KeyofTypeAnnotation,
    QualifiedTypeofIdentifier,
    TupleTypeAnnotation,
    TupleTypeSpreadElement,
    TupleTypeLabeledElement,
    ArrayTypeAnnotation,
    InferTypeAnnotation,
    UnionTypeAnnotation,
    IntersectionTypeAnnotation,
    GenericTypeAnnotation,
    IndexedAccessType,
    OptionalIndexedAccessType,
    ConditionalTypeAnnotation,
    TypePredicate,
    InterfaceTypeAnnotation,
    TypeAlias,
    OpaqueType,
    InterfaceDeclaration,
    DeclareTypeAlias,
    DeclareOpaqueType,
    DeclareInterface,
    DeclareClass,
    DeclareFunction,
    DeclareComponent,
    DeclareVariable,
    DeclareEnum,
    DeclareExportDeclaration,
    DeclareExportAllDeclaration,
    DeclareModule,
    DeclareModuleExports,
    InterfaceExtends,
    ClassImplements,
    TypeAnnotation,
    ObjectTypeAnnotation,
    ObjectTypeProperty,
    ObjectTypeSpreadProperty,
    ObjectTypeInternalSlot,
    ObjectTypeCallProperty,
    ObjectTypeIndexer,
    ObjectTypeMappedTypeProperty,
    Variance,
    TypeParameterDeclaration,
    TypeParameter,
    TypeParameterInstantiation,
    TypeCastExpression,
    InferredPredicate,
    DeclaredPredicate,
    EnumDeclaration,
    EnumStringBody,
    EnumNumberBody,
    EnumBooleanBody,
    EnumSymbolBody,
    EnumDefaultedMember,
    EnumStringMember,
    EnumNumberMember,
    EnumBooleanMember,
    ComponentParameter,
    TSTypeAnnotation,
    TSAnyKeyword,
    TSNumberKeyword,
    TSBooleanKeyword,
    TSStringKeyword,
    TSSymbolKeyword,
    TSVoidKeyword,
    TSThisType,
    TSLiteralType,
    TSIndexedAccessType,
    TSArrayType,
    TSTypeReference,
    TSQualifiedName,
    TSFunctionType,
    TSConstructorType,
    TSTypePredicate,
    TSTupleType,
    TSTypeAssertion,
    TSAsExpression,
    TSParameterProperty,
    TSTypeAliasDeclaration,
    TSInterfaceDeclaration,
    TSInterfaceHeritage,
    TSInterfaceBody,
    TSEnumDeclaration,
    TSEnumMember,
    TSModuleDeclaration,
    TSModuleBlock,
    TSModuleMember,
    TSTypeParameterDeclaration,
    TSTypeParameter,
    TSTypeParameterInstantiation,
    TSUnionType,
    TSIntersectionType,
    TSTypeQuery,
    TSConditionalType,
    TSTypeLiteral,
    TSPropertySignature,
    TSMethodSignature,
    TSIndexSignature,
    TSCallSignatureDeclaration,
    TSModifiers,
    _CoverFirst,
    CoverEmptyArgs,
    CoverTrailingComma,
    CoverInitializer,
    CoverRestElement,
    CoverTypedIdentifier,
    _CoverLast,
}

extern "C" {
    // Program
    pub fn hermes_get_Program_body(node: NodePtr) -> NodeListRef;
    // FunctionExpression
    pub fn hermes_get_FunctionExpression_id(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionExpression_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_FunctionExpression_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_FunctionExpression_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionExpression_returnType(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionExpression_predicate(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionExpression_generator(node: NodePtr) -> bool;
    pub fn hermes_get_FunctionExpression_async(node: NodePtr) -> bool;
    // ArrowFunctionExpression
    pub fn hermes_get_ArrowFunctionExpression_id(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ArrowFunctionExpression_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ArrowFunctionExpression_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ArrowFunctionExpression_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ArrowFunctionExpression_returnType(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ArrowFunctionExpression_predicate(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ArrowFunctionExpression_expression(node: NodePtr) -> bool;
    pub fn hermes_get_ArrowFunctionExpression_async(node: NodePtr) -> bool;
    // FunctionDeclaration
    pub fn hermes_get_FunctionDeclaration_id(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionDeclaration_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_FunctionDeclaration_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_FunctionDeclaration_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionDeclaration_returnType(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionDeclaration_predicate(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionDeclaration_generator(node: NodePtr) -> bool;
    pub fn hermes_get_FunctionDeclaration_async(node: NodePtr) -> bool;
    // ComponentDeclaration
    pub fn hermes_get_ComponentDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ComponentDeclaration_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ComponentDeclaration_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ComponentDeclaration_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ComponentDeclaration_rendersType(node: NodePtr) -> NodePtrOpt;
    // WhileStatement
    pub fn hermes_get_WhileStatement_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_WhileStatement_test(node: NodePtr) -> NodePtr;
    // DoWhileStatement
    pub fn hermes_get_DoWhileStatement_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DoWhileStatement_test(node: NodePtr) -> NodePtr;
    // ForInStatement
    pub fn hermes_get_ForInStatement_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ForInStatement_right(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ForInStatement_body(node: NodePtr) -> NodePtr;
    // ForOfStatement
    pub fn hermes_get_ForOfStatement_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ForOfStatement_right(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ForOfStatement_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ForOfStatement_await(node: NodePtr) -> bool;
    // ForStatement
    pub fn hermes_get_ForStatement_init(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ForStatement_test(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ForStatement_update(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ForStatement_body(node: NodePtr) -> NodePtr;
    // BlockStatement
    pub fn hermes_get_BlockStatement_body(node: NodePtr) -> NodeListRef;
    // BreakStatement
    pub fn hermes_get_BreakStatement_label(node: NodePtr) -> NodePtrOpt;
    // ContinueStatement
    pub fn hermes_get_ContinueStatement_label(node: NodePtr) -> NodePtrOpt;
    // ThrowStatement
    pub fn hermes_get_ThrowStatement_argument(node: NodePtr) -> NodePtr;
    // ReturnStatement
    pub fn hermes_get_ReturnStatement_argument(node: NodePtr) -> NodePtrOpt;
    // WithStatement
    pub fn hermes_get_WithStatement_object(node: NodePtr) -> NodePtr;
    pub fn hermes_get_WithStatement_body(node: NodePtr) -> NodePtr;
    // SwitchStatement
    pub fn hermes_get_SwitchStatement_discriminant(node: NodePtr) -> NodePtr;
    pub fn hermes_get_SwitchStatement_cases(node: NodePtr) -> NodeListRef;
    // LabeledStatement
    pub fn hermes_get_LabeledStatement_label(node: NodePtr) -> NodePtr;
    pub fn hermes_get_LabeledStatement_body(node: NodePtr) -> NodePtr;
    // ExpressionStatement
    pub fn hermes_get_ExpressionStatement_expression(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ExpressionStatement_directive(node: NodePtr) -> NodeStringOpt;
    // TryStatement
    pub fn hermes_get_TryStatement_block(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TryStatement_handler(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TryStatement_finalizer(node: NodePtr) -> NodePtrOpt;
    // IfStatement
    pub fn hermes_get_IfStatement_test(node: NodePtr) -> NodePtr;
    pub fn hermes_get_IfStatement_consequent(node: NodePtr) -> NodePtr;
    pub fn hermes_get_IfStatement_alternate(node: NodePtr) -> NodePtrOpt;
    // BooleanLiteral
    pub fn hermes_get_BooleanLiteral_value(node: NodePtr) -> bool;
    // StringLiteral
    pub fn hermes_get_StringLiteral_value(node: NodePtr) -> NodeString;
    // NumericLiteral
    pub fn hermes_get_NumericLiteral_value(node: NodePtr) -> f64;
    // RegExpLiteral
    pub fn hermes_get_RegExpLiteral_pattern(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_RegExpLiteral_flags(node: NodePtr) -> NodeLabel;
    // BigIntLiteral
    pub fn hermes_get_BigIntLiteral_bigint(node: NodePtr) -> NodeLabel;
    // SequenceExpression
    pub fn hermes_get_SequenceExpression_expressions(node: NodePtr) -> NodeListRef;
    // ObjectExpression
    pub fn hermes_get_ObjectExpression_properties(node: NodePtr) -> NodeListRef;
    // ArrayExpression
    pub fn hermes_get_ArrayExpression_elements(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ArrayExpression_trailingComma(node: NodePtr) -> bool;
    // SpreadElement
    pub fn hermes_get_SpreadElement_argument(node: NodePtr) -> NodePtr;
    // NewExpression
    pub fn hermes_get_NewExpression_callee(node: NodePtr) -> NodePtr;
    pub fn hermes_get_NewExpression_typeArguments(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_NewExpression_arguments(node: NodePtr) -> NodeListRef;
    // YieldExpression
    pub fn hermes_get_YieldExpression_argument(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_YieldExpression_delegate(node: NodePtr) -> bool;
    // AwaitExpression
    pub fn hermes_get_AwaitExpression_argument(node: NodePtr) -> NodePtr;
    // ImportExpression
    pub fn hermes_get_ImportExpression_source(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ImportExpression_attributes(node: NodePtr) -> NodePtrOpt;
    // CallExpression
    pub fn hermes_get_CallExpression_callee(node: NodePtr) -> NodePtr;
    pub fn hermes_get_CallExpression_typeArguments(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_CallExpression_arguments(node: NodePtr) -> NodeListRef;
    // OptionalCallExpression
    pub fn hermes_get_OptionalCallExpression_callee(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OptionalCallExpression_typeArguments(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_OptionalCallExpression_arguments(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_OptionalCallExpression_optional(node: NodePtr) -> bool;
    // AssignmentExpression
    pub fn hermes_get_AssignmentExpression_operator(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_AssignmentExpression_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_AssignmentExpression_right(node: NodePtr) -> NodePtr;
    // UnaryExpression
    pub fn hermes_get_UnaryExpression_operator(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_UnaryExpression_argument(node: NodePtr) -> NodePtr;
    pub fn hermes_get_UnaryExpression_prefix(node: NodePtr) -> bool;
    // UpdateExpression
    pub fn hermes_get_UpdateExpression_operator(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_UpdateExpression_argument(node: NodePtr) -> NodePtr;
    pub fn hermes_get_UpdateExpression_prefix(node: NodePtr) -> bool;
    // MemberExpression
    pub fn hermes_get_MemberExpression_object(node: NodePtr) -> NodePtr;
    pub fn hermes_get_MemberExpression_property(node: NodePtr) -> NodePtr;
    pub fn hermes_get_MemberExpression_computed(node: NodePtr) -> bool;
    // OptionalMemberExpression
    pub fn hermes_get_OptionalMemberExpression_object(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OptionalMemberExpression_property(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OptionalMemberExpression_computed(node: NodePtr) -> bool;
    pub fn hermes_get_OptionalMemberExpression_optional(node: NodePtr) -> bool;
    // LogicalExpression
    pub fn hermes_get_LogicalExpression_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_LogicalExpression_right(node: NodePtr) -> NodePtr;
    pub fn hermes_get_LogicalExpression_operator(node: NodePtr) -> NodeLabel;
    // ConditionalExpression
    pub fn hermes_get_ConditionalExpression_test(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ConditionalExpression_alternate(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ConditionalExpression_consequent(node: NodePtr) -> NodePtr;
    // BinaryExpression
    pub fn hermes_get_BinaryExpression_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_BinaryExpression_right(node: NodePtr) -> NodePtr;
    pub fn hermes_get_BinaryExpression_operator(node: NodePtr) -> NodeLabel;
    // Directive
    pub fn hermes_get_Directive_value(node: NodePtr) -> NodePtr;
    // DirectiveLiteral
    pub fn hermes_get_DirectiveLiteral_value(node: NodePtr) -> NodeString;
    // Identifier
    pub fn hermes_get_Identifier_name(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_Identifier_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_Identifier_optional(node: NodePtr) -> bool;
    // PrivateName
    pub fn hermes_get_PrivateName_id(node: NodePtr) -> NodePtr;
    // MetaProperty
    pub fn hermes_get_MetaProperty_meta(node: NodePtr) -> NodePtr;
    pub fn hermes_get_MetaProperty_property(node: NodePtr) -> NodePtr;
    // SwitchCase
    pub fn hermes_get_SwitchCase_test(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_SwitchCase_consequent(node: NodePtr) -> NodeListRef;
    // CatchClause
    pub fn hermes_get_CatchClause_param(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_CatchClause_body(node: NodePtr) -> NodePtr;
    // VariableDeclarator
    pub fn hermes_get_VariableDeclarator_init(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_VariableDeclarator_id(node: NodePtr) -> NodePtr;
    // VariableDeclaration
    pub fn hermes_get_VariableDeclaration_kind(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_VariableDeclaration_declarations(node: NodePtr) -> NodeListRef;
    // TemplateLiteral
    pub fn hermes_get_TemplateLiteral_quasis(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TemplateLiteral_expressions(node: NodePtr) -> NodeListRef;
    // TaggedTemplateExpression
    pub fn hermes_get_TaggedTemplateExpression_tag(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TaggedTemplateExpression_quasi(node: NodePtr) -> NodePtr;
    // TemplateElement
    pub fn hermes_get_TemplateElement_tail(node: NodePtr) -> bool;
    pub fn hermes_get_TemplateElement_cooked(node: NodePtr) -> NodeStringOpt;
    pub fn hermes_get_TemplateElement_raw(node: NodePtr) -> NodeLabel;
    // Property
    pub fn hermes_get_Property_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_Property_value(node: NodePtr) -> NodePtr;
    pub fn hermes_get_Property_kind(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_Property_computed(node: NodePtr) -> bool;
    pub fn hermes_get_Property_method(node: NodePtr) -> bool;
    pub fn hermes_get_Property_shorthand(node: NodePtr) -> bool;
    // ClassDeclaration
    pub fn hermes_get_ClassDeclaration_id(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassDeclaration_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassDeclaration_superClass(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassDeclaration_superTypeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassDeclaration_implements(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ClassDeclaration_decorators(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ClassDeclaration_body(node: NodePtr) -> NodePtr;
    // ClassExpression
    pub fn hermes_get_ClassExpression_id(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassExpression_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassExpression_superClass(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassExpression_superTypeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassExpression_implements(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ClassExpression_decorators(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ClassExpression_body(node: NodePtr) -> NodePtr;
    // ClassBody
    pub fn hermes_get_ClassBody_body(node: NodePtr) -> NodeListRef;
    // ClassProperty
    pub fn hermes_get_ClassProperty_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ClassProperty_value(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassProperty_computed(node: NodePtr) -> bool;
    pub fn hermes_get_ClassProperty_static(node: NodePtr) -> bool;
    pub fn hermes_get_ClassProperty_declare(node: NodePtr) -> bool;
    pub fn hermes_get_ClassProperty_optional(node: NodePtr) -> bool;
    pub fn hermes_get_ClassProperty_variance(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassProperty_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassProperty_tsModifiers(node: NodePtr) -> NodePtrOpt;
    // ClassPrivateProperty
    pub fn hermes_get_ClassPrivateProperty_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ClassPrivateProperty_value(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassPrivateProperty_static(node: NodePtr) -> bool;
    pub fn hermes_get_ClassPrivateProperty_declare(node: NodePtr) -> bool;
    pub fn hermes_get_ClassPrivateProperty_optional(node: NodePtr) -> bool;
    pub fn hermes_get_ClassPrivateProperty_variance(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassPrivateProperty_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ClassPrivateProperty_tsModifiers(node: NodePtr) -> NodePtrOpt;
    // MethodDefinition
    pub fn hermes_get_MethodDefinition_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_MethodDefinition_value(node: NodePtr) -> NodePtr;
    pub fn hermes_get_MethodDefinition_kind(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_MethodDefinition_computed(node: NodePtr) -> bool;
    pub fn hermes_get_MethodDefinition_static(node: NodePtr) -> bool;
    // ImportDeclaration
    pub fn hermes_get_ImportDeclaration_specifiers(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ImportDeclaration_source(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ImportDeclaration_assertions(node: NodePtr) -> NodeListOptRef;
    pub fn hermes_get_ImportDeclaration_importKind(node: NodePtr) -> NodeLabel;
    // ImportSpecifier
    pub fn hermes_get_ImportSpecifier_imported(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ImportSpecifier_local(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ImportSpecifier_importKind(node: NodePtr) -> NodeLabel;
    // ImportDefaultSpecifier
    pub fn hermes_get_ImportDefaultSpecifier_local(node: NodePtr) -> NodePtr;
    // ImportNamespaceSpecifier
    pub fn hermes_get_ImportNamespaceSpecifier_local(node: NodePtr) -> NodePtr;
    // ImportAttribute
    pub fn hermes_get_ImportAttribute_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ImportAttribute_value(node: NodePtr) -> NodePtr;
    // ExportNamedDeclaration
    pub fn hermes_get_ExportNamedDeclaration_declaration(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ExportNamedDeclaration_specifiers(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ExportNamedDeclaration_source(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ExportNamedDeclaration_exportKind(node: NodePtr) -> NodeLabel;
    // ExportSpecifier
    pub fn hermes_get_ExportSpecifier_exported(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ExportSpecifier_local(node: NodePtr) -> NodePtr;
    // ExportNamespaceSpecifier
    pub fn hermes_get_ExportNamespaceSpecifier_exported(node: NodePtr) -> NodePtr;
    // ExportDefaultDeclaration
    pub fn hermes_get_ExportDefaultDeclaration_declaration(node: NodePtr) -> NodePtr;
    // ExportAllDeclaration
    pub fn hermes_get_ExportAllDeclaration_source(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ExportAllDeclaration_exportKind(node: NodePtr) -> NodeLabel;
    // ObjectPattern
    pub fn hermes_get_ObjectPattern_properties(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ObjectPattern_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    // ArrayPattern
    pub fn hermes_get_ArrayPattern_elements(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ArrayPattern_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    // RestElement
    pub fn hermes_get_RestElement_argument(node: NodePtr) -> NodePtr;
    // AssignmentPattern
    pub fn hermes_get_AssignmentPattern_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_AssignmentPattern_right(node: NodePtr) -> NodePtr;
    // JSXIdentifier
    pub fn hermes_get_JSXIdentifier_name(node: NodePtr) -> NodeLabel;
    // JSXMemberExpression
    pub fn hermes_get_JSXMemberExpression_object(node: NodePtr) -> NodePtr;
    pub fn hermes_get_JSXMemberExpression_property(node: NodePtr) -> NodePtr;
    // JSXNamespacedName
    pub fn hermes_get_JSXNamespacedName_namespace(node: NodePtr) -> NodePtr;
    pub fn hermes_get_JSXNamespacedName_name(node: NodePtr) -> NodePtr;
    // JSXExpressionContainer
    pub fn hermes_get_JSXExpressionContainer_expression(node: NodePtr) -> NodePtr;
    // JSXSpreadChild
    pub fn hermes_get_JSXSpreadChild_expression(node: NodePtr) -> NodePtr;
    // JSXOpeningElement
    pub fn hermes_get_JSXOpeningElement_name(node: NodePtr) -> NodePtr;
    pub fn hermes_get_JSXOpeningElement_attributes(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_JSXOpeningElement_selfClosing(node: NodePtr) -> bool;
    pub fn hermes_get_JSXOpeningElement_typeArguments(node: NodePtr) -> NodePtrOpt;
    // JSXClosingElement
    pub fn hermes_get_JSXClosingElement_name(node: NodePtr) -> NodePtr;
    // JSXAttribute
    pub fn hermes_get_JSXAttribute_name(node: NodePtr) -> NodePtr;
    pub fn hermes_get_JSXAttribute_value(node: NodePtr) -> NodePtrOpt;
    // JSXSpreadAttribute
    pub fn hermes_get_JSXSpreadAttribute_argument(node: NodePtr) -> NodePtr;
    // JSXStringLiteral
    pub fn hermes_get_JSXStringLiteral_value(node: NodePtr) -> NodeString;
    pub fn hermes_get_JSXStringLiteral_raw(node: NodePtr) -> NodeLabel;
    // JSXText
    pub fn hermes_get_JSXText_value(node: NodePtr) -> NodeString;
    pub fn hermes_get_JSXText_raw(node: NodePtr) -> NodeLabel;
    // JSXElement
    pub fn hermes_get_JSXElement_openingElement(node: NodePtr) -> NodePtr;
    pub fn hermes_get_JSXElement_children(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_JSXElement_closingElement(node: NodePtr) -> NodePtrOpt;
    // JSXFragment
    pub fn hermes_get_JSXFragment_openingFragment(node: NodePtr) -> NodePtr;
    pub fn hermes_get_JSXFragment_children(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_JSXFragment_closingFragment(node: NodePtr) -> NodePtr;
    // StringLiteralTypeAnnotation
    pub fn hermes_get_StringLiteralTypeAnnotation_value(node: NodePtr) -> NodeString;
    pub fn hermes_get_StringLiteralTypeAnnotation_raw(node: NodePtr) -> NodeString;
    // NumberLiteralTypeAnnotation
    pub fn hermes_get_NumberLiteralTypeAnnotation_value(node: NodePtr) -> f64;
    pub fn hermes_get_NumberLiteralTypeAnnotation_raw(node: NodePtr) -> NodeLabel;
    // BigIntLiteralTypeAnnotation
    pub fn hermes_get_BigIntLiteralTypeAnnotation_raw(node: NodePtr) -> NodeLabel;
    // BooleanLiteralTypeAnnotation
    pub fn hermes_get_BooleanLiteralTypeAnnotation_value(node: NodePtr) -> bool;
    pub fn hermes_get_BooleanLiteralTypeAnnotation_raw(node: NodePtr) -> NodeLabel;
    // FunctionTypeAnnotation
    pub fn hermes_get_FunctionTypeAnnotation_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_FunctionTypeAnnotation_this(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionTypeAnnotation_returnType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_FunctionTypeAnnotation_rest(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionTypeAnnotation_typeParameters(node: NodePtr) -> NodePtrOpt;
    // FunctionTypeParam
    pub fn hermes_get_FunctionTypeParam_name(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_FunctionTypeParam_typeAnnotation(node: NodePtr) -> NodePtr;
    pub fn hermes_get_FunctionTypeParam_optional(node: NodePtr) -> bool;
    // ComponentTypeAnnotation
    pub fn hermes_get_ComponentTypeAnnotation_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ComponentTypeAnnotation_rest(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ComponentTypeAnnotation_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ComponentTypeAnnotation_rendersType(node: NodePtr) -> NodePtrOpt;
    // ComponentTypeParameter
    pub fn hermes_get_ComponentTypeParameter_name(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ComponentTypeParameter_typeAnnotation(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ComponentTypeParameter_optional(node: NodePtr) -> bool;
    // NullableTypeAnnotation
    pub fn hermes_get_NullableTypeAnnotation_typeAnnotation(node: NodePtr) -> NodePtr;
    // QualifiedTypeIdentifier
    pub fn hermes_get_QualifiedTypeIdentifier_qualification(node: NodePtr) -> NodePtr;
    pub fn hermes_get_QualifiedTypeIdentifier_id(node: NodePtr) -> NodePtr;
    // TypeofTypeAnnotation
    pub fn hermes_get_TypeofTypeAnnotation_argument(node: NodePtr) -> NodePtr;
    // KeyofTypeAnnotation
    pub fn hermes_get_KeyofTypeAnnotation_argument(node: NodePtr) -> NodePtr;
    // QualifiedTypeofIdentifier
    pub fn hermes_get_QualifiedTypeofIdentifier_qualification(node: NodePtr) -> NodePtr;
    pub fn hermes_get_QualifiedTypeofIdentifier_id(node: NodePtr) -> NodePtr;
    // TupleTypeAnnotation
    pub fn hermes_get_TupleTypeAnnotation_types(node: NodePtr) -> NodeListRef;
    // TupleTypeSpreadElement
    pub fn hermes_get_TupleTypeSpreadElement_label(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TupleTypeSpreadElement_typeAnnotation(node: NodePtr) -> NodePtr;
    // TupleTypeLabeledElement
    pub fn hermes_get_TupleTypeLabeledElement_label(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TupleTypeLabeledElement_elementType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TupleTypeLabeledElement_optional(node: NodePtr) -> bool;
    pub fn hermes_get_TupleTypeLabeledElement_variance(node: NodePtr) -> NodePtrOpt;
    // ArrayTypeAnnotation
    pub fn hermes_get_ArrayTypeAnnotation_elementType(node: NodePtr) -> NodePtr;
    // InferTypeAnnotation
    pub fn hermes_get_InferTypeAnnotation_typeParameter(node: NodePtr) -> NodePtr;
    // UnionTypeAnnotation
    pub fn hermes_get_UnionTypeAnnotation_types(node: NodePtr) -> NodeListRef;
    // IntersectionTypeAnnotation
    pub fn hermes_get_IntersectionTypeAnnotation_types(node: NodePtr) -> NodeListRef;
    // GenericTypeAnnotation
    pub fn hermes_get_GenericTypeAnnotation_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_GenericTypeAnnotation_typeParameters(node: NodePtr) -> NodePtrOpt;
    // IndexedAccessType
    pub fn hermes_get_IndexedAccessType_objectType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_IndexedAccessType_indexType(node: NodePtr) -> NodePtr;
    // OptionalIndexedAccessType
    pub fn hermes_get_OptionalIndexedAccessType_objectType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OptionalIndexedAccessType_indexType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OptionalIndexedAccessType_optional(node: NodePtr) -> bool;
    // ConditionalTypeAnnotation
    pub fn hermes_get_ConditionalTypeAnnotation_checkType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ConditionalTypeAnnotation_extendsType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ConditionalTypeAnnotation_trueType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ConditionalTypeAnnotation_falseType(node: NodePtr) -> NodePtr;
    // TypePredicate
    pub fn hermes_get_TypePredicate_parameterName(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TypePredicate_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TypePredicate_asserts(node: NodePtr) -> bool;
    // InterfaceTypeAnnotation
    pub fn hermes_get_InterfaceTypeAnnotation_extends(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_InterfaceTypeAnnotation_body(node: NodePtr) -> NodePtrOpt;
    // TypeAlias
    pub fn hermes_get_TypeAlias_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TypeAlias_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TypeAlias_right(node: NodePtr) -> NodePtr;
    // OpaqueType
    pub fn hermes_get_OpaqueType_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OpaqueType_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_OpaqueType_impltype(node: NodePtr) -> NodePtr;
    pub fn hermes_get_OpaqueType_supertype(node: NodePtr) -> NodePtrOpt;
    // InterfaceDeclaration
    pub fn hermes_get_InterfaceDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_InterfaceDeclaration_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_InterfaceDeclaration_extends(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_InterfaceDeclaration_body(node: NodePtr) -> NodePtr;
    // DeclareTypeAlias
    pub fn hermes_get_DeclareTypeAlias_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareTypeAlias_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareTypeAlias_right(node: NodePtr) -> NodePtr;
    // DeclareOpaqueType
    pub fn hermes_get_DeclareOpaqueType_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareOpaqueType_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareOpaqueType_impltype(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareOpaqueType_supertype(node: NodePtr) -> NodePtrOpt;
    // DeclareInterface
    pub fn hermes_get_DeclareInterface_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareInterface_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareInterface_extends(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_DeclareInterface_body(node: NodePtr) -> NodePtr;
    // DeclareClass
    pub fn hermes_get_DeclareClass_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareClass_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareClass_extends(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_DeclareClass_implements(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_DeclareClass_mixins(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_DeclareClass_body(node: NodePtr) -> NodePtr;
    // DeclareFunction
    pub fn hermes_get_DeclareFunction_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareFunction_predicate(node: NodePtr) -> NodePtrOpt;
    // DeclareComponent
    pub fn hermes_get_DeclareComponent_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareComponent_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_DeclareComponent_rest(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareComponent_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareComponent_rendersType(node: NodePtr) -> NodePtrOpt;
    // DeclareVariable
    pub fn hermes_get_DeclareVariable_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareVariable_kind(node: NodePtr) -> NodeLabel;
    // DeclareEnum
    pub fn hermes_get_DeclareEnum_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareEnum_body(node: NodePtr) -> NodePtr;
    // DeclareExportDeclaration
    pub fn hermes_get_DeclareExportDeclaration_declaration(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareExportDeclaration_specifiers(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_DeclareExportDeclaration_source(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_DeclareExportDeclaration_default(node: NodePtr) -> bool;
    // DeclareExportAllDeclaration
    pub fn hermes_get_DeclareExportAllDeclaration_source(node: NodePtr) -> NodePtr;
    // DeclareModule
    pub fn hermes_get_DeclareModule_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareModule_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_DeclareModule_kind(node: NodePtr) -> NodeLabel;
    // DeclareModuleExports
    pub fn hermes_get_DeclareModuleExports_typeAnnotation(node: NodePtr) -> NodePtr;
    // InterfaceExtends
    pub fn hermes_get_InterfaceExtends_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_InterfaceExtends_typeParameters(node: NodePtr) -> NodePtrOpt;
    // ClassImplements
    pub fn hermes_get_ClassImplements_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ClassImplements_typeParameters(node: NodePtr) -> NodePtrOpt;
    // TypeAnnotation
    pub fn hermes_get_TypeAnnotation_typeAnnotation(node: NodePtr) -> NodePtr;
    // ObjectTypeAnnotation
    pub fn hermes_get_ObjectTypeAnnotation_properties(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ObjectTypeAnnotation_indexers(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ObjectTypeAnnotation_callProperties(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ObjectTypeAnnotation_internalSlots(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_ObjectTypeAnnotation_inexact(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeAnnotation_exact(node: NodePtr) -> bool;
    // ObjectTypeProperty
    pub fn hermes_get_ObjectTypeProperty_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeProperty_value(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeProperty_method(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeProperty_optional(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeProperty_static(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeProperty_proto(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeProperty_variance(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ObjectTypeProperty_kind(node: NodePtr) -> NodeLabel;
    // ObjectTypeSpreadProperty
    pub fn hermes_get_ObjectTypeSpreadProperty_argument(node: NodePtr) -> NodePtr;
    // ObjectTypeInternalSlot
    pub fn hermes_get_ObjectTypeInternalSlot_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeInternalSlot_value(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeInternalSlot_optional(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeInternalSlot_static(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeInternalSlot_method(node: NodePtr) -> bool;
    // ObjectTypeCallProperty
    pub fn hermes_get_ObjectTypeCallProperty_value(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeCallProperty_static(node: NodePtr) -> bool;
    // ObjectTypeIndexer
    pub fn hermes_get_ObjectTypeIndexer_id(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ObjectTypeIndexer_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeIndexer_value(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeIndexer_static(node: NodePtr) -> bool;
    pub fn hermes_get_ObjectTypeIndexer_variance(node: NodePtr) -> NodePtrOpt;
    // ObjectTypeMappedTypeProperty
    pub fn hermes_get_ObjectTypeMappedTypeProperty_keyTparam(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeMappedTypeProperty_propType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeMappedTypeProperty_sourceType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ObjectTypeMappedTypeProperty_variance(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_ObjectTypeMappedTypeProperty_optional(node: NodePtr) -> NodeStringOpt;
    // Variance
    pub fn hermes_get_Variance_kind(node: NodePtr) -> NodeLabel;
    // TypeParameterDeclaration
    pub fn hermes_get_TypeParameterDeclaration_params(node: NodePtr) -> NodeListRef;
    // TypeParameter
    pub fn hermes_get_TypeParameter_name(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_TypeParameter_bound(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TypeParameter_variance(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TypeParameter_default(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TypeParameter_usesExtendsBound(node: NodePtr) -> bool;
    // TypeParameterInstantiation
    pub fn hermes_get_TypeParameterInstantiation_params(node: NodePtr) -> NodeListRef;
    // TypeCastExpression
    pub fn hermes_get_TypeCastExpression_expression(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TypeCastExpression_typeAnnotation(node: NodePtr) -> NodePtr;
    // DeclaredPredicate
    pub fn hermes_get_DeclaredPredicate_value(node: NodePtr) -> NodePtr;
    // EnumDeclaration
    pub fn hermes_get_EnumDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_EnumDeclaration_body(node: NodePtr) -> NodePtr;
    // EnumStringBody
    pub fn hermes_get_EnumStringBody_members(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_EnumStringBody_explicitType(node: NodePtr) -> bool;
    pub fn hermes_get_EnumStringBody_hasUnknownMembers(node: NodePtr) -> bool;
    // EnumNumberBody
    pub fn hermes_get_EnumNumberBody_members(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_EnumNumberBody_explicitType(node: NodePtr) -> bool;
    pub fn hermes_get_EnumNumberBody_hasUnknownMembers(node: NodePtr) -> bool;
    // EnumBooleanBody
    pub fn hermes_get_EnumBooleanBody_members(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_EnumBooleanBody_explicitType(node: NodePtr) -> bool;
    pub fn hermes_get_EnumBooleanBody_hasUnknownMembers(node: NodePtr) -> bool;
    // EnumSymbolBody
    pub fn hermes_get_EnumSymbolBody_members(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_EnumSymbolBody_hasUnknownMembers(node: NodePtr) -> bool;
    // EnumDefaultedMember
    pub fn hermes_get_EnumDefaultedMember_id(node: NodePtr) -> NodePtr;
    // EnumStringMember
    pub fn hermes_get_EnumStringMember_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_EnumStringMember_init(node: NodePtr) -> NodePtr;
    // EnumNumberMember
    pub fn hermes_get_EnumNumberMember_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_EnumNumberMember_init(node: NodePtr) -> NodePtr;
    // EnumBooleanMember
    pub fn hermes_get_EnumBooleanMember_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_EnumBooleanMember_init(node: NodePtr) -> NodePtr;
    // ComponentParameter
    pub fn hermes_get_ComponentParameter_name(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ComponentParameter_local(node: NodePtr) -> NodePtr;
    pub fn hermes_get_ComponentParameter_shorthand(node: NodePtr) -> bool;
    // TSTypeAnnotation
    pub fn hermes_get_TSTypeAnnotation_typeAnnotation(node: NodePtr) -> NodePtr;
    // TSLiteralType
    pub fn hermes_get_TSLiteralType_literal(node: NodePtr) -> NodePtr;
    // TSIndexedAccessType
    pub fn hermes_get_TSIndexedAccessType_objectType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSIndexedAccessType_indexType(node: NodePtr) -> NodePtr;
    // TSArrayType
    pub fn hermes_get_TSArrayType_elementType(node: NodePtr) -> NodePtr;
    // TSTypeReference
    pub fn hermes_get_TSTypeReference_typeName(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSTypeReference_typeParameters(node: NodePtr) -> NodePtrOpt;
    // TSQualifiedName
    pub fn hermes_get_TSQualifiedName_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSQualifiedName_right(node: NodePtr) -> NodePtrOpt;
    // TSFunctionType
    pub fn hermes_get_TSFunctionType_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TSFunctionType_returnType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSFunctionType_typeParameters(node: NodePtr) -> NodePtrOpt;
    // TSConstructorType
    pub fn hermes_get_TSConstructorType_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TSConstructorType_returnType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSConstructorType_typeParameters(node: NodePtr) -> NodePtrOpt;
    // TSTypePredicate
    pub fn hermes_get_TSTypePredicate_parameterName(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSTypePredicate_typeAnnotation(node: NodePtr) -> NodePtr;
    // TSTupleType
    pub fn hermes_get_TSTupleType_elementTypes(node: NodePtr) -> NodeListRef;
    // TSTypeAssertion
    pub fn hermes_get_TSTypeAssertion_typeAnnotation(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSTypeAssertion_expression(node: NodePtr) -> NodePtr;
    // TSAsExpression
    pub fn hermes_get_TSAsExpression_expression(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSAsExpression_typeAnnotation(node: NodePtr) -> NodePtr;
    // TSParameterProperty
    pub fn hermes_get_TSParameterProperty_parameter(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSParameterProperty_accessibility(node: NodePtr) -> NodeLabelOpt;
    pub fn hermes_get_TSParameterProperty_readonly(node: NodePtr) -> bool;
    pub fn hermes_get_TSParameterProperty_static(node: NodePtr) -> bool;
    pub fn hermes_get_TSParameterProperty_export(node: NodePtr) -> bool;
    // TSTypeAliasDeclaration
    pub fn hermes_get_TSTypeAliasDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSTypeAliasDeclaration_typeParameters(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TSTypeAliasDeclaration_typeAnnotation(node: NodePtr) -> NodePtr;
    // TSInterfaceDeclaration
    pub fn hermes_get_TSInterfaceDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSInterfaceDeclaration_body(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSInterfaceDeclaration_extends(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TSInterfaceDeclaration_typeParameters(node: NodePtr) -> NodePtrOpt;
    // TSInterfaceHeritage
    pub fn hermes_get_TSInterfaceHeritage_expression(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSInterfaceHeritage_typeParameters(node: NodePtr) -> NodePtrOpt;
    // TSInterfaceBody
    pub fn hermes_get_TSInterfaceBody_body(node: NodePtr) -> NodeListRef;
    // TSEnumDeclaration
    pub fn hermes_get_TSEnumDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSEnumDeclaration_members(node: NodePtr) -> NodeListRef;
    // TSEnumMember
    pub fn hermes_get_TSEnumMember_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSEnumMember_initializer(node: NodePtr) -> NodePtrOpt;
    // TSModuleDeclaration
    pub fn hermes_get_TSModuleDeclaration_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSModuleDeclaration_body(node: NodePtr) -> NodePtr;
    // TSModuleBlock
    pub fn hermes_get_TSModuleBlock_body(node: NodePtr) -> NodeListRef;
    // TSModuleMember
    pub fn hermes_get_TSModuleMember_id(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSModuleMember_initializer(node: NodePtr) -> NodePtrOpt;
    // TSTypeParameterDeclaration
    pub fn hermes_get_TSTypeParameterDeclaration_params(node: NodePtr) -> NodeListRef;
    // TSTypeParameter
    pub fn hermes_get_TSTypeParameter_name(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSTypeParameter_constraint(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TSTypeParameter_default(node: NodePtr) -> NodePtrOpt;
    // TSTypeParameterInstantiation
    pub fn hermes_get_TSTypeParameterInstantiation_params(node: NodePtr) -> NodeListRef;
    // TSUnionType
    pub fn hermes_get_TSUnionType_types(node: NodePtr) -> NodeListRef;
    // TSIntersectionType
    pub fn hermes_get_TSIntersectionType_types(node: NodePtr) -> NodeListRef;
    // TSTypeQuery
    pub fn hermes_get_TSTypeQuery_exprName(node: NodePtr) -> NodePtr;
    // TSConditionalType
    pub fn hermes_get_TSConditionalType_checkType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSConditionalType_extendsType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSConditionalType_trueType(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSConditionalType_falseType(node: NodePtr) -> NodePtr;
    // TSTypeLiteral
    pub fn hermes_get_TSTypeLiteral_members(node: NodePtr) -> NodeListRef;
    // TSPropertySignature
    pub fn hermes_get_TSPropertySignature_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSPropertySignature_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TSPropertySignature_initializer(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TSPropertySignature_optional(node: NodePtr) -> bool;
    pub fn hermes_get_TSPropertySignature_computed(node: NodePtr) -> bool;
    pub fn hermes_get_TSPropertySignature_readonly(node: NodePtr) -> bool;
    pub fn hermes_get_TSPropertySignature_static(node: NodePtr) -> bool;
    pub fn hermes_get_TSPropertySignature_export(node: NodePtr) -> bool;
    // TSMethodSignature
    pub fn hermes_get_TSMethodSignature_key(node: NodePtr) -> NodePtr;
    pub fn hermes_get_TSMethodSignature_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TSMethodSignature_returnType(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_TSMethodSignature_computed(node: NodePtr) -> bool;
    // TSIndexSignature
    pub fn hermes_get_TSIndexSignature_parameters(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TSIndexSignature_typeAnnotation(node: NodePtr) -> NodePtrOpt;
    // TSCallSignatureDeclaration
    pub fn hermes_get_TSCallSignatureDeclaration_params(node: NodePtr) -> NodeListRef;
    pub fn hermes_get_TSCallSignatureDeclaration_returnType(node: NodePtr) -> NodePtrOpt;
    // TSModifiers
    pub fn hermes_get_TSModifiers_accessibility(node: NodePtr) -> NodeLabel;
    pub fn hermes_get_TSModifiers_readonly(node: NodePtr) -> bool;
    // CoverInitializer
    pub fn hermes_get_CoverInitializer_init(node: NodePtr) -> NodePtr;
    // CoverRestElement
    pub fn hermes_get_CoverRestElement_rest(node: NodePtr) -> NodePtr;
    // CoverTypedIdentifier
    pub fn hermes_get_CoverTypedIdentifier_left(node: NodePtr) -> NodePtr;
    pub fn hermes_get_CoverTypedIdentifier_right(node: NodePtr) -> NodePtrOpt;
    pub fn hermes_get_CoverTypedIdentifier_optional(node: NodePtr) -> bool;
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::fmt::Formatter;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::os::raw::c_char;
use std::os::raw::c_uint;

use juno_support::NullTerminatedBuf;

use super::node::Node;
use super::node::NodePtr;
use super::node::NodePtrOpt;
use super::node::SMLoc;
use super::node::StringRef;
use crate::utf::utf8_with_surrogates_to_string_lossy;

#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ParserDialect {
    /// Good old JS.
    JavaScript,
    /// Parse all Flow type syntax.
    Flow,
    /// Parse all unambiguous Flow type syntax. Syntax that can be intepreted as
    /// either Flow types or standard JavaScript is parsed as if it were standard
    /// JavaScript.
    ///
    /// For example, `foo<T>(x)` is parsed as if it were standard JavaScript
    /// containing two comparisons, even though it could otherwise be interpreted
    /// as a call expression with Flow type arguments.
    FlowUnambiguous,
    /// Look for the '@flow' pragma in the first comment in the JS file.
    /// If it exists, then parse all Flow type syntax, otherwise only parse
    /// Flow type syntax according to the FlowUnambiguous mode.
    FlowDetect,
    /// Parse TypeScript.
    TypeScript,
}

/// Flags controlling the behavior of the parser.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ParserFlags {
    /// Start parsing in strict mode.
    pub strict_mode: bool,
    /// Enable JSX parsing.
    pub enable_jsx: bool,
    /// Dialect control.
    pub dialect: ParserDialect,
    /// Store doc-comment block at the top of the file.
    pub store_doc_block: bool,
}

impl Default for ParserFlags {
    fn default() -> Self {
        ParserFlags {
            strict_mode: false,
            enable_jsx: false,
            dialect: ParserDialect::JavaScript,
            store_doc_block: false,
        }
    }
}

#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum DiagKind {
    Error,
    Warning,
    Remark,
    Note,
}

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct DataRef<'a, T: 'a> {
    data: *const T,
    length: usize,
    _marker: PhantomData<&'a T>,
}

impl<'a, T> DataRef<'a, T> {
    pub fn is_empty(&self) -> bool {
        self.length == 0
    }
    pub fn as_slice(&self) -> &'a [T] {
        if self.data.is_null() {
            &[]
        } else {
            unsafe { std::slice::from_raw_parts(self.data, self.length) }
        }
    }

    /// Returns a new `DataRef` which is one byte longer than this one.
    ///
    /// # Safety
    ///
    /// This is only safe when the user is certain that one more byte past
    /// the end of the `DataRef` is still valid memory, such as when we know the `data` is
    /// null-terminated.
    pub unsafe fn extend_by_1(&self) -> Self {
        Self {
            data: self.data,
            length: self.length + 1,
            _marker: self._marker,
        }
    }

    // Note that the Clippy warning is bogus since we aren't deferencing a pointer.
    #[allow(clippy::not_unsafe_ptr_arg_deref)]
    pub fn try_offset_from(&self, ptr: *const T) -> Option<usize> {
        unsafe {
            if ptr >= self.data && ptr < self.data.add(self.length) {
                Some(ptr.offset_from(self.data) as usize)
            } else {
                None
            }
        }
    }
}

impl<T> Default for DataRef<'_, T> {
    fn default() -> Self {
        DataRef {
            data: std::ptr::null(),
            length: 0,
            _marker: Default::default(),
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Coord {
    /// 1-based line.
    pub line: c_uint,
    /// 0-based offset from start of line.
    pub offset: c_uint,
}

/// Result from looking for a line in the input buffer. Contains the 1-based
/// line number and a reference to the line itself in the buffer.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct LineCoord<'a> {
    /// 1-based line number.
    pub line_no: c_uint,
    /// Reference to the line itself, including the EOL, if present.
    pub line_ref: DataRef<'a, u8>,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct DiagMessage {
    /// Location.
    pub loc: SMLoc,
    /// Source coordinate.
    pub coord: Coord,
    /// What kind of message.
    pub diag_kind: DiagKind,
    /// Error message.
    pub message: StringRef,
    /// Contents of the error line.
    pub line_contents: StringRef,
}

impl std::fmt::Display for DiagMessage {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}:{}:{}",
            self.coord.line,
            self.coord.offset + 1,
            utf8_with_surrogates_to_string_lossy(self.message.as_slice())
        )
    }
}

#[repr(u32)]
#[derive(Copy, Clone)]
pub enum MagicCommentKind {
    SourceUrl = 0,
    SourceMappingUrl = 1,
}

impl MagicCommentKind {
    pub fn name(self) -> &'static str {
        match self {
            MagicCommentKind::SourceUrl => "sourceUrl",
            MagicCommentKind::SourceMappingUrl => "sourceMappingUrl",
        }
    }
}

#[repr(C)]
struct ParserContext {
    _unused: i32,
}

extern "C" {
    /// Note: source[len-1] must be 0.
    fn hermes_parser_parse(
        flags: ParserFlags,
        source: *const c_char,
        len: usize,
    ) -> *mut ParserContext;
    fn hermes_parser_free(parser_ctx: *mut ParserContext);
    fn hermes_parser_get_first_error(parser_ctx: *const ParserContext) -> isize;
    fn hermes_parser_get_messages<'a>(parser_ctx: *const ParserContext)
    -> DataRef<'a, DiagMessage>;
    fn hermes_parser_get_ast(parser_ctx: *const ParserContext) -> NodePtrOpt;
    fn hermes_parser_find_location(
        parser_ctx: *mut ParserContext,
        loc: SMLoc,
        res: *mut Coord,
    ) -> bool;
    /// Return the line surrounding the specified location \p loc. This method
    /// allows the caller to calculate the location column taking UTF-8 into
    /// consideration and to perform its own location caching.
    fn hermes_parser_find_line(
        parser_ctx: *const ParserContext,
        loc: SMLoc,
        res: *mut LineCoord,
    ) -> bool;
    /// Return a reference to the specified (1-based) line.
    /// If the line is greater than the last line in the buffer, an empty
    /// reference is returned.
    fn hermes_parser_get_line_ref<'a>(
        parser_ctx: *const ParserContext,
        line: c_uint,
    ) -> DataRef<'a, u8>;
    /// Return a magic comment or an empty string. The string is always guaranteed to be valid UTF-8.
    fn hermes_parser_get_magic_comment<'a>(
        parser_ctx: *const ParserContext,
        kind: MagicCommentKind,
    ) -> DataRef<'a, u8>;
    fn hermes_get_node_name(node: NodePtr) -> DataRef<'static, u8>;
    /// Return the doc block for the file if `storeDocBlock` was provided at parse time.
    fn hermes_parser_get_doc_block<'a>(parser_ctx: *const ParserContext) -> DataRef<'a, u8>;
}

pub struct HermesParser<'a> {
    /// A pointer to the opaque C++ parser object. It should never be null.
    parser_ctx: *mut ParserContext,
    /// If the input is not zero-terminated, we create a zero-terminated copy
    /// here.
    source: &'a NullTerminatedBuf,
}

impl Drop for HermesParser<'_> {
    fn drop(&mut self) {
        unsafe { hermes_parser_free(self.parser_ctx) }
    }
}

impl HermesParser<'_> {
    /// `file_id` is an opaque value used for encoding source coordinates.
    pub fn parse(flags: ParserFlags, source: &NullTerminatedBuf) -> HermesParser {
        HermesParser {
            parser_ctx: unsafe { hermes_parser_parse(flags, source.as_c_char_ptr(), source.len()) },
            source,
        }
    }

    /// Return the index of the first parser error (there could be warnings before it).
    pub fn first_error_index(&self) -> Option<usize> {
        let index = unsafe { hermes_parser_get_first_error(self.parser_ctx) };
        if index < 0 {
            None
        } else {
            Some(index as usize)
        }
    }

    /// Return true if there was at least one parser error. That implies that there is no AST.
    pub fn has_errors(&self) -> bool {
        self.first_error_index().is_some()
    }

    /// Return the doc block at the top of the file if it exists.
    pub fn get_doc_block(&self) -> Option<&str> {
        let result = unsafe { hermes_parser_get_doc_block(self.parser_ctx) };
        if result.is_empty() {
            None
        } else {
            Some(unsafe { std::str::from_utf8_unchecked(result.as_slice()) })
        }
    }

    /// Return a slice containing all parser messages.
    pub fn messages(&self) -> &[DiagMessage] {
        unsafe { hermes_parser_get_messages(self.parser_ctx).as_slice() }
    }

    /// Return the root AST node if the parse we successful, None otherwise.
    pub fn root(&self) -> Option<NodePtr> {
        unsafe { hermes_parser_get_ast(self.parser_ctx) }.as_node_ptr()
    }

    /// Translate a source coordinate represented as a SMLoc (a pointer) into
    /// line and column.
    pub fn find_coord(&self, loc: SMLoc) -> Option<Coord> {
        let mut res = MaybeUninit::<Coord>::uninit();
        if unsafe { hermes_parser_find_location(self.parser_ctx, loc, res.as_mut_ptr()) } {
            Some(unsafe { res.assume_init() })
        } else {
            None
        }
    }

    /// Find the line surrounding the specified location. This method enables
    /// the caller to calculate the column taking UTF-8 into consideration and
    /// to perform its own location caching.
    pub fn find_line(&self, loc: SMLoc) -> Option<LineCoord> {
        let mut res = MaybeUninit::<LineCoord>::uninit();
        if unsafe { hermes_parser_find_line(self.parser_ctx, loc, res.as_mut_ptr()) } {
            Some(unsafe { res.assume_init() })
        } else {
            None
        }
    }

    /// Return a reference to the specified (1-based) line.
    /// If the line is greater than the last line in the buffer, an empty
    /// reference is returned.
    pub fn get_line_ref(&self, line: u32) -> DataRef<u8> {
        unsafe { hermes_parser_get_line_ref(self.parser_ctx, line) }
    }

    /// Return the last magic comment of the specified type (each comment overrides the previous
    /// one, so only the last is recorded).
    pub fn magic_comment(&self, kind: MagicCommentKind) -> Option<&str> {
        let comment = unsafe { hermes_parser_get_magic_comment(self.parser_ctx, kind) };
        if comment.is_empty() {
            None
        } else {
            Some(unsafe { std::str::from_utf8_unchecked(comment.as_slice()) })
        }
    }

    pub fn node_name(n: &Node) -> &str {
        unsafe { std::str::from_utf8_unchecked(hermes_get_node_name(NodePtr::new(n)).as_slice()) }
    }
}

#[cfg(test)]
mod tests {
    use super::super::generated_ffi::NodeKind;
    use super::*;

    #[test]
    fn good_parse() {
        let buf = NullTerminatedBuf::from_str_check("var x = 10;\0");
        let p = HermesParser::parse(Default::default(), &buf);
        assert!(!p.has_errors());
        assert_eq!(p.root().unwrap().as_ref().kind, NodeKind::Program);
    }

    #[test]
    fn parse_error() {
        let buf = NullTerminatedBuf::from_str_check("var x+ = 10;");
        let p = HermesParser::parse(Default::default(), &buf);
        assert!(p.has_errors());
        assert!(p.root().is_none());

        let messages = p.messages();
        assert_eq!(messages.len(), 1);
        assert_eq!(
            p.find_coord(messages[0].loc).unwrap(),
            Coord { line: 1, offset: 5 }
        );
    }

    #[test]
    fn magic_comments() {
        let buf = NullTerminatedBuf::from_str_check(
            "var p = 0;
            //# sourceURL=1
            //# sourceMappingURL=my map URL
            //# sourceURL=my source URL
            ",
        );
        let p = HermesParser::parse(Default::default(), &buf);
        assert!(!p.has_errors());
        assert_eq!(
            p.magic_comment(MagicCommentKind::SourceUrl).unwrap(),
            "my source URL"
        );
        assert_eq!(
            p.magic_comment(MagicCommentKind::SourceMappingUrl).unwrap(),
            "my map URL"
        );
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

mod generated_ffi;
mod hermes_parser;
mod node;

pub use generated_ffi::*;
pub use hermes_parser::*;
pub use node::*;


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::convert::AsRef;
use std::marker::PhantomData;
use std::ptr::NonNull;

use super::generated_ffi::NodeKind;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SMLoc {
    ptr: *const u8,
}

impl SMLoc {
    pub fn is_valid(self) -> bool {
        !self.ptr.is_null()
    }

    pub fn pred(self) -> SMLoc {
        SMLoc {
            ptr: self.ptr.wrapping_sub(1),
        }
    }

    pub fn as_ptr(self) -> *const u8 {
        self.ptr
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SMRange {
    pub start: SMLoc,
    pub end: SMLoc,
}

impl SMRange {
    pub fn is_empty(self) -> bool {
        self.start.ptr == self.end.ptr
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct StringRef {
    data: *const u8,
    length: usize,
}

impl StringRef {
    pub fn as_slice(&self) -> &[u8] {
        // Rust doesn't allow null pointer in a slice.
        if self.data.is_null() {
            &[]
        } else {
            unsafe { std::slice::from_raw_parts(self.data, self.length) }
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct UniqueString {
    str: StringRef,
}

#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct NodeLabel {
    ptr: *const UniqueString,
}

#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct NodeLabelOpt {
    ptr: *const UniqueString,
}

#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct NodeString {
    ptr: *const UniqueString,
}

#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct NodeStringOpt {
    ptr: *const UniqueString,
}

impl NodeLabel {
    pub fn as_slice(&self) -> &[u8] {
        debug_assert!(!self.ptr.is_null(), "null NodeLabel");
        unsafe { (*self.ptr).str.as_slice() }
    }
}

impl NodeLabelOpt {
    pub fn as_node_label(&self) -> Option<NodeLabel> {
        if self.ptr.is_null() {
            None
        } else {
            Some(NodeLabel { ptr: self.ptr })
        }
    }
}

impl NodeString {
    pub fn as_slice(&self) -> &[u8] {
        debug_assert!(!self.ptr.is_null(), "null NodeLabel");
        unsafe { (*self.ptr).str.as_slice() }
    }
}

impl NodeStringOpt {
    pub fn as_node_string(&self) -> Option<NodeString> {
        if self.ptr.is_null() {
            None
        } else {
            Some(NodeString { ptr: self.ptr })
        }
    }
}

#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct NodePtr {
    ptr: NonNull<Node>,
}

#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct NodePtrOpt {
    ptr: *const Node,
}

impl NodePtr {
    pub fn new(n: &Node) -> NodePtr {
        NodePtr {
            ptr: NonNull::from(n),
        }
    }
}

impl AsRef<Node> for NodePtr {
    fn as_ref(&self) -> &Node {
        debug_assert!(!self.ptr.as_ptr().is_null(), "null NodePtr");
        unsafe { self.ptr.as_ref() }
    }
}

impl NodePtrOpt {
    pub fn as_node_ptr(&self) -> Option<NodePtr> {
        if self.ptr.is_null() {
            None
        } else {
            Some(NodePtr {
                ptr: unsafe { NonNull::new_unchecked(self.ptr as *mut Node) },
            })
        }
    }
}

#[repr(C)]
pub struct NodeList {
    pub prev: *const NodeList,
    pub next: *const NodeList,
}

#[repr(transparent)]
pub struct NodeListRef {
    ptr: *const NodeList,
}

#[repr(transparent)]
pub struct NodeListOptRef {
    ptr: *const NodeList,
}

impl NodeListRef {
    pub fn iter(&self) -> NodeIterator {
        NodeIterator {
            head: self.ptr,
            cur: self.ptr,
            ph: PhantomData,
        }
    }
}

impl AsRef<NodeList> for NodeListRef {
    fn as_ref(&self) -> &NodeList {
        debug_assert!(!self.ptr.is_null(), "null NodeListRef");
        unsafe { &*self.ptr }
    }
}

impl NodeListOptRef {
    pub fn as_node_list_ref(&self) -> Option<NodeListRef> {
        if self.ptr.is_null() {
            None
        } else {
            Some(NodeListRef { ptr: self.ptr })
        }
    }
}

pub struct NodeIterator<'a> {
    head: *const NodeList,
    cur: *const NodeList,
    ph: PhantomData<&'a Node>,
}

impl<'a> std::iter::Iterator for NodeIterator<'a> {
    type Item = &'a Node;

    fn next(&mut self) -> Option<Self::Item> {
        self.cur = unsafe { (*self.cur).next };
        if self.cur == self.head {
            None
        } else {
            Some(unsafe { &*(self.cur as *const Node) })
        }
    }
}

#[repr(C)]
pub struct Node {
    pub link: NodeList,
    pub kind: NodeKind,
    pub parens: u32,
    pub source_range: SMRange,
    pub debug_loc: SMLoc,
}