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,
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 ParseProblem = require('./parsetypes/parse-problem');
const { getOperatorType, Token } = require('./tokenizer');
const { resolveTypeOrPackage, resolveNextTypeOrPackage } = require('./type-resolver');
const { genericTypeArgs, typeIdent, typeIdentList } = require('./typeident');
const { TokenList } = require("./TokenList");
const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, Label, LiteralNumber, LiteralValue, Local, MethodCall, MethodDeclarations, ResolvedIdent, TernaryValue, Value } = require("./body-types");
const { SourceType, SourceField2, SourceMethod2, SourceConstructor2, SourceParameter2 } = require('./source-types2');
const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, Label, LiteralNumber, LiteralValue, Local,
MethodCall, MethodDeclarations, ResolvedIdent, TernaryValue, Value } = require("./body-types");
/**
* @typedef {SourceMethod|SourceConstructor|SourceInitialiser} SourceMC
@@ -47,11 +47,11 @@ function flattenBlocks(blocks, isMethod) {
* @param {Map<string,JavaType>} typemap
*/
function parseBody(method, imports, typemap) {
const body = method._decl.body().blockArray();
if (!body || body.blocks[0].value !== '{') {
const body = method.body;
if (!body || body[0].value !== '{') {
return null;
}
const tokenlist = new TokenList(flattenBlocks(body.blocks, true));
const tokenlist = new TokenList(flattenBlocks(body, true));
let block = null;
let mdecls = new MethodDeclarations();
try {
@@ -245,7 +245,7 @@ class AssertStatement extends Statement {
*/
function localType(modifiers, tokens, mdecls, method, imports, typemap) {
// 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);
if (tokens.isValue('extends')) {
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) {
while (!tokens.isValue('}')) {
let modifiers = [];
let modifiers = [], annotations = [];
while (tokens.current.kind === 'modifier') {
modifiers.push(tokens.current);
tokens.inc();
@@ -276,7 +276,7 @@ function typeBody(type, tokens, method, imports, typemap) {
switch(tokens.current.kind) {
case 'ident':
case 'primitive-type':
fmc(modifiers, [], type, tokens, imports, typemap);
fmc(modifiers, annotations, [], type, tokens, imports, typemap);
continue;
case 'type-kw':
localType(modifiers, tokens, new MethodDeclarations(), method, imports, typemap);
@@ -285,11 +285,11 @@ function typeBody(type, tokens, method, imports, typemap) {
switch(tokens.current.value) {
case '<':
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;
case '@':
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);
continue;
case ';':
@@ -304,19 +304,20 @@ function typeBody(type, tokens, method, imports, typemap) {
/**
* @param {Token[]} modifiers
* @param {SourceAnnotation[]} annotations
* @param {TypeVariable[]} type_variables
* @param {SourceType} type
* @param {TokenList} tokens
* @param {ResolvedImport[]} imports
* @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);
if (decl_type.rawTypeSignature === type.rawTypeSignature) {
if (tokens.current.value === '(') {
// constructor
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);
return;
}
@@ -328,7 +329,7 @@ function fmc(modifiers, type_variables, type, tokens, imports, typemap) {
}
if (tokens.current.value === '(') {
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);
} else {
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`));
}
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);
}
semicolon(tokens);
@@ -362,6 +363,7 @@ function annotation(tokens, scope, imports, typemap) {
}
/**
* @param {string} package_name
* @param {SourceType | SourceMC} scope
* @param {Token[]} modifiers
* @param {TokenList} tokens
@@ -369,11 +371,12 @@ function annotation(tokens, scope, imports, typemap) {
* @param {ResolvedImport[]} imports
* @param {Map<string,JavaType>} typemap
*/
function annotationTypeDeclaration(scope, modifiers, tokens, imports, typemap) {
const type = typeDeclaration(scope, modifiers, tokens.current, tokens, imports, typemap);
function annotationTypeDeclaration(package_name, scope, modifiers, tokens, imports, typemap) {
const type = typeDeclaration(package_name, scope, modifiers, tokens.current, tokens, imports, typemap);
}
/**
* @param {string} package_name
* @param {SourceType | SourceMC} scope
* @param {Token[]} modifiers
* @param {Token} kind_token
@@ -381,14 +384,14 @@ function annotationTypeDeclaration(scope, modifiers, tokens, imports, typemap) {
* @param {ResolvedImport[]} imports
* @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();
if (!tokens.isKind('ident')) {
name = null;
addproblem(tokens, ParseProblem.Error(tokens.current, `Type identifier expected`));
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 === '<'
? typeVariableList(type, tokens, scope, imports, typemap)
: [];
@@ -516,7 +519,7 @@ function parameterDeclaration(owner, tokens, imports, typemap) {
if (varargs) {
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 : '';
}
get name_token() {
return this.varBlock ? this.varBlock.name_token : null;
}
get type() {
return this.varBlock ? this.varBlock.type : '';
}
@@ -475,6 +479,10 @@ class MethodBlock extends MCBlock {
return this.varBlock.name;
}
get name_token() {
return this.varBlock.name_token;
}
get type() {
return this.varBlock.type + (this.postNameArrToken ? this.postNameArrToken.source : '');
}

View File

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

View File

@@ -1,5 +1,4 @@
const { CEIType, JavaType, Field, Method, Constructor, Parameter } = require('java-mti');
const { SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type');
const { CEIType, JavaType, PrimitiveType, Field, Method, MethodBase, Constructor, Parameter } = require('java-mti');
const { Token } = require('./tokenizer');
/**
@@ -24,39 +23,69 @@ function generateShortSignature(scope_or_package_name, name) {
class SourceType extends CEIType {
/**
* @param {string} packageName
* @param {SourceType|SourceMethod2|SourceConstructor|SourceInitialiser} outer_scope
* @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope
* @param {string} docs
* @param {string[]} modifiers
* @param {Token} kind_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
super(generateShortSignature(outer_scope || packageName, name_token), kind_token.source, modifiers, docs);
super.packageName = packageName;
this.kind_token = kind_token;
this.name_token = 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 {SourceConstructor2[]} */
/** @type {SourceTypeIdent[]} */
this.extends_types = [];
/** @type {SourceTypeIdent[]} */
this.implements_types = [];
/** @type {SourceConstructor[]} */
this.constructors = [];
/** @type {SourceMethod2[]} */
/** @type {SourceMethod[]} */
this.methods = [];
/** @type {SourceField2[]} */
/** @type {SourceField[]} */
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 {Token[]} modifiers
* @param {JavaType} field_type
* @param {SourceTypeIdent} field_type
* @param {Token} name_token
*/
constructor(owner, modifiers, field_type, name_token) {
@@ -71,15 +100,15 @@ class SourceField2 extends Field {
}
get type() {
return this.fieldType;
return this.fieldType.type;
}
}
class SourceConstructor2 extends Constructor {
class SourceConstructor extends Constructor {
/**
* @param {SourceType} owner
* @param {Token[]} modifiers
* @param {SourceParameter2[]} parameters
* @param {SourceParameter[]} parameters
* @param {JavaType[]} throws
* @param {Token[]} body
*/
@@ -88,11 +117,11 @@ class SourceConstructor2 extends Constructor {
this.owner = owner;
this.sourceParameters = parameters;
this.throws = throws;
this.body_tokens = body;
this.body = body;
}
get hasImplementation() {
return !!this.body_tokens;
return !!this.body;
}
get parameterCount() {
@@ -100,7 +129,7 @@ class SourceConstructor2 extends Constructor {
}
/**
* @returns {SourceParameter2[]}
* @returns {SourceParameter[]}
*/
get parameters() {
return this.sourceParameters;
@@ -114,27 +143,29 @@ class SourceConstructor2 extends Constructor {
}
}
class SourceMethod2 extends Method {
class SourceMethod extends Method {
/**
* @param {SourceType} owner
* @param {Token[]} modifiers
* @param {JavaType} method_type
* @param {SourceAnnotation[]} annotations
* @param {SourceTypeIdent} method_type_ident
* @param {Token} name_token
* @param {SourceParameter2[]} parameters
* @param {SourceParameter[]} parameters
* @param {JavaType[]} throws
* @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), '');
this.annotations = annotations;
this.owner = owner;
this.methodType = method_type;
this.methodTypeIdent = method_type_ident;
this.sourceParameters = parameters;
this.throws = throws;
this.body_tokens = body;
this.body = body;
}
get hasImplementation() {
return !!this.body_tokens;
return !!this.body;
}
get parameterCount() {
@@ -142,7 +173,7 @@ class SourceMethod2 extends Method {
}
/**
* @returns {SourceParameter2[]}
* @returns {SourceParameter[]}
*/
get parameters() {
return this.sourceParameters;
@@ -152,26 +183,64 @@ class SourceMethod2 extends Method {
* @returns {JavaType}
*/
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 {JavaType} type
* @param {SourceTypeIdent} typeident
* @param {boolean} varargs
* @param {Token} name_token
*/
constructor(modifiers, type, varargs, name_token) {
super(name_token ? name_token.value : '', type, varargs);
constructor(modifiers, typeident, varargs, name_token) {
super(name_token ? name_token.value : '', typeident.type, varargs);
this.name_token = name_token;
this.modifiers = modifiers;
this.paramTypeIdent = typeident;
}
}
class SourceAnnotation {
/**
* @param {SourceTypeIdent} typeident
*/
constructor(typeident) {
this.annotationTypeIdent = typeident;
}
}
exports.SourceType = SourceType;
exports.SourceField2 = SourceField2;
exports.SourceMethod2 = SourceMethod2;
exports.SourceParameter2 = SourceParameter2;
exports.SourceConstructor2 = SourceConstructor2;
exports.SourceTypeIdent = SourceTypeIdent;
exports.SourceField = SourceField;
exports.SourceMethod = SourceMethod;
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 { resolveImports } = require('../java/import-resolver');
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 { TokenList } = require('./TokenList');
const { typeIdent } = require('./typeident');
@@ -10,57 +10,102 @@ const { typeIdent } = require('./typeident');
/**
* @param {ModuleBlock} mod
* @param {string} owner_typename
* @param {SourceType} outer_type
* @param {ModuleBlock|TypeDeclBlock} parent
* @param {SourceType[]} source_types
* @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 => {
const qualifiedTypeName = `${owner_typename}${type.simpleName}`;
// we add the names of type variables here, but we resolve any bounds later
//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);
const t = new SourceType(mod.packageName, outer_type, '', type.modifiers.map(m => m.value), type.kindToken, type.name_token, typemap);
t.typeVariables = type.typevars.map(tv => new TypeVariable(t, tv.name, [new TypeVariable.Bound(t, 'Ljava/lang/Object;', false)]));
source_types.push(t);
getSourceTypes(mod, `${qualifiedTypeName}$`, type, source_types, typemap);
getSourceTypes(mod, t, type, source_types, typemap);
});
}
/**
* @param {ResolvableType} rt
* @param {SourceType|SourceMethod|SourceConstructor} scope
* @param {ResolvedImport[]} resolved_imports
* @param {Map<string,JavaType>} typemap
* @param {TokenList} tokens
* @param {ModuleBlock|TypeDeclBlock} parent
* @param {ResolvedImport[]} imports
* @param {Map<string,JavaType>} typemap
*/
function resolveResolvableType(rt, scope, resolved_imports, typemap) {
const tokens = new TokenList(flattenBlocks(rt.typeTokens, false));
rt._resolved = typeIdent(tokens, scope, resolved_imports, typemap);
}
function populateTypes(tokens, parent, imports, typemap) {
/**
*
* @param {SourceType} source_type
* @param {ResolvedImport[]} resolved_imports
* @param {Map<string,JavaType>} typemap
*/
function resolveResolvableTypes(source_type, resolved_imports, typemap) {
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));
// methods and constructors can have parameterized types
source_type.methods.forEach(m => {
resolveResolvableType(m._returnType, m, resolved_imports, typemap);
m.parameters.forEach(p => resolveResolvableType(p._paramType, m, resolved_imports, typemap));
parent.types.forEach(type => {
const source_type = typemap.get(type.shortSignature);
if (source_type instanceof SourceType) {
if (type.extends_decl)
source_type.extends_types = resolveTypeList(source_type, type.extends_decl);
if (type.implements_decl)
source_type.implements_types = resolveTypeList(source_type, type.implements_decl);
// fields
source_type.fields = type.fields.map(f => {
const field_type = resolveTypeFromTokens(source_type, f);
return new SourceField(source_type, f.modifiers, field_type, f.name_token);
});
// 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 => {
c.parameters.forEach(p => resolveResolvableType(p._paramType, c, resolved_imports, typemap));
});
function resolveTypeFromTokens(scope, decl) {
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 {Map<string, JavaType>} androidLibrary
@@ -70,30 +115,25 @@ function validate(mod, androidLibrary) {
/** @type {SourceType[]} */
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);
source_types.forEach(t => {
resolveResolvableTypes(t, imports.resolved, imports.typemap);
});
populateTypes(new TokenList(flattenBlocks(mod.blocks, false)), mod, imports.resolved, imports.typemap);
let probs = [];
source_types.forEach(t => {
t.initers.forEach(i => {
console.log('<clinit>()');
const parsed = parseBody(i, imports.resolved, imports.typemap);
if (parsed)
probs = probs.concat(parsed.problems)
})
t.declaredConstructors.forEach(c => {
console.log(c.label);
t.constructors.forEach(c => {
const parsed = parseBody(c, imports.resolved, imports.typemap);
if (parsed)
probs = probs.concat(parsed.problems)
})
t.methods.forEach(m => {
console.log(m.label);
const parsed = parseBody(m, imports.resolved, imports.typemap);
if (parsed)
probs = probs.concat(parsed.problems)
@@ -107,7 +147,6 @@ function validate(mod, androidLibrary) {
require('./validation/parse-errors'),
require('./validation/modifier-errors'),
require('./validation/unresolved-imports'),
require('./validation/unresolved-types'),
require('./validation/invalid-types'),
require('./validation/bad-extends'),
require('./validation/bad-implements'),

View File

@@ -10,7 +10,7 @@ function checkExtends(source_type, probs) {
if (source_type.extends_types.length === 0) {
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];
if (source_type.typeKind === 'enum') {
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) {
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') {
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 {SourceType} = require('../source-type');
const {SourceType, SourceAnnotation} = require('../source-type');
const {CEIType, Method} = require('java-mti');
function nonAbstractLabel(label) {
@@ -19,10 +19,10 @@ function checkOverrides(source_type, probs) {
return;
}
/** @type {{ann:TextBlock, method:Method, method_id:string}[]} */
/** @type {{ann:SourceAnnotation, method:Method, method_id:string}[]} */
const overriden_methods = [];
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) {
arr.push({
ann,
@@ -52,7 +52,7 @@ function checkOverrides(source_type, probs) {
overriden_methods.forEach(x => {
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 {SourceType} = require('../source-type');
const {JavaType, ArrayType, CEIType, TypeArgument, UnresolvedType} = require('java-mti');
const { AnyType } = require('../body-types');
const {Token} = require('../tokenizer');
const {JavaType} = require('java-mti');
/**
* @param {JavaType} type
* @param {boolean} is_return_type
* @param {Token[]} typeTokens
* @param {ParseProblem[]} probs
*/
function checkType(type, is_return_type, typeTokens, probs) {
const typesig = type.typeSignature;
@@ -26,11 +29,11 @@ function checkType(type, is_return_type, typeTokens, probs) {
* @param {*} 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 => {
checkType(m.returnType, true, m._decl.typeTokens, probs);
checkType(m.returnType, true, m.methodTypeIdent.typeTokens, probs);
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)) {
// the source type has no declared constructors, but the superclass
// 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) {
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;
}