/******************************************************************************
 * This file was generated by langium-cli 1.3.1.
 * DO NOT EDIT MANUALLY!
 ******************************************************************************/

/* eslint-disable */
import type { AstNode, Reference, ReferenceInfo, TypeMetaData } from 'langium';
import { AbstractAstReflection } from 'langium';

export const ZModelTerminals = {
    WS: /\s+/,
    INTERNAL_ATTRIBUTE_NAME: /@@@([_a-zA-Z][\w_]*\.)*[_a-zA-Z][\w_]*/,
    MODEL_ATTRIBUTE_NAME: /@@([_a-zA-Z][\w_]*\.)*[_a-zA-Z][\w_]*/,
    FIELD_ATTRIBUTE_NAME: /@([_a-zA-Z][\w_]*\.)*[_a-zA-Z][\w_]*/,
    ID: /[_a-zA-Z][\w_]*/,
    STRING: /"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/,
    NUMBER: /[+-]?[0-9]+(\.[0-9]+)?/,
    TRIPLE_SLASH_COMMENT: /\/\/\/[^\n\r]*/,
    ML_COMMENT: /\/\*[\s\S]*?\*\//,
    SL_COMMENT: /\/\/[^\n\r]*/,
};

export type AbstractDeclaration = Attribute | DataModel | DataSource | Enum | FunctionDecl | GeneratorDecl | Plugin | TypeDef;

export const AbstractDeclaration = 'AbstractDeclaration';

export function isAbstractDeclaration(item: unknown): item is AbstractDeclaration {
    return reflection.isInstance(item, AbstractDeclaration);
}

export type Boolean = boolean;

export function isBoolean(item: unknown): item is Boolean {
    return typeof item === 'boolean';
}

export type BuiltinType = 'BigInt' | 'Boolean' | 'Bytes' | 'DateTime' | 'Decimal' | 'Float' | 'Int' | 'Json' | 'String';

export function isBuiltinType(item: unknown): item is BuiltinType {
    return item === 'String' || item === 'Boolean' || item === 'Int' || item === 'BigInt' || item === 'Float' || item === 'Decimal' || item === 'DateTime' || item === 'Json' || item === 'Bytes';
}

export type ConfigExpr = ConfigArrayExpr | InvocationExpr | LiteralExpr;

export const ConfigExpr = 'ConfigExpr';

export function isConfigExpr(item: unknown): item is ConfigExpr {
    return reflection.isInstance(item, ConfigExpr);
}

export type Expression = ArrayExpr | BinaryExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | NullExpr | ObjectExpr | ReferenceExpr | ThisExpr | UnaryExpr;

export const Expression = 'Expression';

export function isExpression(item: unknown): item is Expression {
    return reflection.isInstance(item, Expression);
}

export type ExpressionType = 'Any' | 'Boolean' | 'DateTime' | 'Float' | 'Int' | 'Null' | 'Object' | 'String' | 'Unsupported';

export function isExpressionType(item: unknown): item is ExpressionType {
    return item === 'String' || item === 'Int' || item === 'Float' || item === 'Boolean' || item === 'DateTime' || item === 'Null' || item === 'Object' || item === 'Any' || item === 'Unsupported';
}

export type LiteralExpr = BooleanLiteral | NumberLiteral | StringLiteral;

export const LiteralExpr = 'LiteralExpr';

export function isLiteralExpr(item: unknown): item is LiteralExpr {
    return reflection.isInstance(item, LiteralExpr);
}

export type MemberAccessTarget = DataModelField | TypeDefField;

export const MemberAccessTarget = 'MemberAccessTarget';

export function isMemberAccessTarget(item: unknown): item is MemberAccessTarget {
    return reflection.isInstance(item, MemberAccessTarget);
}

export type ReferenceTarget = DataModelField | EnumField | FunctionParam | TypeDefField;

export const ReferenceTarget = 'ReferenceTarget';

export function isReferenceTarget(item: unknown): item is ReferenceTarget {
    return reflection.isInstance(item, ReferenceTarget);
}

export type RegularID = 'abstract' | 'attribute' | 'datasource' | 'enum' | 'import' | 'in' | 'model' | 'plugin' | 'type' | 'view' | string;

export function isRegularID(item: unknown): item is RegularID {
    return item === 'model' || item === 'enum' || item === 'attribute' || item === 'datasource' || item === 'plugin' || item === 'abstract' || item === 'in' || item === 'view' || item === 'import' || item === 'type' || (typeof item === 'string' && (/[_a-zA-Z][\w_]*/.test(item)));
}

export type RegularIDWithTypeNames = 'Any' | 'BigInt' | 'Boolean' | 'Bytes' | 'DateTime' | 'Decimal' | 'Float' | 'Int' | 'Json' | 'Null' | 'Object' | 'String' | 'Unsupported' | RegularID;

export function isRegularIDWithTypeNames(item: unknown): item is RegularIDWithTypeNames {
    return isRegularID(item) || item === 'String' || item === 'Boolean' || item === 'Int' || item === 'BigInt' || item === 'Float' || item === 'Decimal' || item === 'DateTime' || item === 'Json' || item === 'Bytes' || item === 'Null' || item === 'Object' || item === 'Any' || item === 'Unsupported';
}

export type TypeDeclaration = DataModel | Enum | TypeDef;

export const TypeDeclaration = 'TypeDeclaration';

export function isTypeDeclaration(item: unknown): item is TypeDeclaration {
    return reflection.isInstance(item, TypeDeclaration);
}

export type TypeDefFieldTypes = Enum | TypeDef;

export const TypeDefFieldTypes = 'TypeDefFieldTypes';

export function isTypeDefFieldTypes(item: unknown): item is TypeDefFieldTypes {
    return reflection.isInstance(item, TypeDefFieldTypes);
}

export interface Argument extends AstNode {
    readonly $container: InvocationExpr;
    readonly $type: 'Argument';
    value: Expression
}

export const Argument = 'Argument';

export function isArgument(item: unknown): item is Argument {
    return reflection.isInstance(item, Argument);
}

export interface ArrayExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'ArrayExpr';
    items: Array<Expression>
}

export const ArrayExpr = 'ArrayExpr';

export function isArrayExpr(item: unknown): item is ArrayExpr {
    return reflection.isInstance(item, ArrayExpr);
}

export interface Attribute extends AstNode {
    readonly $container: Model;
    readonly $type: 'Attribute';
    attributes: Array<InternalAttribute>
    comments: Array<string>
    name: string
    params: Array<AttributeParam>
}

export const Attribute = 'Attribute';

export function isAttribute(item: unknown): item is Attribute {
    return reflection.isInstance(item, Attribute);
}

export interface AttributeArg extends AstNode {
    readonly $container: DataModelAttribute | DataModelFieldAttribute | InternalAttribute;
    readonly $type: 'AttributeArg';
    name?: RegularID
    value: Expression
}

export const AttributeArg = 'AttributeArg';

export function isAttributeArg(item: unknown): item is AttributeArg {
    return reflection.isInstance(item, AttributeArg);
}

export interface AttributeParam extends AstNode {
    readonly $container: Attribute;
    readonly $type: 'AttributeParam';
    attributes: Array<InternalAttribute>
    comments: Array<string>
    default: boolean
    name: RegularID
    type: AttributeParamType
}

export const AttributeParam = 'AttributeParam';

export function isAttributeParam(item: unknown): item is AttributeParam {
    return reflection.isInstance(item, AttributeParam);
}

export interface AttributeParamType extends AstNode {
    readonly $container: AttributeParam;
    readonly $type: 'AttributeParamType';
    array: boolean
    optional: boolean
    reference?: Reference<TypeDeclaration>
    type?: 'ContextType' | 'FieldReference' | 'TransitiveFieldReference' | ExpressionType
}

export const AttributeParamType = 'AttributeParamType';

export function isAttributeParamType(item: unknown): item is AttributeParamType {
    return reflection.isInstance(item, AttributeParamType);
}

export interface BinaryExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'BinaryExpr';
    left: Expression
    operator: '!' | '!=' | '&&' | '<' | '<=' | '==' | '>' | '>=' | '?' | '^' | 'in' | '||'
    right: Expression
}

export const BinaryExpr = 'BinaryExpr';

export function isBinaryExpr(item: unknown): item is BinaryExpr {
    return reflection.isInstance(item, BinaryExpr);
}

export interface BooleanLiteral extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'BooleanLiteral';
    value: Boolean
}

export const BooleanLiteral = 'BooleanLiteral';

export function isBooleanLiteral(item: unknown): item is BooleanLiteral {
    return reflection.isInstance(item, BooleanLiteral);
}

export interface ConfigArrayExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'ConfigArrayExpr';
    items: Array<ConfigInvocationExpr | LiteralExpr>
}

export const ConfigArrayExpr = 'ConfigArrayExpr';

export function isConfigArrayExpr(item: unknown): item is ConfigArrayExpr {
    return reflection.isInstance(item, ConfigArrayExpr);
}

export interface ConfigField extends AstNode {
    readonly $container: DataSource | GeneratorDecl;
    readonly $type: 'ConfigField';
    name: RegularID
    value: ConfigExpr
}

export const ConfigField = 'ConfigField';

export function isConfigField(item: unknown): item is ConfigField {
    return reflection.isInstance(item, ConfigField);
}

export interface ConfigInvocationArg extends AstNode {
    readonly $container: ConfigInvocationExpr;
    readonly $type: 'ConfigInvocationArg';
    name: string
    value: LiteralExpr
}

export const ConfigInvocationArg = 'ConfigInvocationArg';

export function isConfigInvocationArg(item: unknown): item is ConfigInvocationArg {
    return reflection.isInstance(item, ConfigInvocationArg);
}

export interface ConfigInvocationExpr extends AstNode {
    readonly $container: ConfigArrayExpr;
    readonly $type: 'ConfigInvocationExpr';
    args: Array<ConfigInvocationArg>
    name: string
}

export const ConfigInvocationExpr = 'ConfigInvocationExpr';

export function isConfigInvocationExpr(item: unknown): item is ConfigInvocationExpr {
    return reflection.isInstance(item, ConfigInvocationExpr);
}

export interface DataModel extends AstNode {
    readonly $container: Model;
    readonly $type: 'DataModel';
    attributes: Array<DataModelAttribute>
    comments: Array<string>
    fields: Array<DataModelField>
    isAbstract: boolean
    isView: boolean
    name: RegularID
    superTypes: Array<Reference<DataModel>>
}

export const DataModel = 'DataModel';

export function isDataModel(item: unknown): item is DataModel {
    return reflection.isInstance(item, DataModel);
}

export interface DataModelAttribute extends AstNode {
    readonly $container: DataModel | Enum | TypeDef;
    readonly $type: 'DataModelAttribute';
    args: Array<AttributeArg>
    decl: Reference<Attribute>
}

export const DataModelAttribute = 'DataModelAttribute';

export function isDataModelAttribute(item: unknown): item is DataModelAttribute {
    return reflection.isInstance(item, DataModelAttribute);
}

export interface DataModelField extends AstNode {
    readonly $container: DataModel | Enum | FunctionDecl | TypeDef;
    readonly $type: 'DataModelField';
    attributes: Array<DataModelFieldAttribute>
    comments: Array<string>
    name: RegularIDWithTypeNames
    type: DataModelFieldType
}

export const DataModelField = 'DataModelField';

export function isDataModelField(item: unknown): item is DataModelField {
    return reflection.isInstance(item, DataModelField);
}

export interface DataModelFieldAttribute extends AstNode {
    readonly $container: DataModelField | EnumField | TypeDefField;
    readonly $type: 'DataModelFieldAttribute';
    args: Array<AttributeArg>
    decl: Reference<Attribute>
}

export const DataModelFieldAttribute = 'DataModelFieldAttribute';

export function isDataModelFieldAttribute(item: unknown): item is DataModelFieldAttribute {
    return reflection.isInstance(item, DataModelFieldAttribute);
}

export interface DataModelFieldType extends AstNode {
    readonly $container: DataModelField;
    readonly $type: 'DataModelFieldType';
    array: boolean
    optional: boolean
    reference?: Reference<TypeDeclaration>
    type?: BuiltinType
    unsupported?: UnsupportedFieldType
}

export const DataModelFieldType = 'DataModelFieldType';

export function isDataModelFieldType(item: unknown): item is DataModelFieldType {
    return reflection.isInstance(item, DataModelFieldType);
}

export interface DataSource extends AstNode {
    readonly $container: Model;
    readonly $type: 'DataSource';
    fields: Array<ConfigField>
    name: RegularID
}

export const DataSource = 'DataSource';

export function isDataSource(item: unknown): item is DataSource {
    return reflection.isInstance(item, DataSource);
}

export interface Enum extends AstNode {
    readonly $container: Model;
    readonly $type: 'Enum';
    attributes: Array<DataModelAttribute>
    comments: Array<string>
    fields: Array<EnumField>
    name: RegularID
}

export const Enum = 'Enum';

export function isEnum(item: unknown): item is Enum {
    return reflection.isInstance(item, Enum);
}

export interface EnumField extends AstNode {
    readonly $container: DataModel | Enum | FunctionDecl | TypeDef;
    readonly $type: 'EnumField';
    attributes: Array<DataModelFieldAttribute>
    comments: Array<string>
    name: RegularIDWithTypeNames
}

export const EnumField = 'EnumField';

export function isEnumField(item: unknown): item is EnumField {
    return reflection.isInstance(item, EnumField);
}

export interface FieldInitializer extends AstNode {
    readonly $container: ObjectExpr;
    readonly $type: 'FieldInitializer';
    name: RegularID | string
    value: Expression
}

export const FieldInitializer = 'FieldInitializer';

export function isFieldInitializer(item: unknown): item is FieldInitializer {
    return reflection.isInstance(item, FieldInitializer);
}

export interface FunctionDecl extends AstNode {
    readonly $container: Model;
    readonly $type: 'FunctionDecl';
    attributes: Array<InternalAttribute>
    expression?: Expression
    name: RegularID
    params: Array<FunctionParam>
    returnType: FunctionParamType
}

export const FunctionDecl = 'FunctionDecl';

export function isFunctionDecl(item: unknown): item is FunctionDecl {
    return reflection.isInstance(item, FunctionDecl);
}

export interface FunctionParam extends AstNode {
    readonly $container: DataModel | Enum | FunctionDecl | TypeDef;
    readonly $type: 'FunctionParam';
    name: RegularID
    optional: boolean
    type: FunctionParamType
}

export const FunctionParam = 'FunctionParam';

export function isFunctionParam(item: unknown): item is FunctionParam {
    return reflection.isInstance(item, FunctionParam);
}

export interface FunctionParamType extends AstNode {
    readonly $container: FunctionDecl | FunctionParam;
    readonly $type: 'FunctionParamType';
    array: boolean
    reference?: Reference<TypeDeclaration>
    type?: ExpressionType
}

export const FunctionParamType = 'FunctionParamType';

export function isFunctionParamType(item: unknown): item is FunctionParamType {
    return reflection.isInstance(item, FunctionParamType);
}

export interface GeneratorDecl extends AstNode {
    readonly $container: Model;
    readonly $type: 'GeneratorDecl';
    fields: Array<ConfigField>
    name: RegularID
}

export const GeneratorDecl = 'GeneratorDecl';

export function isGeneratorDecl(item: unknown): item is GeneratorDecl {
    return reflection.isInstance(item, GeneratorDecl);
}

export interface InternalAttribute extends AstNode {
    readonly $container: Attribute | AttributeParam | FunctionDecl;
    readonly $type: 'InternalAttribute';
    args: Array<AttributeArg>
    decl: Reference<Attribute>
}

export const InternalAttribute = 'InternalAttribute';

export function isInternalAttribute(item: unknown): item is InternalAttribute {
    return reflection.isInstance(item, InternalAttribute);
}

export interface InvocationExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'InvocationExpr';
    args: Array<Argument>
    function: Reference<FunctionDecl>
}

export const InvocationExpr = 'InvocationExpr';

export function isInvocationExpr(item: unknown): item is InvocationExpr {
    return reflection.isInstance(item, InvocationExpr);
}

export interface MemberAccessExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'MemberAccessExpr';
    member: Reference<MemberAccessTarget>
    operand: Expression
}

export const MemberAccessExpr = 'MemberAccessExpr';

export function isMemberAccessExpr(item: unknown): item is MemberAccessExpr {
    return reflection.isInstance(item, MemberAccessExpr);
}

export interface Model extends AstNode {
    readonly $type: 'Model';
    declarations: Array<AbstractDeclaration>
    imports: Array<ModelImport>
}

export const Model = 'Model';

export function isModel(item: unknown): item is Model {
    return reflection.isInstance(item, Model);
}

export interface ModelImport extends AstNode {
    readonly $container: Model;
    readonly $type: 'ModelImport';
    path: string
}

export const ModelImport = 'ModelImport';

export function isModelImport(item: unknown): item is ModelImport {
    return reflection.isInstance(item, ModelImport);
}

export interface NullExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'NullExpr';
    value: 'null'
}

export const NullExpr = 'NullExpr';

export function isNullExpr(item: unknown): item is NullExpr {
    return reflection.isInstance(item, NullExpr);
}

export interface NumberLiteral extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'NumberLiteral';
    value: string
}

export const NumberLiteral = 'NumberLiteral';

export function isNumberLiteral(item: unknown): item is NumberLiteral {
    return reflection.isInstance(item, NumberLiteral);
}

export interface ObjectExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'ObjectExpr';
    fields: Array<FieldInitializer>
}

export const ObjectExpr = 'ObjectExpr';

export function isObjectExpr(item: unknown): item is ObjectExpr {
    return reflection.isInstance(item, ObjectExpr);
}

export interface Plugin extends AstNode {
    readonly $container: Model;
    readonly $type: 'Plugin';
    fields: Array<PluginField>
    name: RegularID
}

export const Plugin = 'Plugin';

export function isPlugin(item: unknown): item is Plugin {
    return reflection.isInstance(item, Plugin);
}

export interface PluginField extends AstNode {
    readonly $container: Plugin;
    readonly $type: 'PluginField';
    name: RegularID
    value: ArrayExpr | LiteralExpr | ObjectExpr
}

export const PluginField = 'PluginField';

export function isPluginField(item: unknown): item is PluginField {
    return reflection.isInstance(item, PluginField);
}

export interface ReferenceArg extends AstNode {
    readonly $container: ReferenceExpr;
    readonly $type: 'ReferenceArg';
    name: string
    value: Expression
}

export const ReferenceArg = 'ReferenceArg';

export function isReferenceArg(item: unknown): item is ReferenceArg {
    return reflection.isInstance(item, ReferenceArg);
}

export interface ReferenceExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'ReferenceExpr';
    args: Array<ReferenceArg>
    target: Reference<ReferenceTarget>
}

export const ReferenceExpr = 'ReferenceExpr';

export function isReferenceExpr(item: unknown): item is ReferenceExpr {
    return reflection.isInstance(item, ReferenceExpr);
}

export interface StringLiteral extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'StringLiteral';
    value: string
}

export const StringLiteral = 'StringLiteral';

export function isStringLiteral(item: unknown): item is StringLiteral {
    return reflection.isInstance(item, StringLiteral);
}

export interface ThisExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'ThisExpr';
    value: 'this'
}

export const ThisExpr = 'ThisExpr';

export function isThisExpr(item: unknown): item is ThisExpr {
    return reflection.isInstance(item, ThisExpr);
}

export interface TypeDef extends AstNode {
    readonly $container: Model;
    readonly $type: 'TypeDef';
    attributes: Array<DataModelAttribute>
    comments: Array<string>
    fields: Array<TypeDefField>
    name: RegularID
}

export const TypeDef = 'TypeDef';

export function isTypeDef(item: unknown): item is TypeDef {
    return reflection.isInstance(item, TypeDef);
}

export interface TypeDefField extends AstNode {
    readonly $container: DataModel | Enum | FunctionDecl | TypeDef;
    readonly $type: 'TypeDefField';
    attributes: Array<DataModelFieldAttribute>
    comments: Array<string>
    name: RegularIDWithTypeNames
    type: TypeDefFieldType
}

export const TypeDefField = 'TypeDefField';

export function isTypeDefField(item: unknown): item is TypeDefField {
    return reflection.isInstance(item, TypeDefField);
}

export interface TypeDefFieldType extends AstNode {
    readonly $container: TypeDefField;
    readonly $type: 'TypeDefFieldType';
    array: boolean
    optional: boolean
    reference?: Reference<TypeDefFieldTypes>
    type?: BuiltinType
}

export const TypeDefFieldType = 'TypeDefFieldType';

export function isTypeDefFieldType(item: unknown): item is TypeDefFieldType {
    return reflection.isInstance(item, TypeDefFieldType);
}

export interface UnaryExpr extends AstNode {
    readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | ReferenceArg | UnaryExpr | UnsupportedFieldType;
    readonly $type: 'UnaryExpr';
    operand: Expression
    operator: '!'
}

export const UnaryExpr = 'UnaryExpr';

export function isUnaryExpr(item: unknown): item is UnaryExpr {
    return reflection.isInstance(item, UnaryExpr);
}

export interface UnsupportedFieldType extends AstNode {
    readonly $container: DataModelFieldType;
    readonly $type: 'UnsupportedFieldType';
    value: LiteralExpr
}

export const UnsupportedFieldType = 'UnsupportedFieldType';

export function isUnsupportedFieldType(item: unknown): item is UnsupportedFieldType {
    return reflection.isInstance(item, UnsupportedFieldType);
}

export type ZModelAstType = {
    AbstractDeclaration: AbstractDeclaration
    Argument: Argument
    ArrayExpr: ArrayExpr
    Attribute: Attribute
    AttributeArg: AttributeArg
    AttributeParam: AttributeParam
    AttributeParamType: AttributeParamType
    BinaryExpr: BinaryExpr
    BooleanLiteral: BooleanLiteral
    ConfigArrayExpr: ConfigArrayExpr
    ConfigExpr: ConfigExpr
    ConfigField: ConfigField
    ConfigInvocationArg: ConfigInvocationArg
    ConfigInvocationExpr: ConfigInvocationExpr
    DataModel: DataModel
    DataModelAttribute: DataModelAttribute
    DataModelField: DataModelField
    DataModelFieldAttribute: DataModelFieldAttribute
    DataModelFieldType: DataModelFieldType
    DataSource: DataSource
    Enum: Enum
    EnumField: EnumField
    Expression: Expression
    FieldInitializer: FieldInitializer
    FunctionDecl: FunctionDecl
    FunctionParam: FunctionParam
    FunctionParamType: FunctionParamType
    GeneratorDecl: GeneratorDecl
    InternalAttribute: InternalAttribute
    InvocationExpr: InvocationExpr
    LiteralExpr: LiteralExpr
    MemberAccessExpr: MemberAccessExpr
    MemberAccessTarget: MemberAccessTarget
    Model: Model
    ModelImport: ModelImport
    NullExpr: NullExpr
    NumberLiteral: NumberLiteral
    ObjectExpr: ObjectExpr
    Plugin: Plugin
    PluginField: PluginField
    ReferenceArg: ReferenceArg
    ReferenceExpr: ReferenceExpr
    ReferenceTarget: ReferenceTarget
    StringLiteral: StringLiteral
    ThisExpr: ThisExpr
    TypeDeclaration: TypeDeclaration
    TypeDef: TypeDef
    TypeDefField: TypeDefField
    TypeDefFieldType: TypeDefFieldType
    TypeDefFieldTypes: TypeDefFieldTypes
    UnaryExpr: UnaryExpr
    UnsupportedFieldType: UnsupportedFieldType
}

export class ZModelAstReflection extends AbstractAstReflection {

    getAllTypes(): string[] {
        return ['AbstractDeclaration', 'Argument', 'ArrayExpr', 'Attribute', 'AttributeArg', 'AttributeParam', 'AttributeParamType', 'BinaryExpr', 'BooleanLiteral', 'ConfigArrayExpr', 'ConfigExpr', 'ConfigField', 'ConfigInvocationArg', 'ConfigInvocationExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'Enum', 'EnumField', 'Expression', 'FieldInitializer', 'FunctionDecl', 'FunctionParam', 'FunctionParamType', 'GeneratorDecl', 'InternalAttribute', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'MemberAccessTarget', 'Model', 'ModelImport', 'NullExpr', 'NumberLiteral', 'ObjectExpr', 'Plugin', 'PluginField', 'ReferenceArg', 'ReferenceExpr', 'ReferenceTarget', 'StringLiteral', 'ThisExpr', 'TypeDeclaration', 'TypeDef', 'TypeDefField', 'TypeDefFieldType', 'TypeDefFieldTypes', 'UnaryExpr', 'UnsupportedFieldType'];
    }

    protected override computeIsSubtype(subtype: string, supertype: string): boolean {
        switch (subtype) {
            case ArrayExpr:
            case BinaryExpr:
            case MemberAccessExpr:
            case NullExpr:
            case ObjectExpr:
            case ReferenceExpr:
            case ThisExpr:
            case UnaryExpr: {
                return this.isSubtype(Expression, supertype);
            }
            case Attribute:
            case DataSource:
            case FunctionDecl:
            case GeneratorDecl:
            case Plugin: {
                return this.isSubtype(AbstractDeclaration, supertype);
            }
            case BooleanLiteral:
            case NumberLiteral:
            case StringLiteral: {
                return this.isSubtype(LiteralExpr, supertype);
            }
            case ConfigArrayExpr: {
                return this.isSubtype(ConfigExpr, supertype);
            }
            case DataModel: {
                return this.isSubtype(AbstractDeclaration, supertype) || this.isSubtype(TypeDeclaration, supertype);
            }
            case DataModelField:
            case TypeDefField: {
                return this.isSubtype(MemberAccessTarget, supertype) || this.isSubtype(ReferenceTarget, supertype);
            }
            case Enum:
            case TypeDef: {
                return this.isSubtype(AbstractDeclaration, supertype) || this.isSubtype(TypeDeclaration, supertype) || this.isSubtype(TypeDefFieldTypes, supertype);
            }
            case EnumField:
            case FunctionParam: {
                return this.isSubtype(ReferenceTarget, supertype);
            }
            case InvocationExpr:
            case LiteralExpr: {
                return this.isSubtype(ConfigExpr, supertype) || this.isSubtype(Expression, supertype);
            }
            default: {
                return false;
            }
        }
    }

    getReferenceType(refInfo: ReferenceInfo): string {
        const referenceId = `${refInfo.container.$type}:${refInfo.property}`;
        switch (referenceId) {
            case 'AttributeParamType:reference':
            case 'DataModelFieldType:reference':
            case 'FunctionParamType:reference': {
                return TypeDeclaration;
            }
            case 'DataModel:superTypes': {
                return DataModel;
            }
            case 'DataModelAttribute:decl':
            case 'DataModelFieldAttribute:decl':
            case 'InternalAttribute:decl': {
                return Attribute;
            }
            case 'InvocationExpr:function': {
                return FunctionDecl;
            }
            case 'MemberAccessExpr:member': {
                return MemberAccessTarget;
            }
            case 'ReferenceExpr:target': {
                return ReferenceTarget;
            }
            case 'TypeDefFieldType:reference': {
                return TypeDefFieldTypes;
            }
            default: {
                throw new Error(`${referenceId} is not a valid reference id.`);
            }
        }
    }

    getTypeMetaData(type: string): TypeMetaData {
        switch (type) {
            case 'ArrayExpr': {
                return {
                    name: 'ArrayExpr',
                    mandatory: [
                        { name: 'items', type: 'array' }
                    ]
                };
            }
            case 'Attribute': {
                return {
                    name: 'Attribute',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' },
                        { name: 'params', type: 'array' }
                    ]
                };
            }
            case 'AttributeParam': {
                return {
                    name: 'AttributeParam',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' },
                        { name: 'default', type: 'boolean' }
                    ]
                };
            }
            case 'AttributeParamType': {
                return {
                    name: 'AttributeParamType',
                    mandatory: [
                        { name: 'array', type: 'boolean' },
                        { name: 'optional', type: 'boolean' }
                    ]
                };
            }
            case 'ConfigArrayExpr': {
                return {
                    name: 'ConfigArrayExpr',
                    mandatory: [
                        { name: 'items', type: 'array' }
                    ]
                };
            }
            case 'ConfigInvocationExpr': {
                return {
                    name: 'ConfigInvocationExpr',
                    mandatory: [
                        { name: 'args', type: 'array' }
                    ]
                };
            }
            case 'DataModel': {
                return {
                    name: 'DataModel',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' },
                        { name: 'fields', type: 'array' },
                        { name: 'isAbstract', type: 'boolean' },
                        { name: 'isView', type: 'boolean' },
                        { name: 'superTypes', type: 'array' }
                    ]
                };
            }
            case 'DataModelAttribute': {
                return {
                    name: 'DataModelAttribute',
                    mandatory: [
                        { name: 'args', type: 'array' }
                    ]
                };
            }
            case 'DataModelField': {
                return {
                    name: 'DataModelField',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' }
                    ]
                };
            }
            case 'DataModelFieldAttribute': {
                return {
                    name: 'DataModelFieldAttribute',
                    mandatory: [
                        { name: 'args', type: 'array' }
                    ]
                };
            }
            case 'DataModelFieldType': {
                return {
                    name: 'DataModelFieldType',
                    mandatory: [
                        { name: 'array', type: 'boolean' },
                        { name: 'optional', type: 'boolean' }
                    ]
                };
            }
            case 'DataSource': {
                return {
                    name: 'DataSource',
                    mandatory: [
                        { name: 'fields', type: 'array' }
                    ]
                };
            }
            case 'Enum': {
                return {
                    name: 'Enum',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' },
                        { name: 'fields', type: 'array' }
                    ]
                };
            }
            case 'EnumField': {
                return {
                    name: 'EnumField',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' }
                    ]
                };
            }
            case 'FunctionDecl': {
                return {
                    name: 'FunctionDecl',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'params', type: 'array' }
                    ]
                };
            }
            case 'FunctionParam': {
                return {
                    name: 'FunctionParam',
                    mandatory: [
                        { name: 'optional', type: 'boolean' }
                    ]
                };
            }
            case 'FunctionParamType': {
                return {
                    name: 'FunctionParamType',
                    mandatory: [
                        { name: 'array', type: 'boolean' }
                    ]
                };
            }
            case 'GeneratorDecl': {
                return {
                    name: 'GeneratorDecl',
                    mandatory: [
                        { name: 'fields', type: 'array' }
                    ]
                };
            }
            case 'InternalAttribute': {
                return {
                    name: 'InternalAttribute',
                    mandatory: [
                        { name: 'args', type: 'array' }
                    ]
                };
            }
            case 'InvocationExpr': {
                return {
                    name: 'InvocationExpr',
                    mandatory: [
                        { name: 'args', type: 'array' }
                    ]
                };
            }
            case 'Model': {
                return {
                    name: 'Model',
                    mandatory: [
                        { name: 'declarations', type: 'array' },
                        { name: 'imports', type: 'array' }
                    ]
                };
            }
            case 'ObjectExpr': {
                return {
                    name: 'ObjectExpr',
                    mandatory: [
                        { name: 'fields', type: 'array' }
                    ]
                };
            }
            case 'Plugin': {
                return {
                    name: 'Plugin',
                    mandatory: [
                        { name: 'fields', type: 'array' }
                    ]
                };
            }
            case 'ReferenceExpr': {
                return {
                    name: 'ReferenceExpr',
                    mandatory: [
                        { name: 'args', type: 'array' }
                    ]
                };
            }
            case 'TypeDef': {
                return {
                    name: 'TypeDef',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' },
                        { name: 'fields', type: 'array' }
                    ]
                };
            }
            case 'TypeDefField': {
                return {
                    name: 'TypeDefField',
                    mandatory: [
                        { name: 'attributes', type: 'array' },
                        { name: 'comments', type: 'array' }
                    ]
                };
            }
            case 'TypeDefFieldType': {
                return {
                    name: 'TypeDefFieldType',
                    mandatory: [
                        { name: 'array', type: 'boolean' },
                        { name: 'optional', type: 'boolean' }
                    ]
                };
            }
            default: {
                return {
                    name: type,
                    mandatory: []
                };
            }
        }
    }
}

export const reflection = new ZModelAstReflection();
