update to use new set of SourceX classes

This commit is contained in:
Dave Holoway
2020-06-13 15:16:35 +01:00
parent f4a18ebcdc
commit da8d37aafd
12 changed files with 244 additions and 171 deletions

View File

@@ -6,15 +6,15 @@
*/ */
const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, NullType, WildcardType, TypeVariableType, const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, NullType, WildcardType, TypeVariableType,
TypeVariable, InferredTypeArgument, Field, Method, ReifiedMethod, Parameter, Constructor, signatureToType } = require('java-mti'); TypeVariable, InferredTypeArgument, Field, Method, ReifiedMethod, Parameter, Constructor, signatureToType } = require('java-mti');
const { SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type'); const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation } = require('./source-types2');
const ResolvedImport = require('./parsetypes/resolved-import'); const ResolvedImport = require('./parsetypes/resolved-import');
const ParseProblem = require('./parsetypes/parse-problem'); const ParseProblem = require('./parsetypes/parse-problem');
const { getOperatorType, Token } = require('./tokenizer'); const { getOperatorType, Token } = require('./tokenizer');
const { resolveTypeOrPackage, resolveNextTypeOrPackage } = require('./type-resolver'); const { resolveTypeOrPackage, resolveNextTypeOrPackage } = require('./type-resolver');
const { genericTypeArgs, typeIdent, typeIdentList } = require('./typeident'); const { genericTypeArgs, typeIdent, typeIdentList } = require('./typeident');
const { TokenList } = require("./TokenList"); const { TokenList } = require("./TokenList");
const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, Label, LiteralNumber, LiteralValue, Local, MethodCall, MethodDeclarations, ResolvedIdent, TernaryValue, Value } = require("./body-types"); const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, Label, LiteralNumber, LiteralValue, Local,
const { SourceType, SourceField2, SourceMethod2, SourceConstructor2, SourceParameter2 } = require('./source-types2'); MethodCall, MethodDeclarations, ResolvedIdent, TernaryValue, Value } = require("./body-types");
/** /**
* @typedef {SourceMethod|SourceConstructor|SourceInitialiser} SourceMC * @typedef {SourceMethod|SourceConstructor|SourceInitialiser} SourceMC
@@ -47,11 +47,11 @@ function flattenBlocks(blocks, isMethod) {
* @param {Map<string,JavaType>} typemap * @param {Map<string,JavaType>} typemap
*/ */
function parseBody(method, imports, typemap) { function parseBody(method, imports, typemap) {
const body = method._decl.body().blockArray(); const body = method.body;
if (!body || body.blocks[0].value !== '{') { if (!body || body[0].value !== '{') {
return null; return null;
} }
const tokenlist = new TokenList(flattenBlocks(body.blocks, true)); const tokenlist = new TokenList(flattenBlocks(body, true));
let block = null; let block = null;
let mdecls = new MethodDeclarations(); let mdecls = new MethodDeclarations();
try { try {
@@ -245,7 +245,7 @@ class AssertStatement extends Statement {
*/ */
function localType(modifiers, tokens, mdecls, method, imports, typemap) { function localType(modifiers, tokens, mdecls, method, imports, typemap) {
// local types are inner types with number-prefixed names, eg. Type$1Inner // local types are inner types with number-prefixed names, eg. Type$1Inner
const type = typeDeclaration(method, modifiers, tokens.current, tokens, imports, typemap); const type = typeDeclaration(method.owner.packageName, method, modifiers, tokens.current, tokens, imports, typemap);
mdecls.types.push(type); mdecls.types.push(type);
if (tokens.isValue('extends')) { if (tokens.isValue('extends')) {
const extends_types = typeIdentList(tokens, type, imports, typemap); const extends_types = typeIdentList(tokens, type, imports, typemap);
@@ -268,7 +268,7 @@ function localType(modifiers, tokens, mdecls, method, imports, typemap) {
*/ */
function typeBody(type, tokens, method, imports, typemap) { function typeBody(type, tokens, method, imports, typemap) {
while (!tokens.isValue('}')) { while (!tokens.isValue('}')) {
let modifiers = []; let modifiers = [], annotations = [];
while (tokens.current.kind === 'modifier') { while (tokens.current.kind === 'modifier') {
modifiers.push(tokens.current); modifiers.push(tokens.current);
tokens.inc(); tokens.inc();
@@ -276,7 +276,7 @@ function typeBody(type, tokens, method, imports, typemap) {
switch(tokens.current.kind) { switch(tokens.current.kind) {
case 'ident': case 'ident':
case 'primitive-type': case 'primitive-type':
fmc(modifiers, [], type, tokens, imports, typemap); fmc(modifiers, annotations, [], type, tokens, imports, typemap);
continue; continue;
case 'type-kw': case 'type-kw':
localType(modifiers, tokens, new MethodDeclarations(), method, imports, typemap); localType(modifiers, tokens, new MethodDeclarations(), method, imports, typemap);
@@ -285,11 +285,11 @@ function typeBody(type, tokens, method, imports, typemap) {
switch(tokens.current.value) { switch(tokens.current.value) {
case '<': case '<':
const type_variables = typeVariableList(type, tokens, type, imports, typemap); const type_variables = typeVariableList(type, tokens, type, imports, typemap);
fmc(modifiers, type_variables, type, tokens, imports, typemap); fmc(modifiers, annotations, type_variables, type, tokens, imports, typemap);
continue; continue;
case '@': case '@':
tokens.inc().value === 'interface' tokens.inc().value === 'interface'
? annotationTypeDeclaration(type, modifiers.splice(0,1e9), tokens, imports, typemap) ? annotationTypeDeclaration(type.packageName, type, modifiers.splice(0,1e9), tokens, imports, typemap)
: annotation(tokens, type, imports, typemap); : annotation(tokens, type, imports, typemap);
continue; continue;
case ';': case ';':
@@ -304,19 +304,20 @@ function typeBody(type, tokens, method, imports, typemap) {
/** /**
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {SourceAnnotation[]} annotations
* @param {TypeVariable[]} type_variables * @param {TypeVariable[]} type_variables
* @param {SourceType} type * @param {SourceType} type
* @param {TokenList} tokens * @param {TokenList} tokens
* @param {ResolvedImport[]} imports * @param {ResolvedImport[]} imports
* @param {Map<string,JavaType>} typemap * @param {Map<string,JavaType>} typemap
*/ */
function fmc(modifiers, type_variables, type, tokens, imports, typemap) { function fmc(modifiers, annotations, type_variables, type, tokens, imports, typemap) {
const decl_type = typeIdent(tokens, type, imports, typemap); const decl_type = typeIdent(tokens, type, imports, typemap);
if (decl_type.rawTypeSignature === type.rawTypeSignature) { if (decl_type.rawTypeSignature === type.rawTypeSignature) {
if (tokens.current.value === '(') { if (tokens.current.value === '(') {
// constructor // constructor
const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap); const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap);
const ctr = new SourceConstructor2(type, modifiers, parameters, throws, body); const ctr = new SourceConstructor(type, modifiers, parameters, throws, body);
type.constructors.push(ctr); type.constructors.push(ctr);
return; return;
} }
@@ -328,7 +329,7 @@ function fmc(modifiers, type_variables, type, tokens, imports, typemap) {
} }
if (tokens.current.value === '(') { if (tokens.current.value === '(') {
const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap); const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap);
const method = new SourceMethod2(type, modifiers, decl_type, name, parameters, throws, body); const method = new SourceMethod(type, modifiers, annotations, new SourceTypeIdent([], decl_type), name, parameters, throws, body);
type.methods.push(method); type.methods.push(method);
} else { } else {
if (name) { if (name) {
@@ -336,7 +337,7 @@ function fmc(modifiers, type_variables, type, tokens, imports, typemap) {
addproblem(tokens, ParseProblem.Error(tokens.current, `Fields cannot declare type variables`)); addproblem(tokens, ParseProblem.Error(tokens.current, `Fields cannot declare type variables`));
} }
const locals = var_ident_list(modifiers, decl_type, name, tokens, new MethodDeclarations(), type, imports, typemap); const locals = var_ident_list(modifiers, decl_type, name, tokens, new MethodDeclarations(), type, imports, typemap);
const fields = locals.map(l => new SourceField2(type, modifiers, l.type, l.decltoken)); const fields = locals.map(l => new SourceField(type, modifiers, new SourceTypeIdent([], l.type), l.decltoken));
type.fields.push(...fields); type.fields.push(...fields);
} }
semicolon(tokens); semicolon(tokens);
@@ -362,6 +363,7 @@ function annotation(tokens, scope, imports, typemap) {
} }
/** /**
* @param {string} package_name
* @param {SourceType | SourceMC} scope * @param {SourceType | SourceMC} scope
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {TokenList} tokens * @param {TokenList} tokens
@@ -369,11 +371,12 @@ function annotation(tokens, scope, imports, typemap) {
* @param {ResolvedImport[]} imports * @param {ResolvedImport[]} imports
* @param {Map<string,JavaType>} typemap * @param {Map<string,JavaType>} typemap
*/ */
function annotationTypeDeclaration(scope, modifiers, tokens, imports, typemap) { function annotationTypeDeclaration(package_name, scope, modifiers, tokens, imports, typemap) {
const type = typeDeclaration(scope, modifiers, tokens.current, tokens, imports, typemap); const type = typeDeclaration(package_name, scope, modifiers, tokens.current, tokens, imports, typemap);
} }
/** /**
* @param {string} package_name
* @param {SourceType | SourceMC} scope * @param {SourceType | SourceMC} scope
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {Token} kind_token * @param {Token} kind_token
@@ -381,14 +384,14 @@ function annotationTypeDeclaration(scope, modifiers, tokens, imports, typemap) {
* @param {ResolvedImport[]} imports * @param {ResolvedImport[]} imports
* @param {Map<string,JavaType>} typemap * @param {Map<string,JavaType>} typemap
*/ */
function typeDeclaration(scope, modifiers, kind_token, tokens, imports, typemap) { function typeDeclaration(package_name, scope, modifiers, kind_token, tokens, imports, typemap) {
let name = tokens.inc(); let name = tokens.inc();
if (!tokens.isKind('ident')) { if (!tokens.isKind('ident')) {
name = null; name = null;
addproblem(tokens, ParseProblem.Error(tokens.current, `Type identifier expected`)); addproblem(tokens, ParseProblem.Error(tokens.current, `Type identifier expected`));
return; return;
} }
const type = new SourceType('', scope, '', modifiers.map(m => m.source), kind_token, name); const type = new SourceType(package_name, scope, '', modifiers.map(m => m.source), kind_token, name, typemap);
type.typeVariables = tokens.current.value === '<' type.typeVariables = tokens.current.value === '<'
? typeVariableList(type, tokens, scope, imports, typemap) ? typeVariableList(type, tokens, scope, imports, typemap)
: []; : [];
@@ -516,7 +519,7 @@ function parameterDeclaration(owner, tokens, imports, typemap) {
if (varargs) { if (varargs) {
type = new ArrayType(type, 1); type = new ArrayType(type, 1);
} }
return new SourceParameter2(modifiers, type, varargs, name_token); return new SourceParameter(modifiers, new SourceTypeIdent([], type), varargs, name_token);
} }
/** /**

View File

@@ -331,6 +331,10 @@ class DeclaredVariableBlock extends DeclarationBlock {
return this.varBlock ? this.varBlock.name : ''; return this.varBlock ? this.varBlock.name : '';
} }
get name_token() {
return this.varBlock ? this.varBlock.name_token : null;
}
get type() { get type() {
return this.varBlock ? this.varBlock.type : ''; return this.varBlock ? this.varBlock.type : '';
} }
@@ -475,6 +479,10 @@ class MethodBlock extends MCBlock {
return this.varBlock.name; return this.varBlock.name;
} }
get name_token() {
return this.varBlock.name_token;
}
get type() { get type() {
return this.varBlock.type + (this.postNameArrToken ? this.postNameArrToken.source : ''); return this.varBlock.type + (this.postNameArrToken ? this.postNameArrToken.source : '');
} }

View File

@@ -298,11 +298,14 @@ class ResolvableType extends UnresolvedType {
} }
} }
exports.SourceType = SourceType; const source_types = require('./source-types2');
exports.SourceField = SourceField; exports.SourceType = source_types.SourceType;
exports.SourceMethod = SourceMethod; exports.SourceTypeIdent = source_types.SourceTypeIdent;
exports.SourceParameter = SourceParameter; exports.SourceField = source_types.SourceField;
exports.SourceConstructor = SourceConstructor; exports.SourceMethod = source_types.SourceMethod;
exports.SourceParameter = source_types.SourceParameter;
exports.SourceConstructor = source_types.SourceConstructor;
exports.DefaultConstructor = DefaultConstructor; exports.DefaultConstructor = DefaultConstructor;
exports.SourceInitialiser = SourceInitialiser; exports.SourceInitialiser = source_types.SourceInitialiser;
exports.SourceAnnotation = source_types.SourceAnnotation;
exports.ResolvableType = ResolvableType; exports.ResolvableType = ResolvableType;

View File

@@ -1,5 +1,4 @@
const { CEIType, JavaType, Field, Method, Constructor, Parameter } = require('java-mti'); const { CEIType, JavaType, PrimitiveType, Field, Method, MethodBase, Constructor, Parameter } = require('java-mti');
const { SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type');
const { Token } = require('./tokenizer'); const { Token } = require('./tokenizer');
/** /**
@@ -24,39 +23,69 @@ function generateShortSignature(scope_or_package_name, name) {
class SourceType extends CEIType { class SourceType extends CEIType {
/** /**
* @param {string} packageName * @param {string} packageName
* @param {SourceType|SourceMethod2|SourceConstructor|SourceInitialiser} outer_scope * @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope
* @param {string} docs * @param {string} docs
* @param {string[]} modifiers * @param {string[]} modifiers
* @param {Token} kind_token * @param {Token} kind_token
* @param {Token} name_token * @param {Token} name_token
*/ */
constructor(packageName, outer_scope, docs, modifiers, kind_token, name_token) { constructor(packageName, outer_scope, docs, modifiers, kind_token, name_token, typemap) {
// @ts-ignore // @ts-ignore
super(generateShortSignature(outer_scope || packageName, name_token), kind_token.source, modifiers, docs); super(generateShortSignature(outer_scope || packageName, name_token), kind_token.source, modifiers, docs);
super.packageName = packageName; super.packageName = packageName;
this.kind_token = kind_token; this.kind_token = kind_token;
this.name_token = name_token; this.name_token = name_token;
this.scope = outer_scope; this.scope = outer_scope;
this.typemap = typemap;
/** /**
* Number of local/anonymous types declared in the scope of this type * Number of local/anonymous types declared in the scope of this type
* The number is used when naming them. * The number is used when naming them.
*/ */
this.localTypeCount = 0; this.localTypeCount = 0;
/** @type {SourceConstructor2[]} */ /** @type {SourceTypeIdent[]} */
this.extends_types = [];
/** @type {SourceTypeIdent[]} */
this.implements_types = [];
/** @type {SourceConstructor[]} */
this.constructors = []; this.constructors = [];
/** @type {SourceMethod2[]} */ /** @type {SourceMethod[]} */
this.methods = []; this.methods = [];
/** @type {SourceField2[]} */ /** @type {SourceField[]} */
this.fields = []; this.fields = [];
/** @type {SourceInitialiser[]} */
this.initers = [];
} }
get supers() {
const supertypes = [...this.extends_types, ...this.implements_types].map(x => x.type);
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 SourceField2 extends Field { class SourceTypeIdent {
/**
* @param {Token[]} tokens
* @param {JavaType} type
*/
constructor(tokens, type) {
this.typeTokens = tokens;
this.type = type;
}
}
class SourceField extends Field {
/** /**
* @param {SourceType} owner * @param {SourceType} owner
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {JavaType} field_type * @param {SourceTypeIdent} field_type
* @param {Token} name_token * @param {Token} name_token
*/ */
constructor(owner, modifiers, field_type, name_token) { constructor(owner, modifiers, field_type, name_token) {
@@ -71,15 +100,15 @@ class SourceField2 extends Field {
} }
get type() { get type() {
return this.fieldType; return this.fieldType.type;
} }
} }
class SourceConstructor2 extends Constructor { class SourceConstructor extends Constructor {
/** /**
* @param {SourceType} owner * @param {SourceType} owner
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {SourceParameter2[]} parameters * @param {SourceParameter[]} parameters
* @param {JavaType[]} throws * @param {JavaType[]} throws
* @param {Token[]} body * @param {Token[]} body
*/ */
@@ -88,11 +117,11 @@ class SourceConstructor2 extends Constructor {
this.owner = owner; this.owner = owner;
this.sourceParameters = parameters; this.sourceParameters = parameters;
this.throws = throws; this.throws = throws;
this.body_tokens = body; this.body = body;
} }
get hasImplementation() { get hasImplementation() {
return !!this.body_tokens; return !!this.body;
} }
get parameterCount() { get parameterCount() {
@@ -100,7 +129,7 @@ class SourceConstructor2 extends Constructor {
} }
/** /**
* @returns {SourceParameter2[]} * @returns {SourceParameter[]}
*/ */
get parameters() { get parameters() {
return this.sourceParameters; return this.sourceParameters;
@@ -114,27 +143,29 @@ class SourceConstructor2 extends Constructor {
} }
} }
class SourceMethod2 extends Method { class SourceMethod extends Method {
/** /**
* @param {SourceType} owner * @param {SourceType} owner
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {JavaType} method_type * @param {SourceAnnotation[]} annotations
* @param {SourceTypeIdent} method_type_ident
* @param {Token} name_token * @param {Token} name_token
* @param {SourceParameter2[]} parameters * @param {SourceParameter[]} parameters
* @param {JavaType[]} throws * @param {JavaType[]} throws
* @param {Token[]} body * @param {Token[]} body
*/ */
constructor(owner, modifiers, method_type, name_token, parameters, throws, 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), ''); super(owner, name_token ? name_token.value : '', modifiers.map(m => m.value), '');
this.annotations = annotations;
this.owner = owner; this.owner = owner;
this.methodType = method_type; this.methodTypeIdent = method_type_ident;
this.sourceParameters = parameters; this.sourceParameters = parameters;
this.throws = throws; this.throws = throws;
this.body_tokens = body; this.body = body;
} }
get hasImplementation() { get hasImplementation() {
return !!this.body_tokens; return !!this.body;
} }
get parameterCount() { get parameterCount() {
@@ -142,7 +173,7 @@ class SourceMethod2 extends Method {
} }
/** /**
* @returns {SourceParameter2[]} * @returns {SourceParameter[]}
*/ */
get parameters() { get parameters() {
return this.sourceParameters; return this.sourceParameters;
@@ -152,26 +183,64 @@ class SourceMethod2 extends Method {
* @returns {JavaType} * @returns {JavaType}
*/ */
get returnType() { get returnType() {
return this.methodType; return this.methodTypeIdent.type;
} }
} }
class SourceParameter2 extends Parameter { 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.body = body;
}
/**
* @returns {SourceParameter[]}
*/
get parameters() {
return [];
}
get returnType() {
return PrimitiveType.map.V;
}
}
class SourceParameter extends Parameter {
/** /**
* @param {Token[]} modifiers * @param {Token[]} modifiers
* @param {JavaType} type * @param {SourceTypeIdent} typeident
* @param {boolean} varargs * @param {boolean} varargs
* @param {Token} name_token * @param {Token} name_token
*/ */
constructor(modifiers, type, varargs, name_token) { constructor(modifiers, typeident, varargs, name_token) {
super(name_token ? name_token.value : '', type, varargs); super(name_token ? name_token.value : '', typeident.type, varargs);
this.name_token = name_token; this.name_token = name_token;
this.modifiers = modifiers; this.modifiers = modifiers;
this.paramTypeIdent = typeident;
}
}
class SourceAnnotation {
/**
* @param {SourceTypeIdent} typeident
*/
constructor(typeident) {
this.annotationTypeIdent = typeident;
} }
} }
exports.SourceType = SourceType; exports.SourceType = SourceType;
exports.SourceField2 = SourceField2; exports.SourceTypeIdent = SourceTypeIdent;
exports.SourceMethod2 = SourceMethod2; exports.SourceField = SourceField;
exports.SourceParameter2 = SourceParameter2; exports.SourceMethod = SourceMethod;
exports.SourceConstructor2 = SourceConstructor2; exports.SourceParameter = SourceParameter;
exports.SourceConstructor = SourceConstructor;
exports.SourceInitialiser = SourceInitialiser;
exports.SourceAnnotation = SourceAnnotation;

View File

@@ -1,8 +1,8 @@
const { JavaType } = require('java-mti'); const { ArrayType, JavaType, TypeVariable } = require('java-mti');
const { ModuleBlock, TypeDeclBlock } = require('./parser9'); const { ModuleBlock, TypeDeclBlock } = require('./parser9');
const { resolveImports } = require('../java/import-resolver'); const { resolveImports } = require('../java/import-resolver');
const ResolvedImport = require('../java/parsetypes/resolved-import'); const ResolvedImport = require('../java/parsetypes/resolved-import');
const { SourceType, SourceMethod, SourceConstructor, ResolvableType } = require('./source-type'); const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation } = require('./source-type');
const { parseBody, flattenBlocks } = require('./body-parser3'); const { parseBody, flattenBlocks } = require('./body-parser3');
const { TokenList } = require('./TokenList'); const { TokenList } = require('./TokenList');
const { typeIdent } = require('./typeident'); const { typeIdent } = require('./typeident');
@@ -10,57 +10,102 @@ const { typeIdent } = require('./typeident');
/** /**
* @param {ModuleBlock} mod * @param {ModuleBlock} mod
* @param {string} owner_typename * @param {SourceType} outer_type
* @param {ModuleBlock|TypeDeclBlock} parent * @param {ModuleBlock|TypeDeclBlock} parent
* @param {SourceType[]} source_types * @param {SourceType[]} source_types
* @param {Map<string,JavaType>} typemap * @param {Map<string,JavaType>} typemap
*/ */
function getSourceTypes(mod, owner_typename, parent, source_types, typemap) { function getSourceTypes(mod, outer_type, parent, source_types, typemap) {
parent.types.forEach(type => { parent.types.forEach(type => {
const qualifiedTypeName = `${owner_typename}${type.simpleName}`; const t = new SourceType(mod.packageName, outer_type, '', type.modifiers.map(m => m.value), type.kindToken, type.name_token, typemap);
// we add the names of type variables here, but we resolve any bounds later t.typeVariables = type.typevars.map(tv => new TypeVariable(t, tv.name, [new TypeVariable.Bound(t, 'Ljava/lang/Object;', false)]));
//const typevar_names = type.typevars.map(tv => tv.name);
//const mti = new MTI().addType(package_name, '', mods, type.kind(), qualifiedTypeName, typevar_names);
const t = new SourceType(mod, type, qualifiedTypeName, typemap);
source_types.push(t); source_types.push(t);
getSourceTypes(mod, `${qualifiedTypeName}$`, type, source_types, typemap); getSourceTypes(mod, t, type, source_types, typemap);
}); });
} }
/** /**
* @param {ResolvableType} rt * @param {TokenList} tokens
* @param {SourceType|SourceMethod|SourceConstructor} scope * @param {ModuleBlock|TypeDeclBlock} parent
* @param {ResolvedImport[]} resolved_imports * @param {ResolvedImport[]} imports
* @param {Map<string,JavaType>} typemap * @param {Map<string,JavaType>} typemap
*/ */
function resolveResolvableType(rt, scope, resolved_imports, typemap) { function populateTypes(tokens, parent, imports, typemap) {
const tokens = new TokenList(flattenBlocks(rt.typeTokens, false));
rt._resolved = typeIdent(tokens, scope, resolved_imports, typemap);
}
/** parent.types.forEach(type => {
* const source_type = typemap.get(type.shortSignature);
* @param {SourceType} source_type if (source_type instanceof SourceType) {
* @param {ResolvedImport[]} resolved_imports if (type.extends_decl)
* @param {Map<string,JavaType>} typemap source_type.extends_types = resolveTypeList(source_type, type.extends_decl);
*/ if (type.implements_decl)
function resolveResolvableTypes(source_type, resolved_imports, typemap) { source_type.implements_types = resolveTypeList(source_type, type.implements_decl);
source_type.extends_types.forEach(rt => resolveResolvableType(rt, source_type, resolved_imports, typemap));
source_type.implements_types.forEach(rt => resolveResolvableType(rt, source_type, resolved_imports, typemap));
source_type.fields.forEach(f => resolveResolvableType(f._type, source_type, resolved_imports, typemap)); // fields
source_type.fields = type.fields.map(f => {
// methods and constructors can have parameterized types const field_type = resolveTypeFromTokens(source_type, f);
source_type.methods.forEach(m => { return new SourceField(source_type, f.modifiers, field_type, f.name_token);
resolveResolvableType(m._returnType, m, resolved_imports, typemap); });
m.parameters.forEach(p => resolveResolvableType(p._paramType, m, resolved_imports, typemap)); // methods
source_type.methods = type.methods.map(m => {
const method_type = resolveTypeFromTokens(source_type, m);
const params = m.parameters.map(p => {
let param_type = resolveTypeFromTokens(source_type, p);
return new SourceParameter(p.modifiers, param_type, p.isVarArgs, p.name_token);
})
const annotations = m.annotations.map(a => new SourceAnnotation(resolveTypeFromTokens(source_type, {typeTokens: [a.blockArray().blocks.slice().pop()]})))
return new SourceMethod(source_type, m.modifiers, annotations, method_type, m.name_token, params, [], flattenBlocks([m.body()], true));
})
// constructors
source_type.constructors = type.constructors.map(c => {
const params = c.parameters.map(p => {
const param_type = resolveTypeFromTokens(source_type, p);
return new SourceParameter(p.modifiers, param_type, p.isVarArgs, p.name_token);
})
return new SourceConstructor(source_type, c.modifiers, params, [], flattenBlocks([c.body()], true));
})
// initialisers
source_type.initers = type.initialisers.map(i => {
return new SourceInitialiser(source_type, i.modifiers, flattenBlocks([i.body()], true));
})
}
populateTypes(tokens, type, imports, typemap);
}); });
source_type.declaredConstructors.forEach(c => { function resolveTypeFromTokens(scope, decl) {
c.parameters.forEach(p => resolveResolvableType(p._paramType, c, resolved_imports, typemap)); const typetokens = flattenBlocks([decl.typeTokens[0]], false);
}); tokens.current = tokens.tokens[tokens.idx = tokens.tokens.indexOf(typetokens[0])];
let type = typeIdent(tokens, scope, imports, typemap);
if (decl.varBlock && decl.varBlock.post_name_arr_token) {
type = new ArrayType(type, decl.varBlock.post_name_arr_token.source.replace(/[^\[]/g,'').length);
}
if (decl.isVarArgs) {
type = new ArrayType(type, 1);
}
return new SourceTypeIdent(typetokens, type);
}
function resolveTypeList(scope, eit_decl) {
const types = [];
const eit_tokens = flattenBlocks([eit_decl], false);
tokens.current = tokens.tokens[tokens.idx = tokens.tokens.indexOf(eit_tokens[0])];
tokens.inc(); // bypass extends/implements/throws keyword
for (;;) {
const start = tokens.idx;
const type = typeIdent(tokens, scope, imports, typemap);
let end = tokens.idx - 1;
while (tokens.tokens[end].kind === 'wsc') {
end -= 1;
}
types.push(new SourceTypeIdent(tokens.tokens.slice(start, end + 1), type));
if (!tokens.isValue(',')) {
break;
}
}
return types;
}
} }
/** /**
* @param {ModuleBlock} mod * @param {ModuleBlock} mod
* @param {Map<string, JavaType>} androidLibrary * @param {Map<string, JavaType>} androidLibrary
@@ -70,30 +115,25 @@ function validate(mod, androidLibrary) {
/** @type {SourceType[]} */ /** @type {SourceType[]} */
const source_types = []; const source_types = [];
getSourceTypes(mod, '', mod, source_types, androidLibrary); getSourceTypes(mod, null, mod, source_types, androidLibrary);
const imports = resolveImports(androidLibrary, source_types, mod.imports, mod.packageName); const imports = resolveImports(androidLibrary, source_types, mod.imports, mod.packageName);
source_types.forEach(t => { populateTypes(new TokenList(flattenBlocks(mod.blocks, false)), mod, imports.resolved, imports.typemap);
resolveResolvableTypes(t, imports.resolved, imports.typemap);
});
let probs = []; let probs = [];
source_types.forEach(t => { source_types.forEach(t => {
t.initers.forEach(i => { t.initers.forEach(i => {
console.log('<clinit>()');
const parsed = parseBody(i, imports.resolved, imports.typemap); const parsed = parseBody(i, imports.resolved, imports.typemap);
if (parsed) if (parsed)
probs = probs.concat(parsed.problems) probs = probs.concat(parsed.problems)
}) })
t.declaredConstructors.forEach(c => { t.constructors.forEach(c => {
console.log(c.label);
const parsed = parseBody(c, imports.resolved, imports.typemap); const parsed = parseBody(c, imports.resolved, imports.typemap);
if (parsed) if (parsed)
probs = probs.concat(parsed.problems) probs = probs.concat(parsed.problems)
}) })
t.methods.forEach(m => { t.methods.forEach(m => {
console.log(m.label);
const parsed = parseBody(m, imports.resolved, imports.typemap); const parsed = parseBody(m, imports.resolved, imports.typemap);
if (parsed) if (parsed)
probs = probs.concat(parsed.problems) probs = probs.concat(parsed.problems)
@@ -107,7 +147,6 @@ function validate(mod, androidLibrary) {
require('./validation/parse-errors'), require('./validation/parse-errors'),
require('./validation/modifier-errors'), require('./validation/modifier-errors'),
require('./validation/unresolved-imports'), require('./validation/unresolved-imports'),
require('./validation/unresolved-types'),
require('./validation/invalid-types'), require('./validation/invalid-types'),
require('./validation/bad-extends'), require('./validation/bad-extends'),
require('./validation/bad-implements'), require('./validation/bad-implements'),

View File

@@ -10,7 +10,7 @@ function checkExtends(source_type, probs) {
if (source_type.extends_types.length === 0) { if (source_type.extends_types.length === 0) {
return; return;
} }
const supertypes = source_type.extends_types.map(st => st.resolved); const supertypes = source_type.extends_types.map(st => st.type);
const supertype = supertypes[0]; const supertype = supertypes[0];
if (source_type.typeKind === 'enum') { if (source_type.typeKind === 'enum') {
probs.push(ParseProblem.Error(source_type.extends_types[0].typeTokens, `Enum types cannot declare a superclass`)); probs.push(ParseProblem.Error(source_type.extends_types[0].typeTokens, `Enum types cannot declare a superclass`));

View File

@@ -11,7 +11,7 @@ function checkImplements(source_type, probs) {
if (source_type.implements_types.length === 0) { if (source_type.implements_types.length === 0) {
return; return;
} }
const interfaces = source_type.implements_types.map(it => it.resolved); const interfaces = source_type.implements_types.map(it => it.type);
if (source_type.typeKind === 'interface') { if (source_type.typeKind === 'interface') {
probs.push(ParseProblem.Error(source_type.implements_types[0].typeTokens, `Interface types cannot declare an implements section`)); probs.push(ParseProblem.Error(source_type.implements_types[0].typeTokens, `Interface types cannot declare an implements section`));
} }

View File

@@ -1,6 +1,6 @@
const { ModuleBlock, TextBlock } = require('../parser9'); const { ModuleBlock } = require('../parser9');
const ParseProblem = require('../parsetypes/parse-problem'); const ParseProblem = require('../parsetypes/parse-problem');
const {SourceType} = require('../source-type'); const {SourceType, SourceAnnotation} = require('../source-type');
const {CEIType, Method} = require('java-mti'); const {CEIType, Method} = require('java-mti');
function nonAbstractLabel(label) { function nonAbstractLabel(label) {
@@ -19,10 +19,10 @@ function checkOverrides(source_type, probs) {
return; return;
} }
/** @type {{ann:TextBlock, method:Method, method_id:string}[]} */ /** @type {{ann:SourceAnnotation, method:Method, method_id:string}[]} */
const overriden_methods = []; const overriden_methods = [];
source_type.methods.reduce((arr, method) => { source_type.methods.reduce((arr, method) => {
const ann = method._decl.annotations.find(a => /^@\s*Override$/.test(a.source)); const ann = method.annotations.find(a => /^Override$/.test(a.annotationTypeIdent.type.simpleTypeName));
if (ann) { if (ann) {
arr.push({ arr.push({
ann, ann,
@@ -52,7 +52,7 @@ function checkOverrides(source_type, probs) {
overriden_methods.forEach(x => { overriden_methods.forEach(x => {
if (!methods.has(x.method_id)) { if (!methods.has(x.method_id)) {
probs.push(ParseProblem.Error(x.ann, `${x.method.label} does not override a matching method in any inherited type or interface`)); probs.push(ParseProblem.Error(x.ann.annotationTypeIdent.typeTokens, `${x.method.label} does not override a matching method in any inherited type or interface`));
} }
}) })
} }

View File

@@ -1,11 +1,14 @@
const { ModuleBlock, TypeDeclBlock } = require('../parser9'); const { ModuleBlock } = require('../parser9');
const ParseProblem = require('../parsetypes/parse-problem'); const ParseProblem = require('../parsetypes/parse-problem');
const {SourceType} = require('../source-type'); const {SourceType} = require('../source-type');
const {JavaType, ArrayType, CEIType, TypeArgument, UnresolvedType} = require('java-mti'); const {Token} = require('../tokenizer');
const { AnyType } = require('../body-types'); const {JavaType} = require('java-mti');
/** /**
* @param {JavaType} type * @param {JavaType} type
* @param {boolean} is_return_type
* @param {Token[]} typeTokens
* @param {ParseProblem[]} probs
*/ */
function checkType(type, is_return_type, typeTokens, probs) { function checkType(type, is_return_type, typeTokens, probs) {
const typesig = type.typeSignature; const typesig = type.typeSignature;
@@ -26,11 +29,11 @@ function checkType(type, is_return_type, typeTokens, probs) {
* @param {*} probs * @param {*} probs
*/ */
function checkInvalidTypes(type, probs) { function checkInvalidTypes(type, probs) {
type.fields.forEach(f => checkType(f.type, false, f._decl.typeTokens, probs)); type.fields.forEach(f => checkType(f.type, false, f.fieldType.typeTokens, probs));
type.methods.forEach(m => { type.methods.forEach(m => {
checkType(m.returnType, true, m._decl.typeTokens, probs); checkType(m.returnType, true, m.methodTypeIdent.typeTokens, probs);
m.parameters.forEach(p => { m.parameters.forEach(p => {
checkType(p.type, false, p._decl.typeTokens, probs); checkType(p.type, false, p.paramTypeIdent.typeTokens, probs);
}) })
}) })
} }

View File

@@ -22,7 +22,7 @@ function checkConstructor(source_type, probs) {
if (!superclass.constructors.find(c => c.parameterCount === 0)) { if (!superclass.constructors.find(c => c.parameterCount === 0)) {
// the source type has no declared constructors, but the superclass // the source type has no declared constructors, but the superclass
// does not include a default (parameterless) constructor // does not include a default (parameterless) constructor
probs.push(ParseProblem.Error(source_type._decl.name_token, `Type ${superclass.fullyDottedRawName} requires a constructor to be declared because the inherited class '${superclass.fullyDottedRawName}' does not define a default constructor.`)); probs.push(ParseProblem.Error(source_type.name_token, `Class '${source_type.fullyDottedRawName}' requires a constructor to be declared because the inherited class '${superclass.fullyDottedRawName}' does not define a default constructor.`));
} }
} }

View File

@@ -49,7 +49,7 @@ function checkImplementedInterfaces(source_type, probs) {
} }
}) })
if (missing_methods.length) { if (missing_methods.length) {
probs.push(ParseProblem.Error(source_type._decl.kindToken, `Non-abstract ${source_type.typeKind} '${source_type.fullyDottedRawName}' does not implement the following methods from interface '${intf.fullyDottedRawName}':\n${missing_methods.join('\n')}`)); probs.push(ParseProblem.Error(source_type.kind_token, `Non-abstract ${source_type.typeKind} '${source_type.fullyDottedRawName}' does not implement the following methods from interface '${intf.fullyDottedRawName}':\n${missing_methods.join('\n')}`));
} }
}); });
} }

View File

@@ -1,52 +0,0 @@
const { ModuleBlock, TypeDeclBlock } = require('../parser9');
const ParseProblem = require('../parsetypes/parse-problem');
const {SourceType} = require('../source-type');
const {JavaType, CEIType, TypeArgument, UnresolvedType} = require('java-mti')
/**
* @param {JavaType} type
*/
function checkType(type, typeTokens, probs) {
if (type instanceof UnresolvedType) {
probs.push(ParseProblem.Error(typeTokens, `Unknown type: ${type.label}`));
return;
}
if (type instanceof CEIType) {
type.typeVariables.forEach(tv => {
if (tv instanceof TypeArgument) {
checkType(tv.type, typeTokens, probs);
}
})
}
}
/**
* @param {SourceType} type
* @param {*} probs
*/
function checkUnresolvedTypes(type, probs) {
type.extends_types.forEach(superclass => checkType(superclass.resolved, superclass.typeTokens, probs));
type.implements_types.forEach(superintf => checkType(superintf.resolved, superintf.typeTokens, probs));
type.fields.forEach(f => checkType(f.type, f._decl.typeTokens, probs));
type.methods.forEach(m => {
checkType(m.returnType, m._decl.typeTokens, probs);
m.parameters.forEach(p => {
checkType(p.type, p._decl.typeTokens, probs);
})
})
}
/**
* @param {ModuleBlock} mod
* @param {*} imports
* @param {SourceType[]} source_types
*/
module.exports = function(mod, imports, source_types) {
/** @type {ParseProblem[]} */
const probs = [];
source_types.forEach(type => checkUnresolvedTypes(type, probs));
return probs;
}