mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 01:48:18 +00:00
refactor new term qualifiers
This commit is contained in:
@@ -10,7 +10,7 @@ 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 } = require('./typeident');
|
const { genericTypeArgs, typeIdent } = require('./typeident');
|
||||||
const { TokenList } = require("./TokenList");
|
const { TokenList } = require("./TokenList");
|
||||||
const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, LiteralNumber, LiteralValue, Local, MethodCall, ResolvedIdent, TernaryValue, Value } = require("./body-types");
|
const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, LiteralNumber, LiteralValue, Local, MethodCall, ResolvedIdent, TernaryValue, Value } = require("./body-types");
|
||||||
|
|
||||||
@@ -1680,43 +1680,7 @@ function rootTerm(tokens, locals, method, imports, typemap) {
|
|||||||
tokens.inc();
|
tokens.inc();
|
||||||
return qualifiedTerm(tokens, locals, method, imports, typemap);
|
return qualifiedTerm(tokens, locals, method, imports, typemap);
|
||||||
case 'new-operator':
|
case 'new-operator':
|
||||||
tokens.inc();
|
return newTerm(tokens, locals, method, imports, typemap);
|
||||||
const ctr = qualifiedTerm(tokens, locals, method, imports, typemap);
|
|
||||||
let new_ident = `new ${ctr.source}`;
|
|
||||||
if (ctr.types[0] instanceof ArrayType) {
|
|
||||||
if (tokens.current.value === '{') {
|
|
||||||
// array init
|
|
||||||
rootTerm(tokens, locals, method, imports, typemap);
|
|
||||||
}
|
|
||||||
return new ResolvedIdent(new_ident, [new Value(new_ident, ctr.types[0])]);
|
|
||||||
}
|
|
||||||
if (ctr.variables[0] instanceof ConstructorCall) {
|
|
||||||
const ctr_type = ctr.variables[0].type;
|
|
||||||
if (tokens.current.value === '{') {
|
|
||||||
// final types cannot be inherited
|
|
||||||
if (ctr_type.modifiers.includes('final') ) {
|
|
||||||
addproblem(tokens, ParseProblem.Error(tokens.current, `Type '${ctr_type.fullyDottedTypeName}' is declared final and cannot be inherited from.`));
|
|
||||||
}
|
|
||||||
// anonymous type - just skip for now
|
|
||||||
for (let balance = 0;;) {
|
|
||||||
if (tokens.isValue('{')) {
|
|
||||||
balance++;
|
|
||||||
} else if (tokens.isValue('}')) {
|
|
||||||
if (--balance === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else tokens.inc();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// abstract and interface types must have a type body
|
|
||||||
if (ctr_type.typeKind === 'interface' || ctr_type.modifiers.includes('abstract') ) {
|
|
||||||
addproblem(tokens, ParseProblem.Error(tokens.current, `Type '${ctr_type.fullyDottedTypeName}' is abstract and cannot be instantiated without a body`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ResolvedIdent(new_ident, [new Value(new_ident, ctr.variables[0].type)]);
|
|
||||||
}
|
|
||||||
addproblem(tokens, ParseProblem.Error(tokens.current, 'Constructor expression expected'));
|
|
||||||
return new ResolvedIdent(new_ident);
|
|
||||||
case 'open-bracket':
|
case 'open-bracket':
|
||||||
tokens.inc();
|
tokens.inc();
|
||||||
matches = expression(tokens, locals, method, imports, typemap);
|
matches = expression(tokens, locals, method, imports, typemap);
|
||||||
@@ -1759,6 +1723,57 @@ function rootTerm(tokens, locals, method, imports, typemap) {
|
|||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {TokenList} tokens
|
||||||
|
* @param {Local[]} locals
|
||||||
|
* @param {SourceMC} method
|
||||||
|
* @param {ResolvedImport[]} imports
|
||||||
|
* @param {Map<string,JavaType>} typemap
|
||||||
|
*/
|
||||||
|
function newTerm(tokens, locals, method, imports, typemap) {
|
||||||
|
tokens.expectValue('new');
|
||||||
|
const ctr_type = typeIdent(tokens, method, imports, typemap, false);
|
||||||
|
let match = new ResolvedIdent(`new ${ctr_type.simpleTypeName}`, [], [], [ctr_type]);
|
||||||
|
switch(tokens.current.value) {
|
||||||
|
case '[':
|
||||||
|
match = arrayQualifiers(match, tokens, locals, method, imports, typemap);
|
||||||
|
// @ts-ignore
|
||||||
|
if (tokens.current.value === '{') {
|
||||||
|
// array init
|
||||||
|
rootTerm(tokens, locals, method, imports, typemap);
|
||||||
|
}
|
||||||
|
return new ResolvedIdent(match.source, [new Value(match.source, match.types[0])]);
|
||||||
|
case '(':
|
||||||
|
match = methodCallQualifier(match, tokens, locals, method, imports, typemap);
|
||||||
|
// @ts-ignore
|
||||||
|
if (tokens.current.value === '{') {
|
||||||
|
// final types cannot be inherited
|
||||||
|
if (ctr_type.modifiers.includes('final') ) {
|
||||||
|
addproblem(tokens, ParseProblem.Error(tokens.current, `Type '${ctr_type.fullyDottedTypeName}' is declared final and cannot be inherited from.`));
|
||||||
|
}
|
||||||
|
// anonymous type - just skip for now
|
||||||
|
for (let balance = 0;;) {
|
||||||
|
if (tokens.isValue('{')) {
|
||||||
|
balance++;
|
||||||
|
} else if (tokens.isValue('}')) {
|
||||||
|
if (--balance === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else tokens.inc();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// abstract and interface types must have a type body
|
||||||
|
if (ctr_type.typeKind === 'interface' || ctr_type.modifiers.includes('abstract') ) {
|
||||||
|
addproblem(tokens, ParseProblem.Error(tokens.current, `Type '${ctr_type.fullyDottedTypeName}' is abstract and cannot be instantiated without a body`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
addproblem(tokens, ParseProblem.Error(tokens.current, 'Constructor expression expected'));
|
||||||
|
return new ResolvedIdent(match.source, [new Value(match.source, ctr_type)]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TokenList} tokens
|
* @param {TokenList} tokens
|
||||||
* @param {Local[]} locals
|
* @param {Local[]} locals
|
||||||
@@ -1955,33 +1970,14 @@ function qualifiers(matches, tokens, locals, method, imports, typemap) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
switch (tokens.current.value) {
|
switch (tokens.current.value) {
|
||||||
case '.':
|
case '.':
|
||||||
tokens.inc();
|
matches = dottedIdent(matches, tokens, typemap);
|
||||||
matches = parseDottedIdent(matches, tokens, typemap);
|
|
||||||
break;
|
break;
|
||||||
case '[':
|
case '[':
|
||||||
let open_array = tokens.current;
|
matches = arrayQualifiers(matches, tokens, locals, method, imports, typemap);
|
||||||
if (tokens.inc().value === ']') {
|
|
||||||
// array type
|
|
||||||
tokens.inc();
|
|
||||||
matches = arrayTypeExpression(matches);
|
|
||||||
} else {
|
|
||||||
// array index
|
|
||||||
const index = arrayIndexOrDimension(tokens, locals, method, imports, typemap);
|
|
||||||
matches = arrayElementOrConstructor(tokens, open_array, matches, index);
|
|
||||||
// @ts-ignore
|
|
||||||
tokens.expectValue(']');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '(':
|
case '(':
|
||||||
// method or constructor call
|
// method or constructor call
|
||||||
let args = [];
|
matches = methodCallQualifier(matches, tokens, locals, method, imports, typemap);
|
||||||
if (tokens.inc().value === ')') {
|
|
||||||
tokens.inc();
|
|
||||||
} else {
|
|
||||||
args = expressionList(tokens, locals, method, imports, typemap);
|
|
||||||
tokens.expectValue(')');
|
|
||||||
}
|
|
||||||
matches = methodCallExpression(tokens, matches, args, typemap);
|
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
// generic type arguments - since this can be confused with less-than, only parse
|
// generic type arguments - since this can be confused with less-than, only parse
|
||||||
@@ -1998,6 +1994,49 @@ function qualifiers(matches, tokens, locals, method, imports, typemap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ResolvedIdent} matches
|
||||||
|
* @param {TokenList} tokens
|
||||||
|
* @param {Local[]} locals
|
||||||
|
* @param {SourceMC} method
|
||||||
|
* @param {ResolvedImport[]} imports
|
||||||
|
* @param {Map<string,JavaType>} typemap
|
||||||
|
*/
|
||||||
|
function arrayQualifiers(matches, tokens, locals, method, imports, typemap) {
|
||||||
|
while (tokens.isValue('[')) {
|
||||||
|
let open_array = tokens.current;
|
||||||
|
if (tokens.isValue(']')) {
|
||||||
|
// array type
|
||||||
|
matches = arrayTypeExpression(matches);
|
||||||
|
} else {
|
||||||
|
// array index
|
||||||
|
const index = arrayIndexOrDimension(tokens, locals, method, imports, typemap);
|
||||||
|
matches = arrayElementOrConstructor(tokens, open_array, matches, index);
|
||||||
|
// @ts-ignore
|
||||||
|
tokens.expectValue(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ResolvedIdent} matches
|
||||||
|
* @param {TokenList} tokens
|
||||||
|
* @param {Local[]} locals
|
||||||
|
* @param {SourceMC} method
|
||||||
|
* @param {ResolvedImport[]} imports
|
||||||
|
* @param {Map<string,JavaType>} typemap
|
||||||
|
*/
|
||||||
|
function methodCallQualifier(matches, tokens, locals, method, imports, typemap) {
|
||||||
|
let args = [];
|
||||||
|
tokens.expectValue('(');
|
||||||
|
if (!tokens.isValue(')')) {
|
||||||
|
args = expressionList(tokens, locals, method, imports, typemap);
|
||||||
|
tokens.expectValue(')');
|
||||||
|
}
|
||||||
|
return methodCallExpression(tokens, matches, args, typemap);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ResolvedIdent} matches
|
* @param {ResolvedIdent} matches
|
||||||
*/
|
*/
|
||||||
@@ -2012,7 +2051,8 @@ function arrayTypeExpression(matches) {
|
|||||||
* @param {TokenList} tokens
|
* @param {TokenList} tokens
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
*/
|
*/
|
||||||
function parseDottedIdent(matches, tokens, typemap) {
|
function dottedIdent(matches, tokens, typemap) {
|
||||||
|
tokens.expectValue('.');
|
||||||
let variables = [],
|
let variables = [],
|
||||||
methods = [],
|
methods = [],
|
||||||
types = [],
|
types = [],
|
||||||
|
|||||||
@@ -32,8 +32,9 @@ function typeIdentList(tokens, scope, imports, typemap) {
|
|||||||
* @param {CEIType|MethodBase} scope
|
* @param {CEIType|MethodBase} scope
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
|
* @param {boolean} allow_array_qualifiers
|
||||||
*/
|
*/
|
||||||
function typeIdent(tokens, scope, imports, typemap) {
|
function typeIdent(tokens, scope, imports, typemap, allow_array_qualifiers = true) {
|
||||||
/** @type {JavaType[]} */
|
/** @type {JavaType[]} */
|
||||||
let types = [], package_name = '';
|
let types = [], package_name = '';
|
||||||
switch(tokens.current.kind) {
|
switch(tokens.current.kind) {
|
||||||
@@ -58,7 +59,7 @@ function typeIdent(tokens, scope, imports, typemap) {
|
|||||||
tokens.inc();
|
tokens.inc();
|
||||||
} else if (tokens.isValue('<')) {
|
} else if (tokens.isValue('<')) {
|
||||||
genericTypeArgs(tokens, types, scope, imports, typemap);
|
genericTypeArgs(tokens, types, scope, imports, typemap);
|
||||||
} else if (tokens.isValue('[')) {
|
} else if (allow_array_qualifiers && tokens.isValue('[')) {
|
||||||
let arrdims = 0;
|
let arrdims = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
arrdims++;
|
arrdims++;
|
||||||
|
|||||||
Reference in New Issue
Block a user