implement resolveExpression

This commit is contained in:
Dave Holoway
2020-06-18 11:46:42 +01:00
parent 13cdd1e0bc
commit 2da127edc0
26 changed files with 435 additions and 33 deletions

View File

@@ -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;

View File

@@ -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());
}
/**

View File

@@ -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;

View File

@@ -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}'`));
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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');

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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];
}

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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() {

View File

@@ -10,8 +10,7 @@ class NullLiteral extends LiteralValue {
* @param {Token} token
*/
constructor(token) {
super(token);
this.type = new NullType();
super(token, new NullType());
}
}

View File

@@ -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) {

View File

@@ -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);
}
}