Skip to content

Commit 6a4aabf

Browse files
committed
Enhance logging and conditional evaluation
- In src/debugLog.ts, changed the `debug` method to use `trace` for more detailed logging. - In src/diagnostics.ts, added a new diagnostic code `errorMessage` and its corresponding description. - In src/index/definitions.ts, added the method `isDefined` to check if a definition exists. Enhanced `replaceDefines` method to handle replacements for boolean and numeric values properly. - In src/index/edkWorkspace.ts, introduced operators for conditional evaluation and improved the handling of `!error` directives. Created a method `evaluateExpression` for better evaluation of conditions and added extensive debug logging for range and conditional evaluations.
1 parent 90462b8 commit 6a4aabf

File tree

4 files changed

+144
-25
lines changed

4 files changed

+144
-25
lines changed

src/debugLog.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class DebugLog {
4545
}
4646

4747
public debug(text:string){
48-
this.outConsole.debug(text);
48+
this.outConsole.trace(text);
4949
}
5050

5151

src/diagnostics.ts

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ emptyFile,
2929
circularDependency,
3030
inactiveCode,
3131
edk2CodeUnsuported,
32+
errorMessage
3233
}
3334

3435
export const edkErrorDescriptions: Map<EdkDiagnosticCodes, string> = new Map([
@@ -58,6 +59,7 @@ export const edkErrorDescriptions: Map<EdkDiagnosticCodes, string> = new Map([
5859
[EdkDiagnosticCodes.circularDependency, "Circular dependency"],
5960
[EdkDiagnosticCodes.inactiveCode, "Inactive code"],
6061
[EdkDiagnosticCodes.edk2CodeUnsuported, "Edk2Code unsupported"],
62+
[EdkDiagnosticCodes.errorMessage, "Error message"],
6163
]);
6264

6365
export class DiagnosticManager {

src/index/definitions.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ export class WorkspaceDefinitions {
6666
this.defines = new Map();
6767
}
6868

69+
isDefined(text:string){
70+
return this.defines.has(text);
71+
}
72+
6973
replaceDefines(text: string) {
7074
let replaced = false;
7175
let maxIterations = 10;
@@ -82,7 +86,19 @@ export class WorkspaceDefinitions {
8286
for (const [key,value] of this.defines.entries()) {
8387
if(text.includes(`$(${key})`)){
8488
replaced = true;
85-
text = text.replaceAll(`$(${key})`, value.value);
89+
let replacement;
90+
if(value.value.toLowerCase() === "true"){
91+
replacement = "TRUE";
92+
}else if(value.value.toLowerCase() === "false"){
93+
replacement = "FALSE";
94+
}else if(isNaN(parseInt(value.value))){
95+
replacement = `"${value.value}"`;
96+
}else{
97+
replacement = value.value;
98+
}
99+
100+
101+
text = text.replaceAll(`$(${key})`, replacement);
86102
}
87103
}
88104

src/index/edkWorkspace.ts

+124-23
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,40 @@ import { EdkSymbolInfLibrary } from '../symbols/infSymbols';
1313
import { DiagnosticManager, EdkDiagnosticCodes } from '../diagnostics';
1414
import { PathFind } from '../pathfind';
1515

16+
const OPERATORS = {
17+
'or': { precedence: 1, fn: (x: boolean, y: boolean) => x || y },
18+
'OR': { precedence: 1, fn: (x: boolean, y: boolean) => x || y },
19+
'||': { precedence: 1, fn: (x: boolean, y: boolean) => x || y },
20+
'and': { precedence: 2, fn: (x: boolean, y: boolean) => x && y },
21+
'AND': { precedence: 2, fn: (x: boolean, y: boolean) => x && y },
22+
'&&': { precedence: 2, fn: (x: boolean, y: boolean) => x && y },
23+
'|': { precedence: 3, fn: (x: number, y: number) => x | y },
24+
'^': { precedence: 4, fn: (x: number, y: number) => x ^ y },
25+
'&': { precedence: 5, fn: (x: number, y: number) => x & y },
26+
'==': { precedence: 6, fn: (x: any, y: any) => (x===UNDEFINED_VARIABLE||y===UNDEFINED_VARIABLE)?false:x === y },
27+
'!=': { precedence: 6, fn: (x: any, y: any) => (x===UNDEFINED_VARIABLE||y===UNDEFINED_VARIABLE)?false:x !== y },
28+
'EQ': { precedence: 6, fn: (x: any, y: any) => (x===UNDEFINED_VARIABLE||y===UNDEFINED_VARIABLE)?false:x === y },
29+
'NE': { precedence: 6, fn: (x: any, y: any) => (x===UNDEFINED_VARIABLE||y===UNDEFINED_VARIABLE)?false:x !== y },
30+
'<=': { precedence: 7, fn: (x: number, y: number) => x <= y },
31+
'>=': { precedence: 7, fn: (x: number, y: number) => x >= y },
32+
'<': { precedence: 7, fn: (x: number, y: number) => x < y },
33+
'>': { precedence: 7, fn: (x: number, y: number) => x > y },
34+
'+': { precedence: 8, fn: (x: number, y: number) => x + y },
35+
'-': { precedence: 8, fn: (x: number, y: number) => x - y },
36+
'*': { precedence: 9, fn: (x: number, y: number) => x * y },
37+
'/': { precedence: 9, fn: (x: number, y: number) => x / y },
38+
'%': { precedence: 9, fn: (x: number, y: number) => x % y },
39+
'!': { precedence: 10, fn: (y:any, x: boolean) => !x },
40+
'not': { precedence: 10, fn: (y:any, x: boolean) => !x },
41+
'NOT': { precedence: 10, fn: (y:any, x: boolean) => !x },
42+
'~': { precedence: 10, fn: (y:any, x: number) => ~x },
43+
'<<': { precedence: 11, fn: (x: number, y: number) => x << y },
44+
'>>': { precedence: 11, fn: (x: number, y: number) => x >> y },
45+
'in': { precedence: 12, fn: (x: string, y: string) => (x===UNDEFINED_VARIABLE||y===UNDEFINED_VARIABLE)?false:x.includes(y) },
46+
'IN': { precedence: 12, fn: (x: string, y: string) => (x===UNDEFINED_VARIABLE||y===UNDEFINED_VARIABLE)?false:x.includes(y) },
47+
};
48+
49+
1650

1751
const dscSectionTypes = ['defines','packages','buildoptions','skuids','libraryclasses','components','userextensions','defaultstores','pcdsfeatureflag','pcdsfixedatbuild','pcdspatchableinmodule','pcdsdynamicdefault','pcdsdynamichii','pcdsdynamicvpd','pcdsdynamicexdefault','pcdsdynamicexhii','pcdsdynamicexvpd'];
1852

@@ -598,9 +632,14 @@ export class EdkWorkspace {
598632
continue;
599633
}
600634

635+
if(line.startsWith("!error ")){
636+
DiagnosticManager.error(document.uri, lineIndex, EdkDiagnosticCodes.errorMessage, line.replace("!error ",""));
637+
}
638+
601639
if (isRangeActive) {
602640
isRangeActive = false;
603641
let lineIndexEnd = lineIndex - 1;
642+
gDebugLog.debug(`New grayout ${document.fileName} -> unuseRangeStart: ${unuseRangeStart} lineIndexEnd: ${lineIndexEnd}`);
604643
doucumentGrayoutRange.push(new vscode.Range(new vscode.Position(unuseRangeStart, 0), new vscode.Position(lineIndexEnd, 0)));
605644
}
606645

@@ -705,6 +744,13 @@ export class EdkWorkspace {
705744
}
706745
}
707746

747+
if (isRangeActive) {
748+
isRangeActive = false;
749+
let lineIndexEnd = lineIndex - 1;
750+
gDebugLog.debug(`New grayout ${document.fileName} -> unuseRangeStart: ${unuseRangeStart} lineIndexEnd: ${lineIndexEnd}`);
751+
doucumentGrayoutRange.push(new vscode.Range(new vscode.Position(unuseRangeStart, 0), new vscode.Position(lineIndexEnd, 0)));
752+
}
753+
708754
this.updateGrayoutRange(document, doucumentGrayoutRange);
709755
}
710756

@@ -939,13 +985,13 @@ export class EdkWorkspace {
939985
this.conditionOpen.push({uri:documentUri, lineNo:lineIndex});
940986
switch(tokens[0].toLowerCase()){
941987
case "!if":
942-
conditionValue = this.evaluateConditional(conditionStr.replaceAll(UNDEFINED_VARIABLE,'FALSE'), documentUri, lineIndex);
988+
conditionValue = this.evaluateConditional(conditionStr, documentUri, lineIndex);
943989
break;
944990
case "!ifdef":
945-
conditionValue = this.pushConditional((tokens[1] !== UNDEFINED_VARIABLE));
991+
conditionValue = this.pushConditional(this.defines.isDefined(tokens[1]));
946992
break;
947993
case "!ifndef":
948-
conditionValue = this.pushConditional((tokens[1] === UNDEFINED_VARIABLE));
994+
conditionValue = this.pushConditional(!this.defines.isDefined(tokens[1]));
949995
break;
950996
}
951997

@@ -964,7 +1010,7 @@ export class EdkWorkspace {
9641010
DiagnosticManager.error(documentUri, lineIndex, EdkDiagnosticCodes.conditionalMissform, "!elseif without !if");
9651011
return true;
9661012
}
967-
conditionValue = this.evaluateConditional(conditionStr.replaceAll(UNDEFINED_VARIABLE,'FALSE'), documentUri, lineIndex);
1013+
conditionValue = this.evaluateConditional(conditionStr, documentUri, lineIndex);
9681014
parentActive = this.conditionStack.length <= 1 || this.conditionStack[this.conditionStack.length - 2].active;
9691015

9701016
// Update the top of the stack
@@ -1039,36 +1085,91 @@ export class EdkWorkspace {
10391085
this.conditionalStack.push(v);
10401086
return v;
10411087
}
1088+
1089+
evaluateExpression(expression: string): any {
1090+
const originalExpression = expression;
1091+
if(expression.includes(UNDEFINED_VARIABLE)){
1092+
gDebugLog.debug(`Evaluate expression: ${expression} -> ${false}`);
1093+
return false;
1094+
}
1095+
// add space to parenteses
1096+
expression = expression.replaceAll(/\(/g, " ( ");
1097+
expression = expression.replaceAll(/\)/g, " ) ");
1098+
expression = expression.replaceAll(/\s+/g, " ");
1099+
1100+
1101+
let tokens = expression.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
1102+
let outputQueue = [];
1103+
let operatorStack: string[] = [];
1104+
let parentesisBalance = 0;
1105+
for (const token of tokens) {
1106+
if (!isNaN(Number(token))) {
1107+
outputQueue.push(Number(token));
1108+
} else if (token.toLowerCase() === 'true' || token.toLowerCase() === 'false') {
1109+
outputQueue.push(token.toLowerCase() === 'true');
1110+
} else if(token.trim().startsWith('"') && token.trim().endsWith('"')){
1111+
outputQueue.push(token.trim().slice(1,-1));
1112+
} else if (token in OPERATORS) {
1113+
while (operatorStack.length && operatorStack[operatorStack.length - 1] in OPERATORS &&
1114+
OPERATORS[token as keyof typeof OPERATORS].precedence <= OPERATORS[operatorStack[operatorStack.length - 1] as keyof typeof OPERATORS].precedence) {
1115+
outputQueue.push(operatorStack.pop());
1116+
}
1117+
operatorStack.push(token);
1118+
} else if (token === '(') {
1119+
parentesisBalance++;
1120+
operatorStack.push(token);
1121+
} else if (token === ')') {
1122+
parentesisBalance--;
1123+
while (operatorStack.length && operatorStack[operatorStack.length - 1] !== '(') {
1124+
outputQueue.push(operatorStack.pop());
1125+
}
1126+
operatorStack.pop();
1127+
} else{
1128+
throw new Error(`Error evaluating expression: ${originalExpression} - bad Operand ${token}`);
1129+
}
1130+
}
10421131

1043-
private evaluateConditional(text: string, documentUri:vscode.Uri, lineNo:number): any {
1132+
if(parentesisBalance !== 0){
1133+
throw new Error(`Error evaluating expression: ${originalExpression} - Parenthesis balance error`);
1134+
}
1135+
1136+
while (operatorStack.length) {
1137+
outputQueue.push(operatorStack.pop());
1138+
}
1139+
1140+
let stack: any[] = [];
1141+
for (const token of outputQueue) {
1142+
if (token! as keyof typeof OPERATORS in OPERATORS) {
1143+
let y = stack.pop() as never;
1144+
let x = stack.pop() as never;
1145+
stack.push(OPERATORS[token! as keyof typeof OPERATORS].fn(x, y));
1146+
}else{
1147+
stack.push(token);
1148+
}
1149+
}
10441150

1045-
let data = text.replaceAll(/"true"/gi, "true"); // replace booleans
1046-
data = data.replaceAll(/"false"/gi, "false");
1047-
data = data.replaceAll(/ and /gi, " && ");
1048-
data = data.replaceAll(/ or /gi, " || ");
1049-
data = data.replace(/ not /gi, " ! ");
1050-
data = data.replaceAll(/(?<![\!"])\b(\w+)\b(?!")/gi, '"$1"'); // convert words to string
1051-
data = data.replace(/^\!\w+/gi, ""); // remove conditional keyword
1151+
if(stack.length > 1){
1152+
throw new Error(`Error evaluating expression: ${originalExpression}`);
1153+
}
10521154

1155+
const retValue = (stack[0]===UNDEFINED_VARIABLE)? false : stack[0];
1156+
gDebugLog.debug(`Evaluate expression: ${originalExpression} -> ${retValue}`);
1157+
return retValue;
1158+
}
10531159

1054-
while (data.match(/"in"/gi)) {
1055-
let inIndex = data.search(/"in"/i);
1056-
let last = data.slice(inIndex + '"in"'.length).replace(/("\w+")/i, '$1)').trim();
1057-
let beging = data.slice(0, inIndex).trim();
1058-
data = beging + ".includes(" + last;
1059-
}
1160+
private evaluateConditional(text: string, documentUri:vscode.Uri, lineNo:number): any {
10601161

10611162

1163+
// let data = text.replaceAll(/(?<![\!"])\b(\w+)\b(?!")/gi, '"$1"'); // convert words to string
1164+
let data = text.replace(/^\!\w+/gi, ""); // remove conditional keyword
1165+
gDebugLog.debug(`Evaluate conditional ${documentUri.fsPath}:${lineNo + 1} - ${text}`);
10621166

10631167
let result = false;
10641168
try {
1065-
if(data.includes(UNDEFINED_VARIABLE)){
1066-
return false;
1067-
}
1068-
result = eval(data);
1169+
result = this.evaluateExpression(data);
10691170
} catch (error) {
10701171
gDebugLog.warning(`Evaluate conditional ${documentUri.fsPath}:${lineNo + 1} - ${(error as Error).message} - ${text}`);
1071-
DiagnosticManager.hint(documentUri,lineNo,EdkDiagnosticCodes.edk2CodeUnsuported,`Edk2Code extension doesnt support this condition. Expression is not evaluated: ${text}` );
1172+
DiagnosticManager.error(documentUri,lineNo,EdkDiagnosticCodes.edk2CodeUnsuported,`${(error as Error).message}` );
10721173

10731174
return false;
10741175
}

0 commit comments

Comments
 (0)