add type variables to SourceMethod

This commit is contained in:
Dave Holoway
2020-06-09 12:51:43 +01:00
parent 252b476147
commit 74a21ecbf8
2 changed files with 79 additions and 49 deletions

View File

@@ -373,10 +373,12 @@ class MCBlock extends DeclarationBlock {
super(section, simplified);
const sm = section.sourcemap();
this.paramBlock = section.blocks[sm.map[match[0].indexOf('R')]];
this.typevarsBlock = section.blocks[sm.map[match[0].indexOf('T')]];
this.parsed = {
typevars: null,
parameters: null,
/** @type {TextBlock[]} */
errors: null,
errors: [],
}
}
@@ -384,30 +386,7 @@ class MCBlock extends DeclarationBlock {
* @return {ParameterBlock[]}
*/
get parameters() {
if (!this.parsed.parameters) {
const param_block = this.paramBlock.blockArray();
parseArrayTypes(param_block);
parseAnnotations(param_block);
parseTypeArgs(param_block);
const vars = group(param_block, 'var-decl', VarDeclBlock.parseRE, markers.varDecl, false, VarDeclBlock);
this.parsed.parameters = group(param_block, 'param', ParameterBlock.parseRE, markers.parameter, false, ParameterBlock);
// parameters must be a comma-separated list
const sm = param_block.sourcemap();
if (sm.simplified.search(/^\((\s*F(\s*,\s*F)*)?\s*\)/) === 0) {
return this.parsed.parameters;
}
let invalid = sm.simplified.match(/^(\(\s*)(F?)(?:\s*,\s*F)*\s*/);
if (!invalid) {
// should never happen, but ignore
return this.parsed.parameters;
}
const token_idx = invalid[2]
? sm.map[invalid[0].length] // there's a problem with a subsequent declaration
: sm.map[invalid[1].length] // there's a problem with the first declaration
const token = param_block.blocks[token_idx];
if (!token) return this.parsed.parameters;
this.parsed.errors = [token];
}
this._ensureParsed();
return this.parsed.parameters;
}
@@ -433,9 +412,43 @@ class MCBlock extends DeclarationBlock {
}
get parseErrors() {
this.parameters;
this._ensureParsed();
return this.parsed.errors;
}
get typeVariables() {
this._ensureParsed();
return this.parsed.typevars;
}
_ensureParsed() {
if (this.parsed.parameters) {
return;
}
const param_block = this.paramBlock.blockArray();
parseArrayTypes(param_block);
parseAnnotations(param_block);
parseTypeArgs(param_block);
const vars = group(param_block, 'var-decl', VarDeclBlock.parseRE, markers.varDecl, false, VarDeclBlock);
this.parsed.parameters = group(param_block, 'param', ParameterBlock.parseRE, markers.parameter, false, ParameterBlock);
// parameters must be a comma-separated list
const sm = param_block.sourcemap();
if (sm.simplified.search(/^\((\s*F(\s*,\s*F)*)?\s*\)/) !== 0) {
let invalid = sm.simplified.match(/^(\(\s*)(F?)(?:\s*,\s*F)*\s*/);
if (invalid) {
const token_idx = invalid[2]
? sm.map[invalid[0].length] // there's a problem with a subsequent declaration
: sm.map[invalid[1].length] // there's a problem with the first declaration
const token = param_block.blocks[token_idx];
if (token) {
this.parsed.errors.push(token);
}
}
}
// parse type arguments
this.parsed.typevars = this.typevarsBlock ? parseTypeVariables(this.typevarsBlock.blockArray()) : [];
}
}
class MethodBlock extends MCBlock {
@@ -631,29 +644,9 @@ class TypeDeclBlock extends DeclarationBlock {
if (this.parsed.fields) {
return;
}
this.parsed.typevars = [];
if (this.typevars_token) {
// split the token into a list of typevars
// - each type var must be a simple ident (W), a bounded var (I)
// or anonymous (?)
this.parsed.typevars = this.typevars_token.blockArray()
.blocks.reduce((arr,b) => {
if (/^[WI?]/.test(b.simplified)) {
arr.push({
decl: b,
get name_token() {
return this.decl instanceof BoundedTypeVar
? this.decl.range.blocks[0]
: this.decl
},
get name() {
return this.name_token.source;
},
})
}
return arr;
}, []);
}
this.parsed.typevars = this.typevars_token
? parseTypeVariables(this.typevars_token.blockArray())
: [];
const body = this.body().blockArray();
parseArrayTypes(body);
parseTypeArgs(body);
@@ -834,6 +827,33 @@ function parseArrayTypes(sourceblocks) {
group(sourceblocks, 'array-type', /\[ *\](( *\[ *\])*)/g, markers.arrayQualifier);
}
/**
* @param {TextBlockArray} sourceblocks
* @returns {{decl: TextBlock|BoundedTypeVar, name_token: TextBlockArray, name: string}[]}
*/
function parseTypeVariables(sourceblocks) {
// split the token into a list of typevars
// - each type var must be a simple ident (W), a bounded var (I)
// or a wildcard (?)
return sourceblocks.blocks.reduce((arr,b) => {
if (/^[WI?]/.test(b.simplified)) {
arr.push({
decl: b,
get name_token() {
return this.decl instanceof BoundedTypeVar
? this.decl.range.blocks[0]
: this.decl
},
get name() {
return this.name_token.source;
},
})
}
return arr;
}, []);
}
function parseTypeArgs(sourceblocks) {
// sort out type parameters + type arguments
// re = /< *[PWD?]( *T)?( *A)?( *, *[PWD]( *T)?( *A)?)* *>/g;

View File

@@ -209,6 +209,12 @@ class SourceMethod extends Method {
this._decl = decl;
this._parameters = decl.parameters.map((p,i) => new SourceParameter(p));
this._returnType = new ResolvableType(decl);
this._typevars = decl.typeVariables.map(tv => {
const typevar = new TypeVariable(owner, tv.name);
// automatically add the Object bound
typevar.bounds.push(new TypeVariable.Bound(owner, 'Ljava/lang/Object;', false));
return typevar;
});
}
/**
@@ -221,6 +227,10 @@ class SourceMethod extends Method {
get returnType() {
return this._returnType.resolved;
}
get typeVariables() {
return this._typevars;
}
}
class SourceParameter extends Parameter {