simplify handling of this and class member qualifiers

This commit is contained in:
Dave Holoway
2020-06-29 14:14:49 +01:00
parent a278237486
commit 3e77b3f1c9
4 changed files with 28 additions and 81 deletions

View File

@@ -25,14 +25,12 @@ const { ArrayValueExpression } = require("./expressiontypes/ArrayValueExpression
const { BinaryOpExpression } = require("./expressiontypes/BinaryOpExpression"); const { BinaryOpExpression } = require("./expressiontypes/BinaryOpExpression");
const { BracketedExpression } = require("./expressiontypes/BracketedExpression"); const { BracketedExpression } = require("./expressiontypes/BracketedExpression");
const { CastExpression } = require("./expressiontypes/CastExpression"); const { CastExpression } = require("./expressiontypes/CastExpression");
const { ClassMemberExpression } = require("./expressiontypes/ClassMemberExpression");
const { IncDecExpression } = require("./expressiontypes/IncDecExpression"); const { IncDecExpression } = require("./expressiontypes/IncDecExpression");
const { LambdaExpression } = require("./expressiontypes/LambdaExpression"); const { LambdaExpression } = require("./expressiontypes/LambdaExpression");
const { MemberExpression } = require("./expressiontypes/MemberExpression"); const { MemberExpression } = require("./expressiontypes/MemberExpression");
const { MethodCallExpression } = require("./expressiontypes/MethodCallExpression"); const { MethodCallExpression } = require("./expressiontypes/MethodCallExpression");
const { NewArray, NewObject } = require("./expressiontypes/NewExpression"); const { NewArray, NewObject } = require("./expressiontypes/NewExpression");
const { TernaryOpExpression } = require("./expressiontypes/TernaryOpExpression"); const { TernaryOpExpression } = require("./expressiontypes/TernaryOpExpression");
const { ThisMemberExpression } = require("./expressiontypes/ThisMemberExpression");
const { UnaryOpExpression } = require("./expressiontypes/UnaryOpExpression"); const { UnaryOpExpression } = require("./expressiontypes/UnaryOpExpression");
const { Variable } = require("./expressiontypes/Variable"); const { Variable } = require("./expressiontypes/Variable");
@@ -1718,11 +1716,8 @@ function memberQualifier(matches, tokens, mdecls, scope, imports, typemap) {
let types = [], package_name = ''; let types = [], package_name = '';
switch (tokens.current.value) { switch (tokens.current.value) {
case 'class': case 'class':
expr = new ClassMemberExpression(matches, tokens.consume());
break;
case 'this': case 'this':
case 'super': expr = new MemberExpression(matches, dot, tokens.consume());
expr = new ThisMemberExpression(matches, tokens.consume());
break; break;
default: default:
let member = tokens.getIfKind('ident'); let member = tokens.getIfKind('ident');

View File

@@ -1,37 +0,0 @@
/**
* @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');
const ParseProblem = require('../parsetypes/parse-problem');
class ClassMemberExpression extends Expression {
/**
* @param {ResolvedIdent} instance
* @param {Token} class_token
*/
constructor(instance, class_token) {
super();
this.instance = instance;
this.classToken = class_token;
}
/**
* @param {ResolveInfo} ri
*/
resolveExpression(ri) {
const classType = ri.typemap.get('java/lang/Class');
const type = this.instance.types[0];
if (!type) {
ri.problems.push(ParseProblem.Error(this.instance.tokens, `Type expected`));
}
return classType.specialise([type || AnyType.Instance]);
}
tokens() {
return this.classToken;
}
}
exports.ClassMemberExpression = ClassMemberExpression;

View File

@@ -4,7 +4,7 @@
* @typedef {import('../tokenizer').Token} Token * @typedef {import('../tokenizer').Token} Token
*/ */
const { Expression } = require("./Expression"); const { Expression } = require("./Expression");
const { JavaType, CEIType } = require('java-mti'); const { JavaType, CEIType, PrimitiveType } = require('java-mti');
const { AnyType, MethodType, PackageNameType, TypeIdentType } = require('../anys'); const { AnyType, MethodType, PackageNameType, TypeIdentType } = require('../anys');
const { getTypeInheritanceList } = require('../expression-resolver'); const { getTypeInheritanceList } = require('../expression-resolver');
const { resolveNextPackage } = require('../type-resolver'); const { resolveNextPackage } = require('../type-resolver');
@@ -68,6 +68,32 @@ class MemberExpression extends Expression {
this.member.loc = this.dot.loc; this.member.loc = this.dot.loc;
const ident = this.member.value; const ident = this.member.value;
if (ident === 'this') {
// if this has a type qualifier (Type.this), return the type, otherwise it's
// and error and return AnyType
return ((loc_key === 'fqs') && (instance instanceof CEIType)) ? instance : AnyType.Instance;
}
if (ident === 'class') {
// if this has a type qualifier (Type.class), return the Class instance, otherwise it's
// and error and return AnyType
if (loc_key !== 'fqs') {
return AnyType.Instance;
}
let class_type = instance;
if (instance instanceof PrimitiveType) {
class_type = ri.typemap.get(`java/lang/${{
B:'Byte',S:'Short',I:'Integer',J:'Long',F:'Float',D:'Double',C:'Character',Z:'Boolean',V:'Void'
}[instance.typeSignature]}`)
}
const clz = ri.typemap.get('java/lang/Class').specialise([class_type]);
if (!ri.typemap.has(clz.shortSignature)) {
ri.typemap.set(clz.shortSignature, clz);
}
return clz;
}
const field = instance.fields.find(f => f.name === ident); const field = instance.fields.find(f => f.name === ident);
if (field) { if (field) {
return field.type; return field.type;

View File

@@ -1,37 +0,0 @@
/**
* @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 {
/**
* @param {ResolvedIdent} instance
* @param {Token} this_token
*/
constructor(instance, this_token) {
super();
this.instance = instance;
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;
}
}
exports.ThisMemberExpression = ThisMemberExpression;