Skip to content

Commit fcbe4c1

Browse files
committed
fix: address indexing expression errors and refactor to use ndarray/base/slice
1 parent 15373b4 commit fcbe4c1

10 files changed

Lines changed: 203 additions & 471 deletions

File tree

lib/node_modules/@stdlib/ndarray/fancy/examples/0d.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,8 @@ console.log( y2.get() );
6060
var y3 = x[ '' ];
6161
console.log( y3.get() );
6262
// => 10
63+
64+
// Use alternative syntax:
65+
var y4 = x[ '...' ];
66+
console.log( y4.get() );
67+
// => 10

lib/node_modules/@stdlib/ndarray/fancy/lib/empty.js

Lines changed: 0 additions & 56 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2023 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var isRangeError = require( '@stdlib/assert/is-range-error' );
24+
var isTypeError = require( '@stdlib/assert/is-type-error' );
25+
var isSyntaxError = require( '@stdlib/assert/is-syntax-error' );
26+
27+
28+
// MAIN //
29+
30+
/**
31+
* Returns the error constructor for a provided error object.
32+
*
33+
* @private
34+
* @param {Error} err - error object
35+
* @returns {Function} error constructor
36+
*/
37+
function errConstructor( err ) {
38+
if ( isRangeError( err ) ) {
39+
return RangeError;
40+
}
41+
if ( isTypeError( err ) ) {
42+
return TypeError;
43+
}
44+
if ( isSyntaxError( err ) ) {
45+
return SyntaxError;
46+
}
47+
return Error;
48+
}
49+
50+
51+
// EXPORTS //
52+
53+
module.exports = errConstructor;

lib/node_modules/@stdlib/ndarray/fancy/lib/slice_strides.js renamed to lib/node_modules/@stdlib/ndarray/fancy/lib/error_message.js

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,25 @@
1818

1919
'use strict';
2020

21+
// MODULES //
22+
23+
var replace = require( '@stdlib/string/base/replace' );
24+
25+
2126
// MAIN //
2227

2328
/**
24-
* Resolves slice strides for a provided normalized multi-slice object.
29+
* Returns an updated error message for trapped errors.
2530
*
2631
* @private
27-
* @param {MultiSlice} slice - normalized multi-slice object
28-
* @param {IntegerArray} strides - array strides
29-
* @param {NonNegativeIntegerArray} sdims - indices of non-reduced dimensions
30-
* @returns {IntegerArray} slice strides
32+
* @param {string} msg - error message
33+
* @returns {string} updated message
3134
*/
32-
function sliceStrides( slice, strides, sdims ) {
33-
var data;
34-
var out;
35-
var i;
36-
var j;
37-
38-
data = slice.data;
39-
out = [];
40-
for ( i = 0; i < sdims.length; i++ ) {
41-
j = sdims[ i ];
42-
out.push( strides[j]*data[j].step );
43-
}
44-
return out;
35+
function errMessage( msg ) {
36+
return replace( msg, /^invalid argument/, 'invalid operation' );
4537
}
4638

4739

4840
// EXPORTS //
4941

50-
module.exports = sliceStrides;
42+
module.exports = errMessage;

lib/node_modules/@stdlib/ndarray/fancy/lib/get.0d.js

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@
2222

2323
var isFunction = require( '@stdlib/assert/is-function' );
2424
var trim = require( '@stdlib/string/base/trim' );
25+
var replace = require( '@stdlib/string/base/replace' );
26+
var MultiSlice = require( '@stdlib/slice/multi' );
2527
var str2multislice = require( '@stdlib/slice/base/str2multislice' );
28+
var seq2multislice = require( '@stdlib/slice/base/seq2multislice' );
29+
var str2slice = require( '@stdlib/slice/base/str2slice' );
30+
var slice = require( '@stdlib/ndarray/base/slice' );
2631
var format = require( '@stdlib/string/format' );
32+
var errMessage = require( './error_message.js' );
33+
var errConstructor = require( './error_constructor.js' );
2734
var hasProperty = require( './has_property.js' );
28-
var options = require( './array_options.js' );
2935
var RE_INTEGER = require( './re_integer.js' );
36+
var RE_SUBSEQ = require( './re_subseq.js' );
3037

3138

3239
// MAIN //
@@ -42,12 +49,12 @@ var RE_INTEGER = require( './re_integer.js' );
4249
* @throws {RangeError} number of slice dimensions must match the number of array dimensions
4350
* @returns {*} result
4451
*/
45-
function get( target, property, receiver ) {
46-
var dtype;
52+
function get( target, property, receiver ) { // eslint-disable-line stdlib/jsdoc-require-throws-tags
4753
var value;
54+
var shape;
4855
var prop;
4956
var ch;
50-
var sh;
57+
var E;
5158
var s;
5259
if ( hasProperty( property ) ) {
5360
value = target[ property ];
@@ -58,41 +65,67 @@ function get( target, property, receiver ) {
5865
}
5966
prop = trim( property );
6067

61-
// Resolve target meta data:
62-
dtype = target.dtype;
63-
sh = target.shape;
64-
6568
// Retrieve the first character in order to to detect how a slice operation was specified:
6669
ch = prop[ 0 ];
6770

71+
// Case: slice
72+
if ( ch === 'S' ) {
73+
// Convert the string to a slice object:
74+
s = str2slice( property );
75+
if ( s === null ) {
76+
throw new Error( format( 'invalid operation. Unsupported slice operation. Value: `%s`.', property ) );
77+
}
78+
// Create a multi-slice:
79+
s = new MultiSlice( s );
80+
}
6881
// Case: multi-slice
69-
if ( ch === 'M' ) {
82+
else if ( ch === 'M' ) {
7083
// Convert the string to a slice object:
7184
s = str2multislice( prop );
7285
if ( s === null ) {
7386
throw new Error( format( 'invalid operation. Unsupported slice operation. Value: `%s`.', property ) );
7487
}
75-
// TODO: => @stdlib/ndarray/base/slice: return slice( receiver, s.data );
88+
}
89+
// Case: integer
90+
else if ( RE_INTEGER.test( prop ) ) {
91+
// Convert the string to a numeric value:
92+
s = parseInt( prop, 10 );
7693

77-
// Ensure that we were provided an empty multi-slice:
78-
if ( s.ndims !== sh.length ) {
79-
throw new RangeError( format( 'invalid operation. Number of array dimensions does not match the number of slice dimensions. Array shape: (%s). Slice dimensions: %u.', sh.join( ',' ), s.ndims ) );
94+
// Create a multi-slice:
95+
s = new MultiSlice( s );
96+
}
97+
// Case: subsequence string (e.g., ':10,1,::-1,:,-5,2::3')
98+
else if ( RE_SUBSEQ.test( prop ) ) {
99+
shape = target.shape;
100+
s = seq2multislice( prop, shape, true );
101+
if ( s.code ) {
102+
if ( s.code === 'ERR_SLICE_INVALID_INCREMENT' ) {
103+
throw new Error( format( 'invalid operation. A subsequence increment must be a non-zero integer. Value: `%s`.', property ) );
104+
}
105+
if ( s.code === 'ERR_SLICE_INVALID_ELLIPSIS' ) {
106+
throw new Error( format( 'invalid operation. A subsequence may only include a single ellipsis. Value: `%s`.', property ) );
107+
}
108+
if ( s.code === 'ERR_SLICE_INVALID_SUBSEQUENCE' ) {
109+
throw new Error( format( 'invalid operation. Unsupported slice operation. Value: `%s`.', property ) );
110+
}
111+
// s.code === 'ERR_SLICE_TOO_MANY_DIMENSIONS'
112+
throw new RangeError( format( 'invalid operation. Number of slice dimensions does not match the number of array dimensions. Array shape: (%s). Slice dimensions: %u.', shape.join( ',' ), replace( prop, /\.\.\.,/, '' ).split( ',' ).length ) );
80113
}
81114
}
115+
// Case: empty string or ellipsis
116+
else if ( prop.length === 0 || prop === '...' ) {
117+
s = new MultiSlice();
118+
}
82119
// Case: non-empty string
83-
else if ( prop.length !== 0 ) {
84-
// TODO: the following can be generalized by going ahead and parsing the slice string or integer and passing to a functional API which then verifies that s.ndims !== sh.length. We need only retain the error raised for an invalid operation.
85-
86-
// Case: slice or an integer
87-
if ( ch === 'S' || RE_INTEGER.test( prop ) ) {
88-
throw new RangeError( format( 'invalid operation. Number of array dimensions does not match the number of slice dimensions. Array shape: (%s). Slice dimensions: %u.', sh.join( ',' ), 1 ) );
89-
}
120+
else {
90121
throw new Error( format( 'invalid operation. Unsupported slice operation. Value: `%s`.', property ) );
91122
}
92-
// TODO: => @stdlib/ndarray/base/slice: return slice( receiver, [] );
93-
94-
// Return an zero-dimensional array view:
95-
return new receiver.constructor( dtype, target.data, sh, target.strides, target.offset, target.order, options() ); // eslint-disable-line max-len
123+
try {
124+
return slice( receiver, s, true );
125+
} catch ( err ) {
126+
E = errConstructor( err );
127+
throw new E( errMessage( err.message ) );
128+
}
96129

97130
/**
98131
* Method wrapper.

0 commit comments

Comments
 (0)