@@ -13,6 +13,40 @@ import { EdkSymbolInfLibrary } from '../symbols/infSymbols';
13
13
import { DiagnosticManager , EdkDiagnosticCodes } from '../diagnostics' ;
14
14
import { PathFind } from '../pathfind' ;
15
15
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
+
16
50
17
51
const dscSectionTypes = [ 'defines' , 'packages' , 'buildoptions' , 'skuids' , 'libraryclasses' , 'components' , 'userextensions' , 'defaultstores' , 'pcdsfeatureflag' , 'pcdsfixedatbuild' , 'pcdspatchableinmodule' , 'pcdsdynamicdefault' , 'pcdsdynamichii' , 'pcdsdynamicvpd' , 'pcdsdynamicexdefault' , 'pcdsdynamicexhii' , 'pcdsdynamicexvpd' ] ;
18
52
@@ -598,9 +632,14 @@ export class EdkWorkspace {
598
632
continue ;
599
633
}
600
634
635
+ if ( line . startsWith ( "!error " ) ) {
636
+ DiagnosticManager . error ( document . uri , lineIndex , EdkDiagnosticCodes . errorMessage , line . replace ( "!error " , "" ) ) ;
637
+ }
638
+
601
639
if ( isRangeActive ) {
602
640
isRangeActive = false ;
603
641
let lineIndexEnd = lineIndex - 1 ;
642
+ gDebugLog . debug ( `New grayout ${ document . fileName } -> unuseRangeStart: ${ unuseRangeStart } lineIndexEnd: ${ lineIndexEnd } ` ) ;
604
643
doucumentGrayoutRange . push ( new vscode . Range ( new vscode . Position ( unuseRangeStart , 0 ) , new vscode . Position ( lineIndexEnd , 0 ) ) ) ;
605
644
}
606
645
@@ -705,6 +744,13 @@ export class EdkWorkspace {
705
744
}
706
745
}
707
746
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
+
708
754
this . updateGrayoutRange ( document , doucumentGrayoutRange ) ;
709
755
}
710
756
@@ -939,13 +985,13 @@ export class EdkWorkspace {
939
985
this . conditionOpen . push ( { uri :documentUri , lineNo :lineIndex } ) ;
940
986
switch ( tokens [ 0 ] . toLowerCase ( ) ) {
941
987
case "!if" :
942
- conditionValue = this . evaluateConditional ( conditionStr . replaceAll ( UNDEFINED_VARIABLE , 'FALSE' ) , documentUri , lineIndex ) ;
988
+ conditionValue = this . evaluateConditional ( conditionStr , documentUri , lineIndex ) ;
943
989
break ;
944
990
case "!ifdef" :
945
- conditionValue = this . pushConditional ( ( tokens [ 1 ] !== UNDEFINED_VARIABLE ) ) ;
991
+ conditionValue = this . pushConditional ( this . defines . isDefined ( tokens [ 1 ] ) ) ;
946
992
break ;
947
993
case "!ifndef" :
948
- conditionValue = this . pushConditional ( ( tokens [ 1 ] === UNDEFINED_VARIABLE ) ) ;
994
+ conditionValue = this . pushConditional ( ! this . defines . isDefined ( tokens [ 1 ] ) ) ;
949
995
break ;
950
996
}
951
997
@@ -964,7 +1010,7 @@ export class EdkWorkspace {
964
1010
DiagnosticManager . error ( documentUri , lineIndex , EdkDiagnosticCodes . conditionalMissform , "!elseif without !if" ) ;
965
1011
return true ;
966
1012
}
967
- conditionValue = this . evaluateConditional ( conditionStr . replaceAll ( UNDEFINED_VARIABLE , 'FALSE' ) , documentUri , lineIndex ) ;
1013
+ conditionValue = this . evaluateConditional ( conditionStr , documentUri , lineIndex ) ;
968
1014
parentActive = this . conditionStack . length <= 1 || this . conditionStack [ this . conditionStack . length - 2 ] . active ;
969
1015
970
1016
// Update the top of the stack
@@ -1039,36 +1085,91 @@ export class EdkWorkspace {
1039
1085
this . conditionalStack . push ( v ) ;
1040
1086
return v ;
1041
1087
}
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
+ }
1042
1131
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
+ }
1044
1150
1045
- let data = text . replaceAll ( / " t r u e " / gi, "true" ) ; // replace booleans
1046
- data = data . replaceAll ( / " f a l s e " / gi, "false" ) ;
1047
- data = data . replaceAll ( / a n d / gi, " && " ) ;
1048
- data = data . replaceAll ( / o r / gi, " || " ) ;
1049
- data = data . replace ( / n o t / 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
+ }
1052
1154
1155
+ const retValue = ( stack [ 0 ] === UNDEFINED_VARIABLE ) ? false : stack [ 0 ] ;
1156
+ gDebugLog . debug ( `Evaluate expression: ${ originalExpression } -> ${ retValue } ` ) ;
1157
+ return retValue ;
1158
+ }
1053
1159
1054
- while ( data . match ( / " i n " / gi) ) {
1055
- let inIndex = data . search ( / " i n " / 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 {
1060
1161
1061
1162
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 } ` ) ;
1062
1166
1063
1167
let result = false ;
1064
1168
try {
1065
- if ( data . includes ( UNDEFINED_VARIABLE ) ) {
1066
- return false ;
1067
- }
1068
- result = eval ( data ) ;
1169
+ result = this . evaluateExpression ( data ) ;
1069
1170
} catch ( error ) {
1070
1171
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 } ` ) ;
1072
1173
1073
1174
return false ;
1074
1175
}
0 commit comments