mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 09:59:25 +00:00
add checks for unary operators
This commit is contained in:
@@ -32,6 +32,7 @@ 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 { ThisMemberExpression } = require("./expressiontypes/ThisMemberExpression");
|
||||||
|
const { UnaryOpExpression } = require("./expressiontypes/UnaryOpExpression");
|
||||||
const { Variable } = require("./expressiontypes/Variable");
|
const { Variable } = require("./expressiontypes/Variable");
|
||||||
|
|
||||||
const { BooleanLiteral } = require('./expressiontypes/literals/Boolean');
|
const { BooleanLiteral } = require('./expressiontypes/literals/Boolean');
|
||||||
@@ -1512,13 +1513,17 @@ function rootTerm(tokens, mdecls, scope, imports, typemap) {
|
|||||||
matches = new ResolvedIdent(tokens.current, [NumberLiteral.from(tokens.current)]);
|
matches = new ResolvedIdent(tokens.current, [NumberLiteral.from(tokens.current)]);
|
||||||
break;
|
break;
|
||||||
case 'inc-operator':
|
case 'inc-operator':
|
||||||
let incop = tokens.getIfKind('inc-operator');
|
let incop = tokens.consume();
|
||||||
matches = qualifiedTerm(tokens, mdecls, scope, imports, typemap);
|
matches = qualifiedTerm(tokens, mdecls, scope, imports, typemap);
|
||||||
return new ResolvedIdent(`${incop.value}${matches.source}`, [new IncDecExpression(matches, incop, 'prefix')])
|
return new ResolvedIdent(`${incop.value}${matches.source}`, [new IncDecExpression(matches, incop, 'prefix')])
|
||||||
case 'plumin-operator':
|
case 'plumin-operator':
|
||||||
case 'unary-operator':
|
case 'unary-operator':
|
||||||
tokens.inc();
|
let unaryop = tokens.consume();
|
||||||
return qualifiedTerm(tokens, mdecls, scope, imports, typemap);
|
matches = qualifiedTerm(tokens, mdecls, scope, imports, typemap);
|
||||||
|
let unary_value = matches.variables[0] instanceof NumberLiteral
|
||||||
|
? NumberLiteral[unaryop.value](matches.variables[0])
|
||||||
|
: new UnaryOpExpression(matches, unaryop);
|
||||||
|
return new ResolvedIdent(`${unaryop.value}${matches.source}`, [unary_value])
|
||||||
case 'new-operator':
|
case 'new-operator':
|
||||||
return newTerm(tokens, mdecls, scope, imports, typemap);
|
return newTerm(tokens, mdecls, scope, imports, typemap);
|
||||||
case 'open-bracket':
|
case 'open-bracket':
|
||||||
|
|||||||
96
langserver/java/expressiontypes/UnaryOpExpression.js
Normal file
96
langserver/java/expressiontypes/UnaryOpExpression.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* @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');
|
||||||
|
const ParseProblem = require('../parsetypes/parse-problem');
|
||||||
|
const { AnyType } = require('../anys');
|
||||||
|
const { NumberLiteral } = require('./literals/Number');
|
||||||
|
|
||||||
|
class UnaryOpExpression extends Expression {
|
||||||
|
/**
|
||||||
|
* @param {ResolvedIdent} expression
|
||||||
|
* @param {Token} op
|
||||||
|
*/
|
||||||
|
constructor(expression, op) {
|
||||||
|
super();
|
||||||
|
this.expression = expression;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ResolveInfo} ri
|
||||||
|
*/
|
||||||
|
resolveExpression(ri) {
|
||||||
|
const operator = this.op.value;
|
||||||
|
const value = this.expression.resolveExpression(ri);
|
||||||
|
|
||||||
|
if (value instanceof AnyType) {
|
||||||
|
return AnyType.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof NumberLiteral) {
|
||||||
|
if (/^[+-]$/.test(operator)) {
|
||||||
|
return NumberLiteral[operator](value);
|
||||||
|
}
|
||||||
|
if (/^[!~]$/.test(operator) && value.type.typeSignature === 'I') {
|
||||||
|
return NumberLiteral[operator](value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = value instanceof JavaType ? value : value instanceof NumberLiteral ? value.type : null;
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
ri.problems.push(ParseProblem.Error(this.expression.tokens, `Expression expected`));
|
||||||
|
return AnyType.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkOperator(operator, ri, this.op, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens() {
|
||||||
|
return [this.op, ...this.expression.tokens];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} operator
|
||||||
|
* @param {ResolveInfo} ri
|
||||||
|
* @param {Token} operator_token
|
||||||
|
* @param {JavaType} type
|
||||||
|
*/
|
||||||
|
function checkOperator(operator, ri, operator_token, type) {
|
||||||
|
|
||||||
|
let is_valid = false;
|
||||||
|
/** @type {JavaType} */
|
||||||
|
let return_type = AnyType.Instance;
|
||||||
|
|
||||||
|
if (/^[+-]$/.test(operator)) {
|
||||||
|
// math operators - must be numeric
|
||||||
|
is_valid = /^[BSIJFDC]$/.test(type.typeSignature);
|
||||||
|
return_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^~$/.test(operator)) {
|
||||||
|
// bitwise invert operator - must be integral
|
||||||
|
is_valid = /^[BSIJC]$/.test(type.typeSignature);
|
||||||
|
return_type = PrimitiveType.map.I;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^!$/.test(operator)) {
|
||||||
|
// logical not operator - must be boolean
|
||||||
|
is_valid = /^Z$/.test(type.typeSignature);
|
||||||
|
return_type = PrimitiveType.map.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_valid) {
|
||||||
|
ri.problems.push(ParseProblem.Error(operator_token, `Operator '${operator_token.value}' is not valid for type '${type.fullyDottedTypeName}'`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return return_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.UnaryOpExpression = UnaryOpExpression;
|
||||||
@@ -77,6 +77,32 @@ class NumberLiteral extends LiteralValue {
|
|||||||
return NumberLiteral.calc(a, b, 'int-number-literal', type, val);
|
return NumberLiteral.calc(a, b, 'int-number-literal', type, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NumberLiteral} a
|
||||||
|
* @param {string} opvalue
|
||||||
|
* @param {(a) => Number} op
|
||||||
|
*/
|
||||||
|
static unary(a, opvalue, op) {
|
||||||
|
if (opvalue === '-') {
|
||||||
|
const ai = a.toNumber();
|
||||||
|
if (ai === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const val = op(ai);
|
||||||
|
const type = PrimitiveType.map[a.type.typeSignature];
|
||||||
|
const toks = a.tokens();
|
||||||
|
return new NumberLiteral(Array.isArray(toks) ? toks : [toks], 'int-number-literal', type, val.toString());
|
||||||
|
}
|
||||||
|
const ai = a.toInt();
|
||||||
|
if (ai === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const val = op(ai);
|
||||||
|
const type = /J/.test(a.type.typeSignature) ? PrimitiveType.map.J : PrimitiveType.map.I;
|
||||||
|
const toks = a.tokens();
|
||||||
|
return new NumberLiteral(Array.isArray(toks) ? toks : [toks], 'int-number-literal', type, val.toString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {NumberLiteral} a
|
* @param {NumberLiteral} a
|
||||||
* @param {NumberLiteral} b
|
* @param {NumberLiteral} b
|
||||||
@@ -99,8 +125,15 @@ class NumberLiteral extends LiteralValue {
|
|||||||
return NumberLiteral.calc(a, b, 'int-number-literal', type, val);
|
return NumberLiteral.calc(a, b, 'int-number-literal', type, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static '+'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a + b) }
|
static '~'(value) { return NumberLiteral.unary(value, '~', (a) => ~a) }
|
||||||
static '-'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a - b) }
|
static '+'(lhs, rhs) { return !rhs
|
||||||
|
? lhs // unary e.g +5
|
||||||
|
: NumberLiteral.math(lhs, rhs, (a,b) => a + b)
|
||||||
|
}
|
||||||
|
static '-'(lhs, rhs) { return !rhs
|
||||||
|
? NumberLiteral.unary(lhs, '-', (a) => -a)
|
||||||
|
: NumberLiteral.math(lhs, rhs, (a,b) => a - b)
|
||||||
|
}
|
||||||
static '*'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a * b) }
|
static '*'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a * b) }
|
||||||
static '/'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a / b) }
|
static '/'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a / b) }
|
||||||
static '%'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a % b) }
|
static '%'(lhs, rhs) { return NumberLiteral.math(lhs, rhs, (a,b) => a % b) }
|
||||||
|
|||||||
Reference in New Issue
Block a user