Skip to content

Commit 0681483

Browse files
authored
Allow identifiers mix letters and numbers (#36)
* Allow identifiers mix letters and numbers * Add check to prevent indentifiers starting with a digit * Precompute a single identifierCharRegex * Refactor unit test --------- Co-authored-by: Maribel Guzmán Marcial <maribel.guzmanmarcial@arm.com>
1 parent 4b067a3 commit 0681483

4 files changed

Lines changed: 90 additions & 36 deletions

File tree

src/views/config-wizard/parser/cw-option-assign.test.ts

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,71 @@ const tokenizer = new Tokenizer();
3131
describe('CwOptionAssign', () => {
3232
const parent = new CwOption;
3333

34-
it('test assignment', () => {
34+
function runAssignment(cmdStr: string, textStr = 'foo') {
3535
ClearErrors();
36+
3637
const item = new CwOptionAssign(parent);
3738
const lineNo = 1;
38-
const cmdStr = '1=';
39-
const textStr = 'foo';
4039
const cmd = tokenizer.tokenizeCmd(cmdStr, lineNo);
4140
const text = tokenizer.tokenizeDescr(textStr, lineNo);
4241
item.addProperty(cmd, text, lineNo);
42+
43+
return {
44+
item,
45+
errors: GetErrors()
46+
};
47+
}
48+
49+
it('test assignment', () => {
50+
const { item, errors } = runAssignment('1=');
4351
const itemText = item.getItemText();
4452
expect(itemText).not.toBe('');
45-
46-
const errors = GetErrors();
47-
const numErr = errors.length;
48-
expect(numErr).toBe(0);
53+
expect(errors.length).toBe(0);
4954
});
5055

5156
it('test error assignment', () => {
52-
const item = new CwOptionAssign(parent);
53-
const lineNo = 1;
54-
const cmdStr = '=';
55-
const textStr = 'foo';
56-
const cmd = tokenizer.tokenizeCmd(cmdStr, lineNo);
57-
const text = tokenizer.tokenizeDescr(textStr, lineNo);
58-
item.addProperty(cmd, text, lineNo); // will throw error
57+
const { item, errors } = runAssignment('='); // will throw error
5958
const itemText = item.getItemText();
6059
expect(itemText).not.toBe('');
60+
expect(errors.length).toBe(1);
61+
});
62+
63+
it('rejects symbol assignment starting with digit and underscore', () => {
64+
const { errors } = runAssignment('1_FOO=');
65+
expect(errors.length).toBeGreaterThan(0);
66+
});
67+
68+
it('rejects symbol assignment starting with digit and letters', () => {
69+
const { errors } = runAssignment('2BAR=', 'bar');
70+
expect(errors.length).toBeGreaterThan(0);
71+
});
72+
73+
it('accepts hexadecimal assignment values', () => {
74+
const { item, errors } = runAssignment('0x2A=');
75+
76+
expect(item.value?.getGuiString()).toBe('0x2A');
77+
expect(errors.length).toBe(0);
78+
});
79+
80+
it('accepts octal assignment values', () => {
81+
const { item, errors } = runAssignment('077=');
82+
83+
expect(item.value?.getGuiString()).toBe('077');
84+
expect(errors.length).toBe(0);
85+
});
86+
87+
it('accepts binary assignment values', () => {
88+
const { item, errors } = runAssignment('0b1010=');
89+
90+
expect(item.value?.getGuiString()).toBe('0b1010');
91+
expect(errors.length).toBe(0);
92+
});
93+
94+
it('accepts valid identifier assignment values', () => {
95+
const { item, errors } = runAssignment('FOO_BAR2=');
6196

62-
const errors = GetErrors();
63-
const numErr = errors.length;
64-
expect(numErr).toBe(1);
97+
expect(item.value?.getGuiString()).toBe('FOO_BAR2');
98+
expect(errors.length).toBe(0);
6599
});
66100

67101
});

src/views/config-wizard/parser/cw-option.test.ts

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,13 @@ describe('CwOption', () => {
5454
tokenizer.tokenizeDescr('Pin PE3', 2),
5555
2
5656
);
57-
option.addOption(pinPE3);
5857

5958
const pinPC1 = new CwOptionAssign(option);
6059
pinPC1.addProperty(
6160
tokenizer.tokenizeCmd('0x00020001=', 3),
6261
tokenizer.tokenizeDescr('Pin PC1', 3),
6362
3
6463
);
65-
option.addOption(pinPC1);
6664
});
6765

6866
it('should match value with 8-digit hex (0x00040003) to option with 8-digit hex', () => {
@@ -134,15 +132,13 @@ describe('CwOption', () => {
134132
tokenizer.tokenizeDescr('Pin PE3', 2),
135133
2
136134
);
137-
traced0.addOption(pe3);
138135

139136
const pc1 = new CwOptionAssign(traced0);
140137
pc1.addProperty(
141138
tokenizer.tokenizeCmd('0x00020001=', 3),
142139
tokenizer.tokenizeDescr('Pin PC1', 3),
143140
3
144141
);
145-
traced0.addOption(pc1);
146142

147143
// TRACED1 options
148144
traced1 = new CwOption();
@@ -158,15 +154,13 @@ describe('CwOption', () => {
158154
tokenizer.tokenizeDescr('Pin PE4', 5),
159155
5
160156
);
161-
traced1.addOption(pe4);
162157

163158
const pc10 = new CwOptionAssign(traced1);
164159
pc10.addProperty(
165160
tokenizer.tokenizeCmd('0x0002000A=', 6),
166161
tokenizer.tokenizeDescr('Pin PC10', 6),
167162
6
168163
);
169-
traced1.addOption(pc10);
170164

171165
// TRACED2 options
172166
traced2 = new CwOption();
@@ -182,15 +176,13 @@ describe('CwOption', () => {
182176
tokenizer.tokenizeDescr('Pin PE5', 8),
183177
8
184178
);
185-
traced2.addOption(pe5);
186179

187180
const pd2 = new CwOptionAssign(traced2);
188181
pd2.addProperty(
189182
tokenizer.tokenizeCmd('0x00030002=', 9),
190183
tokenizer.tokenizeDescr('Pin PD2', 9),
191184
9
192185
);
193-
traced2.addOption(pd2);
194186

195187
// TRACED3 options
196188
traced3 = new CwOption();
@@ -206,15 +198,13 @@ describe('CwOption', () => {
206198
tokenizer.tokenizeDescr('Pin PE6', 11),
207199
11
208200
);
209-
traced3.addOption(pe6);
210201

211202
const pc12 = new CwOptionAssign(traced3);
212203
pc12.addProperty(
213204
tokenizer.tokenizeCmd('0x0002000C=', 12),
214205
tokenizer.tokenizeDescr('Pin PC12', 12),
215206
12
216207
);
217-
traced3.addOption(pc12);
218208
});
219209

220210
it('should correctly match all TRACED0 pin values from dbgconf', () => {
@@ -285,21 +275,47 @@ describe('CwOption', () => {
285275
tokenizer.tokenizeDescr('PushPull', 2),
286276
2
287277
);
288-
option.addOption(opt1);
289278

290279
const opt2 = new CwOptionAssign(option);
291280
opt2.addProperty(
292281
tokenizer.tokenizeCmd('OutOpenDrain_GPIO=', 3),
293282
tokenizer.tokenizeDescr('OpenDrain', 3),
294283
3
295284
);
296-
option.addOption(opt2);
297285

298286
const textValue = new TextType('OutPushPull_GPIO');
299287
const matched = option.getOption(textValue);
300288
expect(matched).toBeDefined();
301289
expect(matched?.description.getText()).toBe('PushPull');
302290
});
291+
292+
it('should match mixed alphanumeric identifier options correctly', () => {
293+
const option = new CwOption();
294+
option.addProperty(
295+
tokenizer.tokenizeCmd('o MACRO2', 1),
296+
tokenizer.tokenizeDescr('Role level', 1),
297+
1
298+
);
299+
300+
const opt1 = new CwOptionAssign(option);
301+
opt1.addProperty(
302+
tokenizer.tokenizeCmd('LEVEL_UNKNOWN=', 2),
303+
tokenizer.tokenizeDescr('LEVEL_UNKNOWN', 2),
304+
2
305+
);
306+
307+
const opt2 = new CwOptionAssign(option);
308+
opt2.addProperty(
309+
tokenizer.tokenizeCmd('LEVEL_3P1=', 3),
310+
tokenizer.tokenizeDescr('LEVEL_3P1', 3),
311+
3
312+
);
313+
314+
const textValue = new TextType('LEVEL_3P1');
315+
const matched = option.getOption(textValue);
316+
expect(matched).toBeDefined();
317+
expect(matched?.description.getText()).toBe('LEVEL_3P1');
318+
});
303319
});
304320

305321
describe('Edge cases', () => {
@@ -330,7 +346,6 @@ describe('CwOption', () => {
330346
tokenizer.tokenizeDescr('Zero option', 2),
331347
2
332348
);
333-
option.addOption(opt0);
334349

335350
const value = new NumberType('0x0');
336351
const matched = option.getOption(value);
@@ -353,7 +368,6 @@ describe('CwOption', () => {
353368
tokenizer.tokenizeDescr('Max 32-bit value', 2),
354369
2
355370
);
356-
option.addOption(optLarge);
357371

358372
const value = new NumberType('0xFFFFFFFF');
359373
const matched = option.getOption(value);
@@ -385,7 +399,6 @@ describe('CwOption', () => {
385399
tokenizer.tokenizeDescr(`${count} entries`, lineNo),
386400
lineNo
387401
);
388-
option.addOption(opt);
389402
lineNo++;
390403
}
391404
});
@@ -522,7 +535,6 @@ describe('CwOption', () => {
522535
tokenizer.tokenizeDescr(`${count} entries`, lineNo),
523536
lineNo
524537
);
525-
option.addOption(opt);
526538
lineNo++;
527539
}
528540
});
@@ -644,7 +656,6 @@ describe('CwOption', () => {
644656
tokenizer.tokenizeDescr(`${count} entries`, lineNo),
645657
lineNo
646658
);
647-
option.addOption(opt);
648659
lineNo++;
649660
}
650661
});

src/views/config-wizard/parser/tokenizer.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ const res: result[] = [
4141
{ input: '// <BAR=> Bar',
4242
cmd: { text: 'BAR=', items: [ 'BAR', '=' ] },
4343
text: { text: 'Bar', items: [ 'Bar' ] } },
44+
{ input: '// <LEVEL_3P1=> Level 3P1',
45+
cmd: { text: 'LEVEL_3P1=', items: [ 'LEVEL_3P1', '=' ] },
46+
text: { text: 'Level 3P1', items: [ 'Level 3P1' ] } },
4447
{ input: '// <-7..-4:2>',
4548
cmd: { text: '-7..-4:2', items: [ '-7', '..', '-4', ':', '2' ] },
4649
text: { text: '', items: [ ] } },

src/views/config-wizard/parser/tokenizer.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export class Tokenizer {
9090
return token;
9191
}
9292

93+
const isAssignmentToken = text.includes('=');
94+
const identifierCharRegex = isAssignmentToken ? /[a-z\d_]/i : /[a-z_]/i;
95+
9396
let canBeNegative = false;
9497
if (text.indexOf('..') != -1) {
9598
canBeNegative = true;
@@ -128,6 +131,7 @@ export class Tokenizer {
128131
// search for number
129132
if (ch.match(/[\d]/)) {
130133
let str = '';
134+
let numTokenPattern = /[\d]/i;
131135
if (isNegative) {
132136
str += '-';
133137
}
@@ -138,9 +142,11 @@ export class Tokenizer {
138142
if (chTmp == 'x' || chTmp == 'X') {
139143
str += '0x';
140144
pos += 2;
145+
numTokenPattern = /[\da-f]/i;
141146
} else if (chTmp == 'b' || chTmp == 'B') {
142147
str += '0b';
143148
pos += 2;
149+
numTokenPattern = /[01]/i;
144150
}
145151
if (pos >= length) {
146152
pos = length - 1;
@@ -150,7 +156,7 @@ export class Tokenizer {
150156

151157
do {
152158
ch = text[pos];
153-
if (!ch.match(/[\da-f]/i)) {
159+
if (!ch.match(numTokenPattern)) {
154160
break;
155161
}
156162
str += ch;
@@ -177,7 +183,7 @@ export class Tokenizer {
177183
let str = '';
178184
do {
179185
ch = text[pos++];
180-
if (!ch.match(/[a-z_]/i)) {
186+
if (!ch.match(identifierCharRegex)) {
181187
pos--;
182188
break;
183189
}

0 commit comments

Comments
 (0)