add new array validation

This commit is contained in:
Dave Holoway
2020-06-18 14:54:12 +01:00
parent d869afe2fa
commit f05b34171c
4 changed files with 70 additions and 8 deletions

View File

@@ -130,7 +130,7 @@ class MultiValueType {
* @typedef {JavaType|MethodType|LambdaType|ArrayValueType|TypeIdentType|MultiValueType} ResolvedType * @typedef {JavaType|MethodType|LambdaType|ArrayValueType|TypeIdentType|MultiValueType} ResolvedType
**/ **/
exports.AnyMethod = AnyMethod; exports.AnyMethod = AnyMethod;
exports.AnyType = AnyType; exports.AnyType = AnyType;
exports.AnyValue = AnyValue; exports.AnyValue = AnyValue;
exports.ArrayValueType = ArrayValueType; exports.ArrayValueType = ArrayValueType;

View File

@@ -6,7 +6,7 @@
*/ */
const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, TypeVariable, Field, Method } = require('java-mti'); const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, TypeVariable, Field, Method } = require('java-mti');
const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation, const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation,
SourceUnit, SourcePackage, SourceImport } = require('./source-types'); SourceUnit, SourcePackage, SourceImport, SourceArrayType, FixedLengthArrayType } = require('./source-types');
const ResolvedImport = require('./parsetypes/resolved-import'); const ResolvedImport = require('./parsetypes/resolved-import');
const ParseProblem = require('./parsetypes/parse-problem'); const ParseProblem = require('./parsetypes/parse-problem');
const { tokenize, Token } = require('./tokenizer'); const { tokenize, Token } = require('./tokenizer');
@@ -1641,7 +1641,8 @@ function expressionList(tokens, mdecls, scope, imports, typemap, opts) {
*/ */
function arrayElementOrConstructor(tokens, open_array, instance, index) { function arrayElementOrConstructor(tokens, open_array, instance, index) {
const ident = `${instance.source}[${index.source}]`; const ident = `${instance.source}[${index.source}]`;
return new ResolvedIdent(ident, [new ArrayIndexExpression(instance, index)]); const types = instance.types.map(t => new FixedLengthArrayType(t, index));
return new ResolvedIdent(ident, [new ArrayIndexExpression(instance, index)], [], types, '', index.tokens.slice());
} }
/** /**
@@ -1765,7 +1766,7 @@ function methodCallQualifier(matches, tokens, mdecls, scope, imports, typemap) {
* @param {ResolvedIdent} matches * @param {ResolvedIdent} matches
*/ */
function arrayTypeExpression(matches) { function arrayTypeExpression(matches) {
const types = matches.types.map(t => new ArrayType(t, 1)); const types = matches.types.map(t => new SourceArrayType(t));
return new ResolvedIdent(`${matches.source}[]`, [], [], types); return new ResolvedIdent(`${matches.source}[]`, [], [], types);
} }

View File

@@ -6,7 +6,9 @@
* @typedef {import('java-mti').JavaType} JavaType * @typedef {import('java-mti').JavaType} JavaType
*/ */
const { Expression } = require("./Expression"); const { Expression } = require("./Expression");
const { ArrayType } = require('java-mti'); const { ArrayType, PrimitiveType } = require('java-mti');
const { FixedLengthArrayType, SourceArrayType } = require('../source-types');
const ParseProblem = require('../parsetypes/parse-problem');
class NewArray extends Expression { class NewArray extends Expression {
/** /**
@@ -19,18 +21,45 @@ class NewArray extends Expression {
this.new_token = new_token; this.new_token = new_token;
this.element_type = element_type; this.element_type = element_type;
this.dimensions = dimensions; this.dimensions = dimensions;
this.array_type = new ArrayType(element_type.resolved, 1);
} }
/** /**
* @param {ResolveInfo} ri * @param {ResolveInfo} ri
*/ */
resolveExpression(ri) { resolveExpression(ri) {
return this.array_type; /** @type {ResolvedIdent[]} */
const fixed_dimensions = [];
const type = this.dimensions.types[0];
for (let x = type; ;) {
if (x instanceof FixedLengthArrayType) {
fixed_dimensions.unshift(x.length);
x = x.parent_type;
continue;
}
if (x instanceof SourceArrayType) {
x = x.parent_type;
continue;
}
break;
}
const arrdims = type instanceof ArrayType ? type.arrdims : 1;
const array_type = new ArrayType(this.element_type.resolved, arrdims);
fixed_dimensions.forEach(d => {
const idx = d.resolveExpression(ri);
if (idx instanceof PrimitiveType) {
if (!/^[BSI]$/.test(idx.typeSignature)) {
ri.problems.push(ParseProblem.Error(d.tokens, `Expression of type '${idx.label}' is not valid as an array dimension`));
}
return;
}
ri.problems.push(ParseProblem.Error(d.tokens, `Integer value expected`));
})
return array_type;
} }
tokens() { tokens() {
return [this.new_token, ...this.element_type.tokens, ...this.dimensions.tokens]; return [this.new_token, ...this.dimensions.tokens];
} }
} }

View File

@@ -487,6 +487,36 @@ class SourceUnit {
types = []; types = [];
} }
class SourceArrayType extends ArrayType {
/**
*
* @param {JavaType} element_type
*/
constructor(element_type) {
super(element_type, 1);
this.parent_type = element_type;
}
get label() {
return `${this.parent_type.label}[]`;
}
}
class FixedLengthArrayType extends SourceArrayType {
/**
*
* @param {JavaType} element_type
* @param {ResolvedIdent} length
*/
constructor(element_type, length) {
super(element_type);
this.length = length;
}
get label() {
return `${this.parent_type.label}[${this.length.source}]`;
}
}
exports.SourceType = SourceType; exports.SourceType = SourceType;
exports.SourceTypeIdent = SourceTypeIdent; exports.SourceTypeIdent = SourceTypeIdent;
exports.SourceField = SourceField; exports.SourceField = SourceField;
@@ -499,3 +529,5 @@ exports.SourceUnit = SourceUnit;
exports.SourcePackage = SourcePackage; exports.SourcePackage = SourcePackage;
exports.SourceImport = SourceImport; exports.SourceImport = SourceImport;
exports.SourceEnumValue = SourceEnumValue; exports.SourceEnumValue = SourceEnumValue;
exports.SourceArrayType = SourceArrayType;
exports.FixedLengthArrayType = FixedLengthArrayType;