Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion grammars/apex.tmLanguage
Original file line number Diff line number Diff line change
Expand Up @@ -3798,7 +3798,7 @@
<key>conditional-operator</key>
<dict>
<key>begin</key>
<string>(?&lt;!\?)\?(?!\?|\.|\[)</string>
<string>(?&lt;!\?)\?(?!\?|\.(?!\d)|\[)</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
Expand Down
2 changes: 1 addition & 1 deletion grammars/apex.tmLanguage.cson
Original file line number Diff line number Diff line change
Expand Up @@ -2242,7 +2242,7 @@ repository:
}
]
'conditional-operator':
begin: '(?<!\\?)\\?(?!\\?|\\.|\\[)'
begin: '(?<!\\?)\\?(?!\\?|\\.(?!\\d)|\\[)'
beginCaptures:
'0':
name: 'keyword.operator.conditional.question-mark.apex'
Expand Down
2 changes: 1 addition & 1 deletion grammars/soql.tmLanguage
Original file line number Diff line number Diff line change
Expand Up @@ -3780,7 +3780,7 @@
<key>conditional-operator</key>
<dict>
<key>begin</key>
<string>(?&lt;!\?)\?(?!\?|\.|\[)</string>
<string>(?&lt;!\?)\?(?!\?|\.(?!\d)|\[)</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"watch": "tsc -w -p .",
"test:soql-tmgrammar": "vscode-tmgrammar-test -g \"./grammars/soql.tmLanguage\" \"./test/soql/*.soql\" ",
"test:soql-tmgrammar-snapshots": "vscode-tmgrammar-snap -s source.soql -g \"./grammars/soql.tmLanguage\" \"./test/soql/snapshots/*.soql\" ",
"test": "npm run compile && mocha out/test/**/*.tests.js && npm run test:soql-tmgrammar && npm run test:soql-tmgrammar-snapshots",
"test": "npm run compile && mocha out/test/**/*.test.js && npm run test:soql-tmgrammar && npm run test:soql-tmgrammar-snapshots",
"prepare": "npm run build",
"format": "prettier --config .prettierrc.json --write './**/*.{ts,js,json,md}'"
},
Expand Down Expand Up @@ -72,4 +72,4 @@
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}
}
3 changes: 2 additions & 1 deletion src/apex.tmLanguage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,8 @@ repository:
# Only match ? if:
# 1. There isn't a preceding or trailing ? (null-coalescing operator)
# 2. There isn't a trailing . or [ (null-conditional operator)
begin: (?<!\?)\?(?!\?|\.|\[)
# 3. UNLESS the trailing . is followed by a digit (decimal literal like ?.34)
begin: (?<!\?)\?(?!\?|\.(?!\d)|\[)
beginCaptures:
'0': { name: keyword.operator.conditional.question-mark.apex }
end: ':'
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
51 changes: 51 additions & 0 deletions test/expressions.tests.ts → test/expressions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,57 @@ Object newPoint = new Vector(point.x * z, 0);`);
Token.Punctuation.Semicolon,
]);
});

it('ternary with decimal literal without spaces (W-8095488)', async () => {
const input = Input.InMethod(`Decimal d = b?.34:0;`);
const tokens = await tokenize(input);

tokens.should.deep.equal([
Token.PrimitiveType.Decimal,
Token.Identifiers.LocalName('d'),
Token.Operators.Assignment,
Token.Variables.ReadWrite('b'),
Token.Operators.Conditional.QuestionMark,
Token.Literals.Numeric.Decimal('34'),
Token.Operators.Conditional.Colon,
Token.Literals.Numeric.Decimal('0'),
Token.Punctuation.Semicolon,
]);
});

it('ternary with decimal literal with leading digits (W-8095488)', async () => {
const input = Input.InMethod(`Decimal i = b?.123:0;`);
const tokens = await tokenize(input);

tokens.should.deep.equal([
Token.PrimitiveType.Decimal,
Token.Identifiers.LocalName('i'),
Token.Operators.Assignment,
Token.Variables.ReadWrite('b'),
Token.Operators.Conditional.QuestionMark,
Token.Literals.Numeric.Decimal('123'),
Token.Operators.Conditional.Colon,
Token.Literals.Numeric.Decimal('0'),
Token.Punctuation.Semicolon,
]);
});

it('ternary with decimal literal with spaces (W-8095488)', async () => {
const input = Input.InMethod(`Decimal d = b ? .34 : 0;`);
const tokens = await tokenize(input);

tokens.should.deep.equal([
Token.PrimitiveType.Decimal,
Token.Identifiers.LocalName('d'),
Token.Operators.Assignment,
Token.Variables.ReadWrite('b'),
Token.Operators.Conditional.QuestionMark,
Token.Literals.Numeric.Decimal('34'),
Token.Operators.Conditional.Colon,
Token.Literals.Numeric.Decimal('0'),
Token.Punctuation.Semicolon,
]);
});
});

describe('Element Access', () => {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* W-8095488: Ternary expression with decimals syntax highlighting
*
* When a ternary expression contains a decimal literal and spaces are excluded,
* the question mark may be incorrectly tokenized as a safe navigation operator
* instead of a ternary operator.
*/
public class TernaryWithDecimals_W8095488 {

// With spaces - should work correctly
public void ternaryWithSpaces() {
Boolean b = true;
Decimal d = b ? .34 : 0;
Decimal i = b?.123 : 0;
}

// Without spaces - potential tokenization issue
public void ternaryWithoutSpaces() {
Boolean b = true;
Decimal d = b?.34:0;
Decimal i = b?.123:0;
}

// Mixed scenarios
public void mixedScenarios() {
Boolean b = true;

// Space before question mark, no space after
Decimal d1 = b ?.34:0;

// No space before, space after
Decimal d2 = b? .34:0;

// Space after question mark, no space around colon
Decimal d3 = b? .34:0;

// All spaces
Decimal d4 = b ? .34 : 0;

// Integer values (for comparison)
Integer i1 = b?1:0;
Integer i2 = b ? 1 : 0;
}

// Safe navigation operator (for comparison)
public void safeNavigationOperator() {
String s = 'test';
Integer len = s?.length();

Account acc;
String name = acc?.Name;
}

// Complex expressions
public void complexExpressions() {
Boolean b = true;

// Ternary in switch
switch on (b) {
when true {
Decimal d = b?.34:0;
String s = 'SUCCESS';
}
}

// Nested ternary with decimals
Decimal nested = b ? (b?.5:.25) : .0;

// Ternary with decimal in variable declaration
Decimal inline = b?.99:0;
}

// Property access vs ternary
public void propertyVsTernary() {
Boolean b = true;

// These should be ternary operators, not safe navigation
Decimal d = b?.34:0;
Decimal i = b?.123:0;

// This is safe navigation
String type = this?.type;
}

String type = 'test';
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading