mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-22 17:39:19 +00:00
implement resolveExpression
This commit is contained in:
@@ -2,9 +2,9 @@ const { JavaType, Method } = require('java-mti');
|
||||
const { Expression } = require('./expressiontypes/Expression');
|
||||
|
||||
/**
|
||||
* AnyType is a special type that's used to fill in types that are missing.
|
||||
* To prevent cascading errors, AnyType should be fully assign/cast/type-compatible
|
||||
* with any other type
|
||||
* Custom type designed to be used where a type is missing or unresolved.
|
||||
*
|
||||
* AnyType should be fully assign/cast/type-compatible with any other type
|
||||
*/
|
||||
class AnyType extends JavaType {
|
||||
/**
|
||||
@@ -27,6 +27,10 @@ class AnyType extends JavaType {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom method designed to be compatible with
|
||||
* any arguments in method call
|
||||
*/
|
||||
class AnyMethod extends Method {
|
||||
/**
|
||||
* @param {string} name
|
||||
@@ -40,6 +44,10 @@ class AnyMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom expression designed to be compatiable with
|
||||
* any variable or operator
|
||||
*/
|
||||
class AnyValue extends Expression {
|
||||
/**
|
||||
*
|
||||
@@ -52,6 +60,81 @@ class AnyValue extends Expression {
|
||||
}
|
||||
}
|
||||
|
||||
exports.AnyMethod = AnyMethod;
|
||||
/**
|
||||
* Custom type used to represent a method identifier
|
||||
*
|
||||
* e.g `"".length`
|
||||
*/
|
||||
class MethodType {
|
||||
/**
|
||||
* @param {Method[]} methods
|
||||
*/
|
||||
constructor(methods) {
|
||||
this.methods = methods;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom type used to represent a lambda expression
|
||||
*
|
||||
* eg. `() => null`
|
||||
*/
|
||||
class LambdaType {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom type used to represent type name expressions
|
||||
*
|
||||
* eg. `x instanceof String`
|
||||
*/
|
||||
class TypeIdentType {
|
||||
/**
|
||||
* @param {JavaType} type
|
||||
*/
|
||||
constructor(type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom type used to represent an array literal
|
||||
*
|
||||
* eg. `new int[] { 1,2,3 }`
|
||||
*/
|
||||
class ArrayValueType {
|
||||
/**
|
||||
* @param {(ResolvedType)[]} element_types
|
||||
*/
|
||||
constructor(element_types) {
|
||||
this.element_types = element_types;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom type used to represent the types of a
|
||||
* expression that can return multiple distinct types
|
||||
*
|
||||
* eg. `x == null ? 0 : 'c'`
|
||||
*/
|
||||
class MultiValueType {
|
||||
/**
|
||||
* @param {ResolvedType[]} types
|
||||
*/
|
||||
constructor(...types) {
|
||||
this.types = types;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {JavaType|MethodType|LambdaType|ArrayValueType|TypeIdentType|MultiValueType} ResolvedType
|
||||
**/
|
||||
|
||||
exports.AnyMethod = AnyMethod;
|
||||
exports.AnyType = AnyType;
|
||||
exports.AnyValue = AnyValue;
|
||||
exports.ArrayValueType = ArrayValueType;
|
||||
exports.LambdaType = LambdaType;
|
||||
exports.MethodType = MethodType;
|
||||
exports.MultiValueType = MultiValueType;
|
||||
exports.TypeIdentType = TypeIdentType;
|
||||
|
||||
@@ -16,7 +16,7 @@ const { TokenList } = require("./TokenList");
|
||||
const { AnyMethod, AnyType, AnyValue } = require("./anys");
|
||||
const { Label, Local, MethodDeclarations, ResolvedIdent } = require("./body-types");
|
||||
const { resolveImports, resolveSingleImport } = require('../java/import-resolver');
|
||||
const { getTypeInheritanceList } = require('./expression-resolver');
|
||||
const { checkAssignment, getTypeInheritanceList } = require('./expression-resolver');
|
||||
|
||||
const { ArrayIndexExpression } = require("./expressiontypes/ArrayIndexExpression");
|
||||
const { ArrayValueExpression } = require("./expressiontypes/ArrayValueExpression");
|
||||
@@ -212,9 +212,15 @@ function parse(source, typemap) {
|
||||
time('parse');
|
||||
parseUnit(tokens, unit, typemap);
|
||||
timeEnd('parse');
|
||||
|
||||
// once all the types have been parsed, resolve any field initialisers
|
||||
unit.types.forEach(t => {
|
||||
t.fields.filter(f => f.init).forEach(f => checkAssignment(f.init, f.type, typemap, tokens.problems));
|
||||
});
|
||||
|
||||
} catch(err) {
|
||||
timers.forEach(timeEnd);
|
||||
if (tokens) {
|
||||
if (tokens && tokens.current) {
|
||||
addproblem(tokens, ParseProblem.Error(tokens.current, `Parse failed: ${err.message}`));
|
||||
} else {
|
||||
console.log(`Parse failed: ${err.message}`);
|
||||
@@ -1566,26 +1572,29 @@ function rootTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
*/
|
||||
function newTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
tokens.mark();
|
||||
const new_token = tokens.current;
|
||||
tokens.expectValue('new');
|
||||
const ctr_type = typeIdent(tokens, scope, imports, typemap, {no_array_qualifiers:true, type_vars:[]});
|
||||
let match = new ResolvedIdent(`new ${ctr_type.resolved.simpleTypeName}`, [], [], [ctr_type.resolved]);
|
||||
let ctr_args = [], type_body = null;
|
||||
let ctr_args = [], type_body = null, newtokens;
|
||||
switch(tokens.current.value) {
|
||||
case '[':
|
||||
match = arrayQualifiers(match, tokens, mdecls, scope, imports, typemap);
|
||||
newtokens = tokens.markEnd();
|
||||
// @ts-ignore
|
||||
if (tokens.current.value === '{') {
|
||||
// array init
|
||||
rootTerm(tokens, mdecls, scope, imports, typemap);
|
||||
}
|
||||
return new ResolvedIdent(match.source, [new NewArray(new_token, ctr_type, match)]);
|
||||
return new ResolvedIdent(match.source, [new NewArray(new_token, ctr_type, match)], [], [], '', newtokens);
|
||||
case '(':
|
||||
tokens.inc();
|
||||
if (!tokens.isValue(')')) {
|
||||
ctr_args = expressionList(tokens, mdecls, scope, imports, typemap);
|
||||
tokens.expectValue(')');
|
||||
}
|
||||
newtokens = tokens.markEnd();
|
||||
// @ts-ignore
|
||||
if (tokens.current.value === '{') {
|
||||
// anonymous type - just skip for now
|
||||
@@ -1593,10 +1602,11 @@ function newTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
newtokens = tokens.markEnd();
|
||||
addproblem(tokens, ParseProblem.Error(tokens.current, 'Constructor expression expected'));
|
||||
break;
|
||||
}
|
||||
return new ResolvedIdent(match.source, [new NewObject(new_token, ctr_type, ctr_args, type_body)]);
|
||||
return new ResolvedIdent(match.source, [new NewObject(new_token, ctr_type, ctr_args, type_body)], [], [], '', newtokens);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1679,6 +1689,7 @@ function qualifiers(matches, tokens, mdecls, scope, imports, typemap) {
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
*/
|
||||
function memberQualifier(matches, tokens, mdecls, scope, imports, typemap) {
|
||||
tokens.mark();
|
||||
tokens.expectValue('.');
|
||||
let expr, label = `${matches.source}.${tokens.current.value}`;
|
||||
let types = [], package_name = '';
|
||||
@@ -1704,7 +1715,7 @@ function memberQualifier(matches, tokens, mdecls, scope, imports, typemap) {
|
||||
break;
|
||||
}
|
||||
tokens.inc();
|
||||
return new ResolvedIdent(label, [expr], [], types, package_name);
|
||||
return new ResolvedIdent(label, [expr], [], types, package_name, tokens.markEnd());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* @typedef {import('./expressiontypes/Expression').Expression} Expression
|
||||
* @typedef {import('./anys').ResolvedType} ResolvedType
|
||||
*/
|
||||
const { JavaType, ArrayType, Method, Parameter, Field } = require('java-mti');
|
||||
const { JavaType, CEIType, ArrayType, Method } = require('java-mti');
|
||||
const { Token } = require('./tokenizer');
|
||||
const { AnyType, MethodType, TypeIdentType } = require('./anys');
|
||||
|
||||
|
||||
class ResolvedIdent {
|
||||
/**
|
||||
@@ -11,16 +14,35 @@ class ResolvedIdent {
|
||||
* @param {Method[]} methods
|
||||
* @param {JavaType[]} types
|
||||
* @param {string} package_name
|
||||
* @param {Token[]} tokens
|
||||
*/
|
||||
constructor(ident, variables = [], methods = [], types = [], package_name = '') {
|
||||
constructor(ident, variables = [], methods = [], types = [], package_name = '', tokens = []) {
|
||||
this.source = ident;
|
||||
this.variables = variables;
|
||||
this.methods = methods;
|
||||
this.types = types;
|
||||
this.package_name = package_name;
|
||||
/** @type {Token[]} */
|
||||
this.tokens = [];
|
||||
this.tokens = tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
* @returns {ResolvedType}
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
if (this.variables[0]) {
|
||||
return this.variables[0].resolveExpression(ri);
|
||||
}
|
||||
if (this.methods) {
|
||||
return new MethodType(this.methods);
|
||||
}
|
||||
if (this.types[0]) {
|
||||
return new TypeIdentType(this.types[0]);
|
||||
}
|
||||
return AnyType.Instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Local {
|
||||
@@ -79,7 +101,19 @@ class MethodDeclarations {
|
||||
}
|
||||
}
|
||||
|
||||
class ResolveInfo {
|
||||
/**
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
* @param {*[]} problems
|
||||
*/
|
||||
constructor(typemap, problems) {
|
||||
this.typemap = typemap;
|
||||
this.problems = problems;
|
||||
}
|
||||
}
|
||||
|
||||
exports.Label = Label;
|
||||
exports.Local = Local;
|
||||
exports.MethodDeclarations = MethodDeclarations;
|
||||
exports.ResolvedIdent = ResolvedIdent;
|
||||
exports.ResolveInfo = ResolveInfo;
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
*/
|
||||
const ParseProblem = require('./parsetypes/parse-problem');
|
||||
const { TypeVariable, JavaType, PrimitiveType, NullType, ArrayType, CEIType, WildcardType, TypeVariableType, InferredTypeArgument } = require('java-mti');
|
||||
const { AnyType } = require('./anys');
|
||||
const { Local } = require('./body-types');
|
||||
const { AnyType, MultiValueType } = require('./anys');
|
||||
const { ResolveInfo } = require('./body-types');
|
||||
const { LiteralValue } = require('./expressiontypes/literals/LiteralValue');
|
||||
const { NumberLiteral } = require('./expressiontypes/literals/Number');
|
||||
const { Expression } = require('./expressiontypes/Expression');
|
||||
const { Variable } = require('./expressiontypes/Variable');
|
||||
|
||||
@@ -20,9 +22,19 @@ function checkAssignment(e, assign_type, typemap, problems) {
|
||||
checkTypeAssignable(assign_type, value.type, () => value.name_token, problems);
|
||||
return;
|
||||
}
|
||||
if (value instanceof NumberLiteral) {
|
||||
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}'`));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value instanceof LiteralValue) {
|
||||
checkTypeAssignable(assign_type, value.type, () => value.token, problems);
|
||||
return;
|
||||
}
|
||||
if (value instanceof Expression) {
|
||||
const expression_result_type = null;//value.resolveType(typemap);
|
||||
checkTypeAssignable(assign_type, expression_result_type, value.tokens, problems);
|
||||
const expression_result_type = value.resolveExpression(new ResolveInfo(typemap, problems));
|
||||
checkTypeAssignable(assign_type, expression_result_type, () => value.tokens(), problems);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -30,13 +42,21 @@ function checkAssignment(e, assign_type, typemap, problems) {
|
||||
/**
|
||||
*
|
||||
* @param {JavaType} variable_type
|
||||
* @param {JavaType} value_type
|
||||
* @param {import('./anys').ResolvedType} value_type
|
||||
* @param {() => Token|Token[]} tokens
|
||||
*/
|
||||
function checkTypeAssignable(variable_type, value_type, tokens, problems) {
|
||||
if (value_type instanceof MultiValueType) {
|
||||
value_type.types.forEach(t => checkTypeAssignable(variable_type, t, tokens, problems));
|
||||
return;
|
||||
}
|
||||
if (!(value_type instanceof JavaType)) {
|
||||
return;
|
||||
}
|
||||
if (!isTypeAssignable(variable_type, value_type)) {
|
||||
const t = tokens();
|
||||
problems.push(ParseProblem.Error(t, `Incompatible types: Expression of type '${value_type.fullyDottedTypeName}' cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
||||
if (t.length || (t && !Array.isArray(t)))
|
||||
problems.push(ParseProblem.Error(t, `Incompatible types: Expression of type '${value_type.fullyDottedTypeName}' cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { ArrayType } = require('java-mti');
|
||||
const { AnyType } = require('../anys');
|
||||
|
||||
class ArrayIndexExpression extends Expression {
|
||||
/**
|
||||
@@ -17,6 +20,17 @@ class ArrayIndexExpression extends Expression {
|
||||
tokens() {
|
||||
return [...this.instance.tokens, ...this.index.tokens];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const instance_type = this.instance.resolveExpression(ri);
|
||||
if (instance_type instanceof ArrayType) {
|
||||
return instance_type.elementType;
|
||||
}
|
||||
return AnyType.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
exports.ArrayIndexExpression = ArrayIndexExpression;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { ArrayValueType } = require('../anys');
|
||||
|
||||
class ArrayValueExpression extends Expression {
|
||||
/**
|
||||
@@ -18,6 +20,13 @@ class ArrayValueExpression extends Expression {
|
||||
tokens() {
|
||||
return this.open;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
return new ArrayValueType(this.elements.map(e => e.resolveExpression(ri)));
|
||||
}
|
||||
}
|
||||
|
||||
exports.ArrayValueExpression = ArrayValueExpression;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { JavaType, PrimitiveType } = require('java-mti');
|
||||
|
||||
class BinaryOpExpression extends Expression {
|
||||
/**
|
||||
@@ -17,6 +19,52 @@ class BinaryOpExpression extends Expression {
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const operator = this.op.value;
|
||||
const lhstype = this.lhs.resolveExpression(ri);
|
||||
const rhstype = this.rhs.resolveExpression(ri);
|
||||
if (operator === '+') {
|
||||
const lhstypesig = lhstype instanceof JavaType && lhstype.typeSignature,
|
||||
rhstypesig = rhstype instanceof JavaType && rhstype.typeSignature;
|
||||
if (lhstypesig === 'Ljava/lang/String;') {
|
||||
return lhstype;
|
||||
}
|
||||
if (lhstypesig === 'D' || rhstypesig === 'D') {
|
||||
return PrimitiveType.map.D;
|
||||
}
|
||||
if (lhstypesig === 'F' || rhstypesig === 'F') {
|
||||
return PrimitiveType.map.F;
|
||||
}
|
||||
if (lhstypesig === 'J' || rhstypesig === 'J') {
|
||||
return PrimitiveType.map.J;
|
||||
}
|
||||
return PrimitiveType.map.I;
|
||||
}
|
||||
if (/^([*/%&|^+-]?=|<<=|>>>?=)$/.test(operator)) {
|
||||
// result of assignments are lhs
|
||||
return lhstype;
|
||||
}
|
||||
if (/^[*/%-]$/.test(operator)) {
|
||||
// math operators
|
||||
return PrimitiveType.map.I;
|
||||
}
|
||||
if (/^(<<|>>>?)$/.test(operator)) {
|
||||
// shift operators
|
||||
return PrimitiveType.map.I;
|
||||
}
|
||||
if (/^[&|^]$/.test(operator)) {
|
||||
// bitwise or logical operators
|
||||
return lhstype === PrimitiveType.map.Z ? lhstype : PrimitiveType.map.I;
|
||||
}
|
||||
if (operator === 'instanceof') {
|
||||
}
|
||||
// logical/comparison operators
|
||||
return PrimitiveType.map.Z;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.lhs.tokens, this.op, ...this.rhs.tokens];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
|
||||
@@ -12,6 +13,13 @@ class BracketedExpression extends Expression {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
return this.expression.resolveExpression(ri);
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.expression.tokens;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { AnyType, TypeIdentType } = require('../anys');
|
||||
|
||||
class CastExpression extends Expression {
|
||||
/**
|
||||
@@ -14,6 +16,17 @@ class CastExpression extends Expression {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const cast_type = this.castType.resolveExpression(ri);
|
||||
if (cast_type instanceof TypeIdentType) {
|
||||
return cast_type.type;
|
||||
}
|
||||
return AnyType.Instance;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.castType.tokens, ...this.expression.tokens];
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { AnyType } = require('../anys');
|
||||
|
||||
class ClassMemberExpression extends Expression {
|
||||
/**
|
||||
@@ -15,6 +17,15 @@ class ClassMemberExpression extends Expression {
|
||||
this.classToken = class_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const classType = ri.typemap.get('java/lang/Class');
|
||||
const type = this.instance.types[0];
|
||||
return classType.specialise([type || AnyType.Instance]);
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.classToken;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
/**
|
||||
* @typedef {import('java-mti').JavaType} JavaType
|
||||
* @typedef {import('java-mti').CEIType} CEIType
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../anys').ResolvedType} ResolvedType
|
||||
*/
|
||||
|
||||
class Expression {
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
* @returns {ResolvedType}
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
throw new Error('Expression.resolveType');
|
||||
}
|
||||
|
||||
/** @returns {Token|Token[]} */
|
||||
tokens() {
|
||||
throw new Error('Expression.tokens');
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { PrimitiveType } = require('java-mti');
|
||||
const { AnyType } = require('../anys');
|
||||
|
||||
class IncDecExpression extends Expression {
|
||||
/**
|
||||
@@ -17,6 +20,19 @@ class IncDecExpression extends Expression {
|
||||
this.which = which;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const type = this.expr.resolveExpression(ri);
|
||||
if (type instanceof PrimitiveType) {
|
||||
if (/^[BSIJFD]$/.test(type.typeSignature)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return AnyType.Instance;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.operator;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { Block } = require('../statementtypes/Block');
|
||||
const { LambdaType } = require('../anys');
|
||||
|
||||
class LambdaExpression extends Expression {
|
||||
/**
|
||||
@@ -16,6 +18,13 @@ class LambdaExpression extends Expression {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveType(ri) {
|
||||
return new LambdaType();
|
||||
}
|
||||
|
||||
tokens() {
|
||||
if (this.body instanceof Block) {
|
||||
return this.body.open;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { CEIType } = require('java-mti');
|
||||
const { AnyType, MethodType } = require('../anys');
|
||||
const { getTypeInheritanceList } = require('../expression-resolver');
|
||||
|
||||
class MemberExpression extends Expression {
|
||||
/**
|
||||
@@ -16,6 +20,34 @@ class MemberExpression extends Expression {
|
||||
this.member = member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const type = this.instance.resolveExpression(ri);
|
||||
if (!(type instanceof CEIType)) {
|
||||
return AnyType.Instance;
|
||||
}
|
||||
const ident = this.member.value;
|
||||
const field = type.fields.find(f => f.name === ident);
|
||||
if (field) {
|
||||
return field.type;
|
||||
}
|
||||
let methods = new Map();
|
||||
getTypeInheritanceList(type).forEach(type => {
|
||||
type.methods.forEach(m => {
|
||||
let msig;
|
||||
if (m.name === ident && !methods.has(msig = m.methodSignature)) {
|
||||
methods.set(msig, m);
|
||||
}
|
||||
})
|
||||
});
|
||||
if (methods.size > 0) {
|
||||
return new MethodType([...methods.values()]);
|
||||
}
|
||||
return AnyType.Instance;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { AnyType, MethodType } = require('../anys');
|
||||
|
||||
class MethodCallExpression extends Expression {
|
||||
/**
|
||||
@@ -14,6 +16,18 @@ class MethodCallExpression extends Expression {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const type = this.instance.resolveExpression(ri);
|
||||
if (!(type instanceof MethodType)) {
|
||||
return AnyType.Instance;
|
||||
}
|
||||
const arg_types = this.args.map(arg => arg.resolveExpression(ri));
|
||||
return type.methods[0].returnType;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.instance.tokens;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/**
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../source-types').SourceTypeIdent} SourceTypeIdent
|
||||
* @typedef {import('java-mti').JavaType} JavaType
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { ArrayType } = require('java-mti');
|
||||
|
||||
class NewArray extends Expression {
|
||||
/**
|
||||
@@ -17,6 +19,14 @@ class NewArray extends Expression {
|
||||
this.new_token = new_token;
|
||||
this.element_type = element_type;
|
||||
this.dimensions = dimensions;
|
||||
this.array_type = new ArrayType(element_type.resolved, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
return this.array_type;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
@@ -39,6 +49,13 @@ class NewObject extends Expression {
|
||||
this.type_body = type_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
return this.object_type.resolved;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [this.new_token, ...this.object_type.tokens];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
*/
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { MultiValueType } = require('../anys');
|
||||
|
||||
class TernaryOpExpression extends Expression {
|
||||
/**
|
||||
@@ -16,6 +18,15 @@ class TernaryOpExpression extends Expression {
|
||||
this.falseExpression = falseExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
const ttype = this.truthExpression.resolveExpression(ri);
|
||||
const ftype = this.falseExpression.resolveExpression(ri);
|
||||
return new MultiValueType(ttype, ftype);
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.test.tokens, ...this.truthExpression.tokens, ...this.falseExpression.tokens];
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { AnyType, TypeIdentType } = require('../anys');
|
||||
|
||||
class ThisMemberExpression extends Expression {
|
||||
/**
|
||||
@@ -15,6 +17,18 @@ class ThisMemberExpression extends Expression {
|
||||
this.thisToken = this_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
// instance should be a type identifier
|
||||
const typeident = this.instance.resolveExpression(ri);
|
||||
if (typeident instanceof TypeIdentType) {
|
||||
return typeident.type;
|
||||
}
|
||||
return AnyType.Instance;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.thisToken;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').Local} Local
|
||||
* @typedef {import('../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
* @typedef {import('java-mti').Field} Field
|
||||
* @typedef {import('java-mti').Parameter} Parameter
|
||||
@@ -20,6 +21,13 @@ class Variable extends Expression {
|
||||
this.type = this.variable.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveType(ri) {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.name_token;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ class BooleanLiteral extends LiteralValue {
|
||||
* @param {Token} token
|
||||
*/
|
||||
constructor(token) {
|
||||
super(token);
|
||||
this.type = PrimitiveType.map.Z;
|
||||
super(token, PrimitiveType.map.Z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ class CharacterLiteral extends LiteralValue {
|
||||
* @param {Token} token
|
||||
*/
|
||||
constructor(token) {
|
||||
super(token);
|
||||
this.type = PrimitiveType.map.C;
|
||||
super(token, PrimitiveType.map.C);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* @typedef {import('../../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../../tokenizer').Token} Token
|
||||
* @typedef {import('java-mti').CEIType} CEIType
|
||||
*/
|
||||
@@ -11,9 +12,19 @@ class InstanceLiteral extends LiteralValue {
|
||||
* @param {CEIType} scoped_type
|
||||
*/
|
||||
constructor(token, scoped_type) {
|
||||
super(token);
|
||||
super(token, null);
|
||||
this.scoped_type = scoped_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
if (this.token.value === 'this') {
|
||||
return this.scoped_type;
|
||||
}
|
||||
return this.scoped_type.supers.find(t => t.typeKind === 'class') || ri.typemap.get('java/lang/Object');
|
||||
}
|
||||
}
|
||||
|
||||
exports.InstanceLiteral = InstanceLiteral;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/**
|
||||
* @typedef {import('java-mti').JavaType} JavaType
|
||||
* @typedef {import('../../body-types').ResolveInfo} ResolveInfo
|
||||
* @typedef {import('../../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require('../Expression');
|
||||
@@ -6,10 +8,19 @@ const { Expression } = require('../Expression');
|
||||
class LiteralValue extends Expression {
|
||||
/**
|
||||
* @param {Token} token
|
||||
* @param {JavaType} known_type
|
||||
*/
|
||||
constructor(token) {
|
||||
constructor(token, known_type) {
|
||||
super();
|
||||
this.token = token;
|
||||
this.type = known_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResolveInfo} ri
|
||||
*/
|
||||
resolveExpression(ri) {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
|
||||
@@ -10,8 +10,7 @@ class NullLiteral extends LiteralValue {
|
||||
* @param {Token} token
|
||||
*/
|
||||
constructor(token) {
|
||||
super(token);
|
||||
this.type = new NullType();
|
||||
super(token, new NullType());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,8 @@ class NumberLiteral extends LiteralValue {
|
||||
* @param {PrimitiveType} default_type
|
||||
*/
|
||||
constructor(value, kind, default_type) {
|
||||
super(value);
|
||||
super(value, default_type);
|
||||
this.numberKind = kind;
|
||||
this.type = default_type;
|
||||
}
|
||||
|
||||
static shift(a, b, op) {
|
||||
|
||||
@@ -11,8 +11,7 @@ class StringLiteral extends LiteralValue {
|
||||
* @param {CEIType} string_type
|
||||
*/
|
||||
constructor(token, string_type) {
|
||||
super(token);
|
||||
this.type = string_type;
|
||||
super(token, string_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user