mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 01:48:18 +00:00
support token extraction in expressions
This commit is contained in:
@@ -16,6 +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 { ArrayIndexExpression } = require("./expressiontypes/ArrayIndexExpression");
|
||||
const { ArrayValueExpression } = require("./expressiontypes/ArrayValueExpression");
|
||||
@@ -30,6 +31,7 @@ const { MethodCallExpression } = require("./expressiontypes/MethodCallExpression
|
||||
const { NewArray, NewObject } = require("./expressiontypes/NewExpression");
|
||||
const { TernaryOpExpression } = require("./expressiontypes/TernaryOpExpression");
|
||||
const { ThisMemberExpression } = require("./expressiontypes/ThisMemberExpression");
|
||||
const { Variable } = require("./expressiontypes/Variable");
|
||||
|
||||
const { BooleanLiteral } = require('./expressiontypes/literals/Boolean');
|
||||
const { CharacterLiteral } = require('./expressiontypes/literals/Character');
|
||||
@@ -843,15 +845,15 @@ function enumValueList(type, tokens, imports, typemap) {
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
*/
|
||||
function statementBlock(tokens, mdecls, method, imports, typemap) {
|
||||
const b = new Block();
|
||||
const block = new Block(tokens.current);
|
||||
tokens.expectValue('{');
|
||||
mdecls.pushScope();
|
||||
while (!tokens.isValue('}')) {
|
||||
const s = statement(tokens, mdecls, method, imports, typemap);
|
||||
b.statements.push(s);
|
||||
block.statements.push(s);
|
||||
}
|
||||
mdecls.popScope();
|
||||
return b;
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1538,15 +1540,16 @@ function rootTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
// the result of a bracketed expression is always a value, never a variable
|
||||
// - this prevents things like: (a) = 5;
|
||||
return new ResolvedIdent(`(${matches.source})`, [new BracketedExpression(matches)]);
|
||||
case tokens.isValue('{') && 'symbol':
|
||||
case tokens.current.value === '{' && 'symbol':
|
||||
// array initer
|
||||
let elements = [];
|
||||
let elements = [], open = tokens.current;
|
||||
tokens.expectValue('{');
|
||||
if (!tokens.isValue('}')) {
|
||||
elements = expressionList(tokens, mdecls, scope, imports, typemap, { isArrayLiteral:true });
|
||||
tokens.expectValue('}');
|
||||
}
|
||||
const ident = `{${elements.map(e => e.source).join(',')}}`;
|
||||
return new ResolvedIdent(ident, [new ArrayValueExpression(elements)]);
|
||||
return new ResolvedIdent(ident, [new ArrayValueExpression(elements, open)]);
|
||||
default:
|
||||
addproblem(tokens, ParseProblem.Error(tokens.current, 'Expression expected'));
|
||||
return new ResolvedIdent('');
|
||||
@@ -1563,9 +1566,10 @@ function rootTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
*/
|
||||
function newTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
const new_token = tokens.current;
|
||||
tokens.expectValue('new');
|
||||
const { resolved: ctr_type } = typeIdent(tokens, scope, imports, typemap, {no_array_qualifiers:true, type_vars:[]});
|
||||
let match = new ResolvedIdent(`new ${ctr_type.simpleTypeName}`, [], [], [ctr_type]);
|
||||
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;
|
||||
switch(tokens.current.value) {
|
||||
case '[':
|
||||
@@ -1575,7 +1579,7 @@ function newTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
// array init
|
||||
rootTerm(tokens, mdecls, scope, imports, typemap);
|
||||
}
|
||||
return new ResolvedIdent(match.source, [new NewArray(ctr_type, match)]);
|
||||
return new ResolvedIdent(match.source, [new NewArray(new_token, ctr_type, match)]);
|
||||
case '(':
|
||||
tokens.inc();
|
||||
if (!tokens.isValue(')')) {
|
||||
@@ -1592,7 +1596,7 @@ function newTerm(tokens, mdecls, scope, imports, typemap) {
|
||||
addproblem(tokens, ParseProblem.Error(tokens.current, 'Constructor expression expected'));
|
||||
break;
|
||||
}
|
||||
return new ResolvedIdent(match.source, [new NewObject(ctr_type, ctr_args, type_body)]);
|
||||
return new ResolvedIdent(match.source, [new NewObject(new_token, ctr_type, ctr_args, type_body)]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1630,28 +1634,6 @@ function arrayElementOrConstructor(tokens, open_array, instance, index) {
|
||||
return new ResolvedIdent(ident, [new ArrayIndexExpression(instance, index)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CEIType} type
|
||||
*/
|
||||
function getTypeInheritanceList(type) {
|
||||
const types = {
|
||||
/** @type {JavaType[]} */
|
||||
list: [type],
|
||||
/** @type {Set<JavaType>} */
|
||||
done: new Set(),
|
||||
};
|
||||
for (let type; type = types.list.shift(); ) {
|
||||
if (types.done.has(type)) {
|
||||
continue;
|
||||
}
|
||||
types.done.add(type);
|
||||
if (type instanceof CEIType)
|
||||
types.list.push(...type.supers);
|
||||
}
|
||||
return Array.from(types.done);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {ResolvedIdent} matches
|
||||
* @param {TokenList} tokens
|
||||
@@ -1807,7 +1789,7 @@ function arrayTypeExpression(matches) {
|
||||
*/
|
||||
function resolveIdentifier(tokens, mdecls, scope, imports, typemap) {
|
||||
const ident = tokens.current.value;
|
||||
const matches = findIdentifier(ident, mdecls, scope, imports, typemap);
|
||||
const matches = findIdentifier(tokens.current, mdecls, scope, imports, typemap);
|
||||
checkIdentifierFound(tokens, ident, matches);
|
||||
return matches;
|
||||
}
|
||||
@@ -1827,20 +1809,22 @@ function checkIdentifierFound(tokens, ident, matches) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} ident
|
||||
* @param {Token} token
|
||||
* @param {MethodDeclarations} mdecls
|
||||
* @param {Scope} scope
|
||||
* @param {ResolvedImport[]} imports
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
*/
|
||||
function findIdentifier(ident, mdecls, scope, imports, typemap) {
|
||||
function findIdentifier(token, mdecls, scope, imports, typemap) {
|
||||
const ident = token.value;
|
||||
const matches = new ResolvedIdent(ident);
|
||||
matches.tokens = [token];
|
||||
|
||||
// is it a local or parameter - note that locals must be ordered innermost-scope-first
|
||||
const local = mdecls.locals.find(local => local.name === ident);
|
||||
let param = scope && !(scope instanceof SourceType) && scope.parameters.find(p => p.name === ident);
|
||||
if (local || param) {
|
||||
matches.variables = [local || param];
|
||||
matches.variables = [new Variable(token, local || param)];
|
||||
} else if (scope) {
|
||||
// is it a field, method or enum value in the current type (or any of the outer types or superclasses)
|
||||
const scoped_type = scope instanceof SourceType ? scope : scope.owner;
|
||||
@@ -1857,12 +1841,12 @@ function findIdentifier(ident, mdecls, scope, imports, typemap) {
|
||||
if (!matches.variables[0]) {
|
||||
const field = type.fields.find(f => f.name === ident);
|
||||
if (field) {
|
||||
matches.variables = [field];
|
||||
matches.variables = [new Variable(token, field)];
|
||||
return;
|
||||
}
|
||||
const enumValue = (type instanceof SourceType) && type.enumValues.find(e => e.ident.value === ident);
|
||||
if (enumValue) {
|
||||
matches.variables = [enumValue];
|
||||
matches.variables = [new Variable(token, enumValue)];
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1883,7 +1867,7 @@ function findIdentifier(ident, mdecls, scope, imports, typemap) {
|
||||
imp.members.forEach(member => {
|
||||
if (member.name === ident) {
|
||||
if (member instanceof Field) {
|
||||
matches.variables.push(member);
|
||||
matches.variables.push(new Variable(token, member));
|
||||
} else if (member instanceof Method) {
|
||||
matches.methods.push(member);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const { Token } = require('./tokenizer');
|
||||
class ResolvedIdent {
|
||||
/**
|
||||
* @param {string} ident
|
||||
* @param {(Local|Parameter|Field|Expression)[]} variables
|
||||
* @param {Expression[]} variables
|
||||
* @param {Method[]} methods
|
||||
* @param {JavaType[]} types
|
||||
* @param {string} package_name
|
||||
|
||||
175
langserver/java/expression-resolver.js
Normal file
175
langserver/java/expression-resolver.js
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* @typedef {import('./tokenizer').Token} Token
|
||||
*/
|
||||
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 { Expression } = require('./expressiontypes/Expression');
|
||||
const { Variable } = require('./expressiontypes/Variable');
|
||||
|
||||
/**
|
||||
* @param {import('./body-types').ResolvedIdent} e
|
||||
* @param {JavaType} assign_type
|
||||
* @param {Map<string,CEIType>} typemap
|
||||
* @param {ParseProblem[]} problems
|
||||
*/
|
||||
function checkAssignment(e, assign_type, typemap, problems) {
|
||||
const value = e.variables[0];
|
||||
if (value instanceof Variable) {
|
||||
checkTypeAssignable(assign_type, value.type, () => value.name_token, problems);
|
||||
return;
|
||||
}
|
||||
if (value instanceof Expression) {
|
||||
const expression_result_type = null;//value.resolveType(typemap);
|
||||
checkTypeAssignable(assign_type, expression_result_type, value.tokens, problems);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {JavaType} variable_type
|
||||
* @param {JavaType} value_type
|
||||
* @param {() => Token|Token[]} tokens
|
||||
*/
|
||||
function checkTypeAssignable(variable_type, value_type, tokens, problems) {
|
||||
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}'`));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* Note that void (V) is never type-assignable to anything
|
||||
*/
|
||||
const valid_primitive_types = {
|
||||
// conversions from a primitive to a value
|
||||
from: {
|
||||
B: /^[BSIJFD]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Float|Double);$/,
|
||||
S: /^[SIJFD]$|^Ljava\/lang\/(Short|Integer|Long|Float|Double);$/,
|
||||
I: /^[IJFD]$|^Ljava\/lang\/(Integer|Long|Float|Double);$/,
|
||||
J: /^[JFD]$|^Ljava\/lang\/(Long|Float|Double);$/,
|
||||
F: /^[FD]$|^Ljava\/lang\/(Float|Double);$/,
|
||||
D: /^D$|^Ljava\/lang\/(Double);$/,
|
||||
C: /^[CIJFD]$|^Ljava\/lang\/(Character|Integer|Long|Float|Double);$/,
|
||||
Z: /^Z$|^Ljava\/lang\/(Boolean);$/,
|
||||
V: /$^/, // V.test() always returns false
|
||||
},
|
||||
// conversions to a primitive from a value
|
||||
to: {
|
||||
B: /^[B]$|^Ljava\/lang\/(Byte);$/,
|
||||
S: /^[BS]$|^Ljava\/lang\/(Byte|Short);$/,
|
||||
I: /^[BSIC]$|^Ljava\/lang\/(Byte|Short|Integer|Character);$/,
|
||||
J: /^[BSIJC]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Character);$/,
|
||||
F: /^[BSIJCF]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Character|Float);$/,
|
||||
D: /^[BSIJCFD]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Character|Float|Double);$/,
|
||||
C: /^C$|^Ljava\/lang\/(Character);$/,
|
||||
Z: /^Z$|^Ljava\/lang\/(Boolean);$/,
|
||||
V: /$^/, // V.test() always returns false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a value of value_type is assignable to a variable of dest_type
|
||||
* @param {JavaType} dest_type
|
||||
* @param {JavaType} value_type
|
||||
*/
|
||||
function isTypeAssignable(dest_type, value_type) {
|
||||
let is_assignable = false;
|
||||
if (dest_type.typeSignature === value_type.typeSignature) {
|
||||
// exact signature match
|
||||
is_assignable = true;
|
||||
} else if (dest_type instanceof AnyType || value_type instanceof AnyType) {
|
||||
// everything is assignable to or from AnyType
|
||||
is_assignable = true;
|
||||
} else if (dest_type.rawTypeSignature === 'Ljava/lang/Object;') {
|
||||
// everything is assignable to Object
|
||||
is_assignable = true;
|
||||
} else if (value_type instanceof PrimitiveType) {
|
||||
// primitive values can only be assigned to wider primitives or their class equivilents
|
||||
is_assignable = valid_primitive_types.from[value_type.typeSignature].test(dest_type.typeSignature);
|
||||
} else if (dest_type instanceof PrimitiveType) {
|
||||
// primitive variables can only be assigned from narrower primitives or their class equivilents
|
||||
is_assignable = valid_primitive_types.to[dest_type.typeSignature].test(value_type.typeSignature);
|
||||
} else if (value_type instanceof NullType) {
|
||||
// null is assignable to any non-primitive
|
||||
is_assignable = !(dest_type instanceof PrimitiveType);
|
||||
} else if (value_type instanceof ArrayType) {
|
||||
// arrays are assignable to other arrays with the same dimensionality and type-assignable bases
|
||||
is_assignable = dest_type instanceof ArrayType
|
||||
&& dest_type.arrdims === value_type.arrdims
|
||||
&& isTypeAssignable(dest_type.base, value_type.base);
|
||||
} else if (value_type instanceof CEIType && dest_type instanceof CEIType) {
|
||||
// class/interfaces types are assignable to any class/interface types in their inheritence tree
|
||||
const valid_types = getTypeInheritanceList(value_type);
|
||||
is_assignable = valid_types.includes(dest_type);
|
||||
if (!is_assignable) {
|
||||
// generic types are also assignable to their raw counterparts
|
||||
const valid_raw_types = valid_types.map(t => t.getRawType());
|
||||
is_assignable = valid_raw_types.includes(dest_type);
|
||||
if (!is_assignable) {
|
||||
// generic types are also assignable to compatible wildcard type bounds
|
||||
const raw_type = valid_raw_types.find(rt => rt.rawTypeSignature === dest_type.rawTypeSignature);
|
||||
if (raw_type instanceof CEIType && raw_type.typeVariables.length === value_type.typeVariables.length) {
|
||||
is_assignable = dest_type.typeVariables.every((dest_tv, idx) => isTypeArgumentCompatible(dest_tv, value_type.typeVariables[idx].type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return is_assignable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TypeVariable} dest_typevar
|
||||
* @param {JavaType} value_typevar_type
|
||||
*/
|
||||
function isTypeArgumentCompatible(dest_typevar, value_typevar_type) {
|
||||
if (dest_typevar.type instanceof WildcardType) {
|
||||
if (!dest_typevar.type.bound) {
|
||||
// unbounded wildcard types are compatible with everything
|
||||
return true;
|
||||
}
|
||||
if (dest_typevar.type.bound.type === value_typevar_type) {
|
||||
return true;
|
||||
}
|
||||
switch (dest_typevar.type.bound.kind) {
|
||||
case 'extends':
|
||||
return isTypeAssignable(dest_typevar.type.bound.type, value_typevar_type);
|
||||
case 'super':;
|
||||
return isTypeAssignable(value_typevar_type, dest_typevar.type.bound.type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (value_typevar_type instanceof TypeVariableType) {
|
||||
// inferred type arguments of the form `x = List<>` are compatible with every destination type variable
|
||||
return value_typevar_type.typeVariable instanceof InferredTypeArgument;
|
||||
}
|
||||
return dest_typevar.type === value_typevar_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CEIType} type
|
||||
*/
|
||||
function getTypeInheritanceList(type) {
|
||||
const types = {
|
||||
/** @type {JavaType[]} */
|
||||
list: [type],
|
||||
/** @type {Set<JavaType>} */
|
||||
done: new Set(),
|
||||
};
|
||||
for (let type; type = types.list.shift(); ) {
|
||||
if (types.done.has(type)) {
|
||||
continue;
|
||||
}
|
||||
types.done.add(type);
|
||||
if (type instanceof CEIType)
|
||||
types.list.push(...type.supers);
|
||||
}
|
||||
return Array.from(types.done);
|
||||
}
|
||||
|
||||
exports.checkAssignment = checkAssignment;
|
||||
exports.getTypeInheritanceList = getTypeInheritanceList;
|
||||
@@ -13,6 +13,10 @@ class ArrayIndexExpression extends Expression {
|
||||
this.instance = instance;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.instance.tokens, ...this.index.tokens];
|
||||
}
|
||||
}
|
||||
|
||||
exports.ArrayIndexExpression = ArrayIndexExpression;
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
|
||||
class ArrayValueExpression extends Expression {
|
||||
/**
|
||||
* @param {ResolvedIdent[]} elements
|
||||
* @param {Token} open
|
||||
*/
|
||||
constructor(elements) {
|
||||
constructor(elements, open) {
|
||||
super();
|
||||
this.elements = elements;
|
||||
this.open = open;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.open;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ class BinaryOpExpression extends Expression {
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.lhs.tokens, this.op, ...this.rhs.tokens];
|
||||
}
|
||||
}
|
||||
|
||||
exports.BinaryOpExpression = BinaryOpExpression;
|
||||
|
||||
@@ -11,6 +11,10 @@ class BracketedExpression extends Expression {
|
||||
super();
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.expression.tokens;
|
||||
}
|
||||
}
|
||||
|
||||
exports.BracketedExpression = BracketedExpression;
|
||||
|
||||
@@ -13,6 +13,10 @@ class CastExpression extends Expression {
|
||||
this.castType = castType;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.castType.tokens, ...this.expression.tokens];
|
||||
}
|
||||
}
|
||||
|
||||
exports.CastExpression = CastExpression;
|
||||
|
||||
@@ -14,5 +14,9 @@ class ClassMemberExpression extends Expression {
|
||||
this.instance = instance;
|
||||
this.classToken = class_token;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.classToken;
|
||||
}
|
||||
}
|
||||
exports.ClassMemberExpression = ClassMemberExpression;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
/**
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
|
||||
class Expression {
|
||||
/** @returns {Token|Token[]} */
|
||||
tokens() {
|
||||
throw new Error('Expression.tokens');
|
||||
}
|
||||
}
|
||||
|
||||
exports.Expression = Expression;
|
||||
|
||||
@@ -16,6 +16,10 @@ class IncDecExpression extends Expression {
|
||||
this.operator = operator;
|
||||
this.which = which;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.operator;
|
||||
}
|
||||
}
|
||||
|
||||
exports.IncDecExpression = IncDecExpression;
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../statementtypes/Block').Block} Block
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
const { Block } = require('../statementtypes/Block');
|
||||
|
||||
class LambdaExpression extends Expression {
|
||||
/**
|
||||
*
|
||||
* @param {*[]} params
|
||||
* @param {Expression|Block} body
|
||||
* @param {ResolvedIdent|Block} body
|
||||
*/
|
||||
constructor(params, body) {
|
||||
super();
|
||||
this.params = params;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
if (this.body instanceof Block) {
|
||||
return this.body.open;
|
||||
}
|
||||
return this.body.tokens;
|
||||
}
|
||||
}
|
||||
exports.LambdaExpression = LambdaExpression;
|
||||
|
||||
@@ -15,6 +15,10 @@ class MemberExpression extends Expression {
|
||||
// member will be null for incomplete expressions
|
||||
this.member = member;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.member;
|
||||
}
|
||||
}
|
||||
|
||||
exports.MemberExpression = MemberExpression;
|
||||
|
||||
@@ -13,6 +13,10 @@ class MethodCallExpression extends Expression {
|
||||
this.instance = instance;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.instance.tokens;
|
||||
}
|
||||
}
|
||||
|
||||
exports.MethodCallExpression = MethodCallExpression;
|
||||
|
||||
@@ -1,34 +1,47 @@
|
||||
/**
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../source-types').SourceTypeIdent} SourceTypeIdent
|
||||
* @typedef {import('java-mti').JavaType} JavaType
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
|
||||
class NewArray extends Expression {
|
||||
/**
|
||||
* @param {JavaType} element_type
|
||||
* @param {Token} new_token
|
||||
* @param {SourceTypeIdent} element_type
|
||||
* @param {ResolvedIdent} dimensions
|
||||
*/
|
||||
constructor(element_type, dimensions) {
|
||||
constructor(new_token, element_type, dimensions) {
|
||||
super();
|
||||
this.new_token = new_token;
|
||||
this.element_type = element_type;
|
||||
this.dimensions = dimensions;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [this.new_token, ...this.element_type.tokens, ...this.dimensions.tokens];
|
||||
}
|
||||
}
|
||||
|
||||
class NewObject extends Expression {
|
||||
/**
|
||||
* @param {JavaType} object_type
|
||||
* @param {Token} new_token
|
||||
* @param {SourceTypeIdent} object_type
|
||||
* @param {ResolvedIdent[]} ctr_args
|
||||
* @param {Token[]} type_body
|
||||
*/
|
||||
constructor(object_type, ctr_args, type_body) {
|
||||
constructor(new_token, object_type, ctr_args, type_body) {
|
||||
super();
|
||||
this.element_type = object_type;
|
||||
this.new_token = new_token;
|
||||
this.object_type = object_type;
|
||||
this.ctr_args = ctr_args;
|
||||
this.type_body = type_body;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [this.new_token, ...this.object_type.tokens];
|
||||
}
|
||||
}
|
||||
|
||||
exports.NewArray = NewArray;
|
||||
|
||||
@@ -15,6 +15,10 @@ class TernaryOpExpression extends Expression {
|
||||
this.truthExpression = truthExpression;
|
||||
this.falseExpression = falseExpression;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return [...this.test.tokens, ...this.truthExpression.tokens, ...this.falseExpression.tokens];
|
||||
}
|
||||
}
|
||||
|
||||
exports.TernaryOpExpression = TernaryOpExpression;
|
||||
|
||||
@@ -14,6 +14,10 @@ class ThisMemberExpression extends Expression {
|
||||
this.instance = instance;
|
||||
this.thisToken = this_token;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.thisToken;
|
||||
}
|
||||
}
|
||||
|
||||
exports.ThisMemberExpression = ThisMemberExpression;
|
||||
|
||||
28
langserver/java/expressiontypes/Variable.js
Normal file
28
langserver/java/expressiontypes/Variable.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @typedef {import('../body-types').ResolvedIdent} ResolvedIdent
|
||||
* @typedef {import('../body-types').Local} Local
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
* @typedef {import('java-mti').Field} Field
|
||||
* @typedef {import('java-mti').Parameter} Parameter
|
||||
* @typedef {import('../source-types').SourceEnumValue} SourceEnumValue
|
||||
*/
|
||||
const { Expression } = require("./Expression");
|
||||
|
||||
class Variable extends Expression {
|
||||
/**
|
||||
* @param {Token} name_token
|
||||
* @param {Local|Parameter|Field|SourceEnumValue} variable
|
||||
*/
|
||||
constructor(name_token, variable) {
|
||||
super();
|
||||
this.name_token = name_token;
|
||||
this.variable = variable;
|
||||
this.type = this.variable.type;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.name_token;
|
||||
}
|
||||
}
|
||||
|
||||
exports.Variable = Variable;
|
||||
@@ -11,6 +11,10 @@ class LiteralValue extends Expression {
|
||||
super();
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
tokens() {
|
||||
return this.token;
|
||||
}
|
||||
}
|
||||
|
||||
exports.LiteralValue = LiteralValue;
|
||||
|
||||
@@ -498,3 +498,4 @@ exports.SourceAnnotation = SourceAnnotation;
|
||||
exports.SourceUnit = SourceUnit;
|
||||
exports.SourcePackage = SourcePackage;
|
||||
exports.SourceImport = SourceImport;
|
||||
exports.SourceEnumValue = SourceEnumValue;
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
/**
|
||||
* @typedef {import('../tokenizer').Token} Token
|
||||
*/
|
||||
const { Statement } = require("./Statement");
|
||||
|
||||
class Block extends Statement {
|
||||
/** @type {Statement[]} */
|
||||
statements = [];
|
||||
|
||||
/**
|
||||
* @param {Token} open
|
||||
*/
|
||||
constructor(open) {
|
||||
super();
|
||||
this.open = open;
|
||||
}
|
||||
}
|
||||
|
||||
exports.Block = Block;
|
||||
|
||||
Reference in New Issue
Block a user