const { CEIType, JavaType, PrimitiveType, Field, Method, MethodBase, Constructor, Parameter } = require('java-mti'); const { Token } = require('./tokenizer'); /** * @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser|string} scope_or_package_name * @param {string} name */ function generateShortSignature(scope_or_package_name, name) { if (scope_or_package_name instanceof SourceType) { const type = scope_or_package_name; return `${type._rawShortSignature}$${name}`; } if (scope_or_package_name instanceof SourceMethod || scope_or_package_name instanceof SourceConstructor || scope_or_package_name instanceof SourceInitialiser) { const method = scope_or_package_name; return `${method.owner._rawShortSignature}$${method.owner.localTypeCount += 1}${name}`; } const pkgname = scope_or_package_name; return pkgname ?`${pkgname.replace(/\./g, '/')}/${name}` : name; } class SourceType extends CEIType { /** * @param {string} packageName * @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope * @param {string} docs * @param {Token[]} modifiers * @param {string} typeKind * @param {Token} kind_token * @param {Token} name_token */ constructor(packageName, outer_scope, docs, modifiers, typeKind, kind_token, name_token, typemap) { // @ts-ignore super(generateShortSignature(outer_scope || packageName, name_token.value), typeKind, modifiers.map(m => m.source), docs); super.packageName = packageName; this.modifierTokens = modifiers; this.kind_token = kind_token; this.nameToken = name_token; this.scope = outer_scope; this.typemap = typemap; /** * Number of local/anonymous types declared in the scope of this type * The number is used when naming them. */ this.localTypeCount = 0; /** @type {SourceTypeIdent[]} */ this.extends_types = []; /** @type {SourceTypeIdent[]} */ this.implements_types = []; /** @type {SourceConstructor[]} */ this.constructors = []; /** @type {SourceMethod[]} */ this.methods = []; /** @type {SourceField[]} */ this.fields = []; /** @type {SourceInitialiser[]} */ this.initers = []; } /** * @param {string} package_name * @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope * @param {string} name */ static getShortSignature(package_name, outer_scope, name) { return generateShortSignature(outer_scope || package_name || '', name); } /** * @param {Token[]} mods */ setModifierTokens(mods) { this.modifierTokens = mods; this.modifiers = mods.map(m => m.source); } get supers() { const supertypes = [...this.extends_types, ...this.implements_types].map(x => x.resolved); if (this.typeKind === 'enum') { /** @type {CEIType} */ const enumtype = this.typemap.get('java/lang/Enum'); supertypes.unshift(enumtype.specialise([this])); } else if (!supertypes.find(type => type.typeKind === 'class')) { supertypes.unshift(this.typemap.get('java/lang/Object')); } return supertypes; } } class SourceTypeIdent { /** * @param {Token[]} tokens * @param {JavaType} type */ constructor(tokens, type) { this.tokens = tokens; this.resolved = type; } } class SourceField extends Field { /** * @param {SourceType} owner * @param {Token[]} modifiers * @param {SourceTypeIdent} field_type_ident * @param {Token} name_token */ constructor(owner, modifiers, field_type_ident, name_token) { super(modifiers.map(m => m.value), ''); this.owner = owner; this.modifierTokens = modifiers; this.fieldTypeIdent = field_type_ident; this.nameToken = name_token; } get name() { return this.nameToken ? this.nameToken.value : ''; } get type() { return this.fieldTypeIdent.resolved; } } class SourceConstructor extends Constructor { /** * @param {SourceType} owner * @param {Token[]} modifiers * @param {SourceParameter[]} parameters * @param {JavaType[]} throws * @param {Token[]} body */ constructor(owner, modifiers, parameters, throws, body) { super(owner, modifiers.map(m => m.value), ''); this.owner = owner; this.modifierTokens = modifiers; this.sourceParameters = parameters; this.throws = throws; this.body = body; } get hasImplementation() { return !!this.body; } get parameterCount() { return this.sourceParameters.length; } /** * @returns {SourceParameter[]} */ get parameters() { return this.sourceParameters; } /** * @returns {SourceType} */ get returnType() { return this.owner; } } class SourceMethod extends Method { /** * @param {SourceType} owner * @param {Token[]} modifiers * @param {SourceAnnotation[]} annotations * @param {SourceTypeIdent} method_type_ident * @param {Token} name_token * @param {SourceParameter[]} parameters * @param {JavaType[]} throws * @param {Token[]} body */ constructor(owner, modifiers, annotations, method_type_ident, name_token, parameters, throws, body) { super(owner, name_token ? name_token.value : '', modifiers.map(m => m.value), ''); this.annotations = annotations; this.owner = owner; this.modifierTokens = modifiers; this.returnTypeIdent = method_type_ident; this.nameToken = name_token; this.sourceParameters = parameters; this.throws = throws; this.body = body; } get hasImplementation() { return !!this.body; } get parameterCount() { return this.sourceParameters.length; } /** * @returns {SourceParameter[]} */ get parameters() { return this.sourceParameters; } /** * @returns {JavaType} */ get returnType() { return this.returnTypeIdent.resolved; } } class SourceInitialiser extends MethodBase { /** * @param {SourceType} owner * @param {Token[]} modifiers * @param {Token[]} body */ constructor(owner, modifiers, body) { super(owner, modifiers.map(m => m.value), ''); /** @type {SourceType} */ this.owner = owner; this.modifierTokens = modifiers; this.body = body; } /** * @returns {SourceParameter[]} */ get parameters() { return []; } get returnType() { return PrimitiveType.map.V; } } class SourceParameter extends Parameter { /** * @param {Token[]} modifiers * @param {SourceTypeIdent} typeident * @param {boolean} varargs * @param {Token} name_token */ constructor(modifiers, typeident, varargs, name_token) { super(name_token ? name_token.value : '', typeident.resolved, varargs); this.nameToken = name_token; this.modifierTokens = modifiers; this.paramTypeIdent = typeident; } get type() { return this.paramTypeIdent.resolved; } } class SourceAnnotation { /** * @param {SourceTypeIdent} typeident */ constructor(typeident) { this.annotationTypeIdent = typeident; } get type() { return this.annotationTypeIdent.resolved; } } class SourcePackage { /** * @param {Token[]} tokens * @param {string} name */ constructor(tokens, name) { this.tokens = tokens; this.name = name; } } class SourceImport { /** * @param {Token[]} tokens * @param {Token[]} name_tokens * @param {string} pkg_name * @param {Token} static_token * @param {Token} asterisk_token * @param {import('./parsetypes/resolved-import')} resolved */ constructor(tokens, name_tokens, pkg_name, static_token, asterisk_token, resolved) { this.tokens = tokens; this.nameTokens = name_tokens; this.package_name = pkg_name; this.staticToken = static_token; this.asteriskToken = asterisk_token; this.resolved = resolved; } get isDemandLoad() { return !!this.asteriskToken; } get isStatic() { return !!this.staticToken; } } class SourceUnit { /** @type {SourcePackage} */ package_ = null; /** @type {SourceImport[]} */ imports = []; /** @type {SourceType[]} */ types = []; } exports.SourceType = SourceType; exports.SourceTypeIdent = SourceTypeIdent; exports.SourceField = SourceField; exports.SourceMethod = SourceMethod; exports.SourceParameter = SourceParameter; exports.SourceConstructor = SourceConstructor; exports.SourceInitialiser = SourceInitialiser; exports.SourceAnnotation = SourceAnnotation; exports.SourceUnit = SourceUnit; exports.SourcePackage = SourcePackage; exports.SourceImport = SourceImport;