mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 09:59:25 +00:00
validate array literals
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
const { JavaType, Method } = require('java-mti');
|
const { JavaType, Method } = require('java-mti');
|
||||||
const { Expression } = require('./expressiontypes/Expression');
|
const { Expression } = require('./expressiontypes/Expression');
|
||||||
|
/**
|
||||||
|
* @typedef {import('./tokenizer').Token} Token
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom type designed to be used where a type is missing or unresolved.
|
* Custom type designed to be used where a type is missing or unresolved.
|
||||||
@@ -104,10 +107,10 @@ class TypeIdentType {
|
|||||||
*/
|
*/
|
||||||
class ArrayValueType {
|
class ArrayValueType {
|
||||||
/**
|
/**
|
||||||
* @param {(ResolvedType)[]} element_types
|
* @param {{tokens:Token[], value: ResolvedType}[]} elements
|
||||||
*/
|
*/
|
||||||
constructor(element_types) {
|
constructor(elements) {
|
||||||
this.element_types = element_types;
|
this.elements = elements;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* @typedef {import('./tokenizer').Token} Token
|
* @typedef {import('./tokenizer').Token} Token
|
||||||
|
* @typedef {import('./anys').ResolvedType} ResolvedType
|
||||||
*/
|
*/
|
||||||
const ParseProblem = require('./parsetypes/parse-problem');
|
const ParseProblem = require('./parsetypes/parse-problem');
|
||||||
const { TypeVariable, JavaType, PrimitiveType, NullType, ArrayType, CEIType, WildcardType, TypeVariableType, InferredTypeArgument } = require('java-mti');
|
const { TypeVariable, JavaType, PrimitiveType, NullType, ArrayType, CEIType, WildcardType, TypeVariableType, InferredTypeArgument } = require('java-mti');
|
||||||
const { AnyType, MultiValueType } = require('./anys');
|
const { AnyType, ArrayValueType, MultiValueType } = require('./anys');
|
||||||
const { ResolveInfo } = require('./body-types');
|
const { ResolveInfo } = require('./body-types');
|
||||||
const { LiteralValue } = require('./expressiontypes/literals/LiteralValue');
|
const { LiteralValue } = require('./expressiontypes/literals/LiteralValue');
|
||||||
const { NumberLiteral } = require('./expressiontypes/literals/Number');
|
const { NumberLiteral } = require('./expressiontypes/literals/Number');
|
||||||
@@ -24,7 +25,7 @@ function checkAssignment(e, assign_type, typemap, problems) {
|
|||||||
}
|
}
|
||||||
if (value instanceof NumberLiteral) {
|
if (value instanceof NumberLiteral) {
|
||||||
if (!value.isCompatibleWith(assign_type)) {
|
if (!value.isCompatibleWith(assign_type)) {
|
||||||
problems.push(ParseProblem.Error(value.token, `Incompatible types: Expression of type '${value.type.fullyDottedTypeName}' cannot be assigned to a variable of type '${assign_type.fullyDottedTypeName}'`));
|
incompatibleTypesError(assign_type, value.type, () => value.token, problems);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -44,21 +45,79 @@ function checkAssignment(e, assign_type, typemap, problems) {
|
|||||||
* @param {JavaType} variable_type
|
* @param {JavaType} variable_type
|
||||||
* @param {import('./anys').ResolvedType} value_type
|
* @param {import('./anys').ResolvedType} value_type
|
||||||
* @param {() => Token|Token[]} tokens
|
* @param {() => Token|Token[]} tokens
|
||||||
|
* @param {ParseProblem[]} problems
|
||||||
*/
|
*/
|
||||||
function checkTypeAssignable(variable_type, value_type, tokens, problems) {
|
function checkTypeAssignable(variable_type, value_type, tokens, problems) {
|
||||||
if (value_type instanceof MultiValueType) {
|
if (value_type instanceof MultiValueType) {
|
||||||
value_type.types.forEach(t => checkTypeAssignable(variable_type, t, tokens, problems));
|
value_type.types.forEach(t => checkTypeAssignable(variable_type, t, tokens, problems));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (value_type instanceof ArrayValueType) {
|
||||||
|
checkArrayLiteral(variable_type, value_type, tokens, problems);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (value_type instanceof JavaType) {
|
if (value_type instanceof JavaType) {
|
||||||
if (!isTypeAssignable(variable_type, value_type)) {
|
if (!isTypeAssignable(variable_type, value_type)) {
|
||||||
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Expression of type '${value_type.fullyDottedTypeName}' cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
incompatibleTypesError(variable_type, value_type, tokens, problems);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
problems.push(ParseProblem.Error(tokens(), `Field, variable or method call expected`));
|
problems.push(ParseProblem.Error(tokens(), `Field, variable or method call expected`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {JavaType} variable_type
|
||||||
|
* @param {JavaType} value_type
|
||||||
|
* @param {() => Token|Token[]} tokens
|
||||||
|
* @param {ParseProblem[]} problems
|
||||||
|
*/
|
||||||
|
function incompatibleTypesError(variable_type, value_type, tokens, problems) {
|
||||||
|
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Expression of type '${value_type.fullyDottedTypeName}' cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {JavaType} variable_type
|
||||||
|
* @param {ArrayValueType} value_type
|
||||||
|
* @param {() => Token|Token[]} tokens
|
||||||
|
* @param {ParseProblem[]} problems
|
||||||
|
*/
|
||||||
|
function checkArrayLiteral(variable_type, value_type, tokens, problems) {
|
||||||
|
if (!(variable_type instanceof ArrayType)) {
|
||||||
|
problems.push(ParseProblem.Error(tokens(), `Array expression cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value_type.elements.length === 0) {
|
||||||
|
// empty arrays are compatible with all array types
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const element_type = variable_type.elementType;
|
||||||
|
value_type.elements.forEach(element => {
|
||||||
|
checkArrayElement(element_type, element.value, element.tokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {JavaType} element_type
|
||||||
|
* @param {ResolvedType} value_type
|
||||||
|
* @param {Token[]} tokens
|
||||||
|
*/
|
||||||
|
function checkArrayElement(element_type, value_type, tokens) {
|
||||||
|
if (value_type instanceof JavaType) {
|
||||||
|
if (!isTypeAssignable(element_type, value_type)) {
|
||||||
|
incompatibleTypesError(element_type, value_type, () => tokens, problems);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value_type instanceof ArrayValueType) {
|
||||||
|
checkArrayLiteral(element_type, value_type, () => tokens, problems);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
problems.push(ParseProblem.Error(tokens, `Expression expected`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of regexes to map source primitives to their destination types.
|
* Set of regexes to map source primitives to their destination types.
|
||||||
* eg, long (J) is type-assignable to long, float and double (and their boxed counterparts)
|
* eg, long (J) is type-assignable to long, float and double (and their boxed counterparts)
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ class ArrayValueExpression extends Expression {
|
|||||||
* @param {ResolveInfo} ri
|
* @param {ResolveInfo} ri
|
||||||
*/
|
*/
|
||||||
resolveExpression(ri) {
|
resolveExpression(ri) {
|
||||||
return new ArrayValueType(this.elements.map(e => e.resolveExpression(ri)));
|
return new ArrayValueType(this.elements.map(e => ({
|
||||||
|
tokens: e.tokens,
|
||||||
|
value: e.resolveExpression(ri),
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user