Skip to content

Commit

Permalink
Fixed compiling of constructor and type reference. Fixed unary plus/m…
Browse files Browse the repository at this point in the history
…inus. Added node.getRaw(). (#14)
  • Loading branch information
ukrbublik committed Jan 21, 2022
1 parent 357ee52 commit ae83580
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/SpelExpressionParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ export var SpelExpressionParser = function () {
return true;
}
var value = node.stringValue();
return (value.length && VALID_QUALIFIED_ID_PATTERN.test(value));
return (value && value.length && VALID_QUALIFIED_ID_PATTERN.test(value));
}

// This is complicated due to the support for dollars in identifiers. Dollars are normally separate tokens but
Expand Down
4 changes: 2 additions & 2 deletions src/ast/BeanReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {SpelNode} from './SpelNode';
*
* @author Andy Clement
*/
function createNode(position, left, right) {
var node = SpelNode.create('beanref', position, left, right);
function createNode(position, beanName) {
var node = SpelNode.create('beanref', position);

node.getValue = function (state) {
throw {
Expand Down
45 changes: 42 additions & 3 deletions src/ast/ConstructorReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {SpelNode} from './SpelNode';
import {Stack} from '../lib/Stack';

/**
* Represents the invocation of a constructor. Either a constructor on a regular type or
Expand All @@ -29,13 +30,51 @@ import {SpelNode} from './SpelNode';
* @author Juergen Hoeller
* @since 3.0
*/
function createNode(position, left, right) {
var node = SpelNode.create('constructorref', position, left, right);
function createNode(position, dimensions, nodes) {
var isArray = nodes !== undefined;
var dimension;
if (isArray) {
dimension = dimensions.length && dimensions[0] && dimensions[0].getType() === 'number' ? dimensions[0].getValue() : null;
} else {
nodes = dimensions;
dimensions = undefined;
}
const [_qualifiedIdentifier, ...args] = nodes;

var node = SpelNode.create('constructorref', position, ...nodes);

node.getRaw = function () {
return dimension;
};

node.getValue = function (state) {
if (isArray && args.length <= 1) {
var compiledArgs = [];

//populate arguments
args.forEach(function (arg) {
// reset the active context to root context for evaluating argument
const currentActiveContext = state.activeContext
state.activeContext = new Stack();
state.activeContext.push(state.rootContext);

// evaluate argument
compiledArgs.push(arg.getValue(state));

// reset the active context
state.activeContext = currentActiveContext;
});

if (args.length === 1) {
return compiledArgs[0];
} else {
return dimension ? new Array(dimension) : [];
}
}

throw {
name: 'MethodNotImplementedException',
message: 'BeanReference: Not implemented'
message: 'ConstructorReference: Not implemented'
}
};

Expand Down
7 changes: 7 additions & 0 deletions src/ast/FunctionReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ import {Stack} from '../lib/Stack';
function createNode(functionName, position, args) {
var node = SpelNode.create('function', position);

node.getRaw = function () {
return {
functionName,
args
};
};

node.getValue = function (state) {
var locals = state.locals || {},
context = state.rootContext,
Expand Down
8 changes: 6 additions & 2 deletions src/ast/Identifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ import {SpelNode} from './SpelNode';
* @author Andy Clement
* @since 3.0
*/
function createNode(position, left, right) {
var node = SpelNode.create('identifier', position, left, right);
function createNode(identifierName, position) {
var node = SpelNode.create('identifier', position);

node.getRaw = function () {
return identifierName;
};

node.getValue = function (state) {
throw {
Expand Down
4 changes: 4 additions & 0 deletions src/ast/InlineList.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ function createNode(position, elements) {
var node = SpelNode.create('list', position),
list = [].concat(elements || []);

node.getRaw = function () {
return list;
};

node.getValue = function (state) {
return list.map(function (element) {
return element.getValue(state);
Expand Down
7 changes: 7 additions & 0 deletions src/ast/MethodReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ import {Stack} from '../lib/Stack'
function createNode(nullSafeNavigation, methodName, position, args) {
var node = SpelNode.create('method', position);

node.getRaw = function () {
return {
methodName,
args
};
};

node.getValue = function (state) {
var context = state.activeContext.peek(),
compiledArgs = [],
Expand Down
3 changes: 3 additions & 0 deletions src/ast/OpMinus.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ function createNode(position, left, right) {
var node = SpelNode.create('op-minus', position, left, right);

node.getValue = function (state) {
if (!right) {
return - left.getValue(state);
}
return left.getValue(state) - right.getValue(state);
};

Expand Down
3 changes: 3 additions & 0 deletions src/ast/OpPlus.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ function createNode(position, left, right) {
var node = SpelNode.create('op-plus', position, left, right);

node.getValue = function (state) {
if (!right) {
return + left.getValue(state);
}
//javascript will handle string concatenation or addition depending on types
return left.getValue(state) + right.getValue(state);
};
Expand Down
4 changes: 4 additions & 0 deletions src/ast/PropertyReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import {SpelNode} from './SpelNode';
function createNode(nullSafeNavigation, propertyName, position) {
var node = SpelNode.create('property', position);

node.getRaw = function () {
return propertyName;
};

node.getValue = function (state) {
var context = state.activeContext.peek();

Expand Down
8 changes: 6 additions & 2 deletions src/ast/QualifiedIdentifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ import {SpelNode} from './SpelNode';
* @author Andy Clement
* @since 3.0
*/
function createNode(position, left, right) {
var node = SpelNode.create('qualifiedidentifier', position, left, right);
function createNode(position, pieces) {
var node = SpelNode.create('qualifiedidentifier', position, ...pieces);

node.getRaw = function () {
return pieces.map(p => p.getRaw());
};

node.getValue = function (state) {
throw {
Expand Down
10 changes: 10 additions & 0 deletions src/ast/SpelNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ function createSpelNode(nodeType, position, ...operands) {
return children;
};
node.addChild = function (childNode) {
if (!childNode) {
// See OpMinus and OpPlus: right node can be null for unary mode
return;
}
if (!childNode.setParent) {
throw {
name: 'Error',
message: 'Trying to add a child which is not a node: ' + JSON.stringify(childNode)
};
}
childNode.setParent(node);
children.push(childNode);
};
Expand Down
4 changes: 2 additions & 2 deletions src/ast/TypeReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {SpelNode} from './SpelNode';
*
* @author Andy Clement
*/
function createNode(position, left, right) {
var node = SpelNode.create('typeref', position, left, right);
function createNode(position, node, _dims) {
var node = SpelNode.create('typeref', position, node);

node.getValue = function (state) {
throw {
Expand Down
4 changes: 4 additions & 0 deletions src/ast/VariableReference.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import {SpelNode} from './SpelNode';
function createNode(variableName, position) {
var node = SpelNode.create('variable', position);

node.getRaw = function () {
return variableName;
};

node.getValue = function (state) {
var context = state.activeContext.peek(),
locals = state.locals;
Expand Down
82 changes: 82 additions & 0 deletions test/spec/SpelExpressionEvaluator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,38 @@ describe('spel expression evaluator', ()=>{
expect(compiledExpression.eval).toBeDefined();
});

it('should compile expression with constructor', ()=>{
//when
let compiledExpression = evaluator.compile('new java.text.SimpleDateFormat("yyyy-MM-dd").parse("2022-01-01")');

//then
expect(compiledExpression.eval).toBeDefined();
});

it('should compile expression with array constructor without dimensions', ()=>{
//when
let compiledExpression = evaluator.compile('new int[]{1,2,3}');

//then
expect(compiledExpression.eval).toBeDefined();
});

it('should compile expression with array constructor with dimensions', ()=>{
//when
let compiledExpression = evaluator.compile('new int[3]{1,2,3}');

//then
expect(compiledExpression.eval).toBeDefined();
});

it('should compile expression with type reference', ()=>{
//when
let compiledExpression = evaluator.compile('T(java.time.LocalTime).parse("11:22")');

//then
expect(compiledExpression.eval).toBeDefined();
});

});


Expand All @@ -28,10 +60,14 @@ describe('spel expression evaluator', ()=>{
//when
let numberInt = evaluator.eval('123');
let numberFloat = evaluator.eval('123.4');
let negativeNumberInt = evaluator.eval('-123');
let negativeNumberFloat = evaluator.eval('-123.4');

//then
expect(numberInt).toBe(123);
expect(numberFloat).toBe(123.4);
expect(negativeNumberInt).toBe(-123);
expect(negativeNumberFloat).toBe(-123.4);
});

it('should evaluate a string', ()=>{
Expand Down Expand Up @@ -833,6 +869,52 @@ describe('spel expression evaluator', ()=>{

});

describe('constructor', ()=>{
it('should create new int array', ()=>{
//given
let context = {};

//when
let newArray = evaluator.eval('new int[]{1, 2, 3}', context);

//then
expect(newArray).toEqual([1, 2, 3]);
});

it('should create new int array with dimension', ()=>{
//given
let context = {};

//when
let newArray = evaluator.eval('new int[3]{1, 2, 3}', context);

//then
expect(newArray).toEqual([1, 2, 3]);
});

it('should create new empty array', ()=>{
//given
let context = {};

//when
let newArray = evaluator.eval('new int[]', context);

//then
expect(newArray).toEqual([]);
});

it('should create new empty array with dimension', ()=>{
//given
let context = {};

//when
let newArray = evaluator.eval('new int[3]', context);

//then
expect(newArray.length).toEqual(3);
});
});

});

});

0 comments on commit ae83580

Please sign in to comment.