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); super(section, simplified);
const sm = section.sourcemap(); const sm = section.sourcemap();
this.paramBlock = section.blocks[sm.map[match[0].indexOf('R')]]; this.paramBlock = section.blocks[sm.map[match[0].indexOf('R')]];
this.typevarsBlock = section.blocks[sm.map[match[0].indexOf('T')]];
this.parsed = { this.parsed = {
typevars: null,
parameters: null, parameters: null,
/** @type {TextBlock[]} */ /** @type {TextBlock[]} */
errors: null, errors: [],
} }
} }
@@ -384,30 +386,7 @@ class MCBlock extends DeclarationBlock {
* @return {ParameterBlock[]} * @return {ParameterBlock[]}
*/ */
get parameters() { get parameters() {
if (!this.parsed.parameters) { this._ensureParsed();
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];
}
return this.parsed.parameters; return this.parsed.parameters;
} }
@@ -433,9 +412,43 @@ class MCBlock extends DeclarationBlock {
} }
get parseErrors() { get parseErrors() {
this.parameters; this._ensureParsed();
return this.parsed.errors; 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 { class MethodBlock extends MCBlock {
@@ -631,29 +644,9 @@ class TypeDeclBlock extends DeclarationBlock {
if (this.parsed.fields) { if (this.parsed.fields) {
return; return;
} }
this.parsed.typevars = []; this.parsed.typevars = this.typevars_token
if (this.typevars_token) { ? parseTypeVariables(this.typevars_token.blockArray())
// 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;
}, []);
}
const body = this.body().blockArray(); const body = this.body().blockArray();
parseArrayTypes(body); parseArrayTypes(body);
parseTypeArgs(body); parseTypeArgs(body);
@@ -834,6 +827,33 @@ function parseArrayTypes(sourceblocks) {
group(sourceblocks, 'array-type', /\[ *\](( *\[ *\])*)/g, markers.arrayQualifier); 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) { function parseTypeArgs(sourceblocks) {
// sort out type parameters + type arguments // sort out type parameters + type arguments
// re = /< *[PWD?]( *T)?( *A)?( *, *[PWD]( *T)?( *A)?)* *>/g; // re = /< *[PWD?]( *T)?( *A)?( *, *[PWD]( *T)?( *A)?)* *>/g;

View File

@@ -209,6 +209,12 @@ class SourceMethod extends Method {
this._decl = decl; this._decl = decl;
this._parameters = decl.parameters.map((p,i) => new SourceParameter(p)); this._parameters = decl.parameters.map((p,i) => new SourceParameter(p));
this._returnType = new ResolvableType(decl); 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() { get returnType() {
return this._returnType.resolved; return this._returnType.resolved;
} }
get typeVariables() {
return this._typevars;
}
} }
class SourceParameter extends Parameter { class SourceParameter extends Parameter {