2020 * DEALINGS IN THE SOFTWARE.
2121 */
2222package hscript ;
23+
24+ import hscript .thx_semver .Version ;
2325import hscript .Expr ;
2426
2527using StringTools ;
@@ -68,6 +70,11 @@ class Parser {
6870 **/
6971 public var preprocessorValues : Map <String ,Dynamic > = new Map ();
7072
73+ /**
74+ defines preprocessor variables that will be considered false
75+ **/
76+ public var invalidPreprocessValues : Array <Dynamic > = [" null" , null , " 0" , 0 , " false" , false ];
77+
7178 /**
7279 activate JSON compatiblity
7380 **/
@@ -207,6 +214,10 @@ class Parser {
207214 push (tk );
208215 parseFullExpr (a );
209216 }
217+ if (preprocStack .length > 0 )
218+ {
219+ error (EInvalidPreprocessor (" Unclosed" ), tokenMin , tokenMax );
220+ }
210221 return if ( a .length == 1 ) a [0 ] else mk (EBlock (a ),0 );
211222 }
212223
@@ -1771,6 +1782,10 @@ class Parser {
17711782 push (tk );
17721783 decls .push (parseModuleDecl ());
17731784 }
1785+ if (preprocStack .length > 0 )
1786+ {
1787+ error (EInvalidPreprocessor (" Unclosed" ), tokenMin , tokenMax );
1788+ }
17741789 return decls ;
17751790 }
17761791
@@ -2379,91 +2394,213 @@ class Parser {
23792394
23802395 function parsePreproCond (): Expr {
23812396 var tk = token ();
2382- return switch ( tk ) {
2383- case TPOpen :
2384- push (TPOpen );
2385- parseExpr ();
2386- case TId (id ):
2387- while (true ) {
2388- var tk = token ();
2389- if (tk == TDot ) {
2390- id + = " ." ;
2397+ switch ( tk ) {
2398+ case TPOpen :
2399+ push (TPOpen );
2400+ return parseExpr ();
2401+ case TId (id ):
2402+ var tk ;
2403+ while (true ) {
23912404 tk = token ();
2392- switch (tk ) {
2393- case TId (id2 ):
2394- id + = id2 ;
2395- default : unexpected (tk );
2405+ if (tk == TDot ) {
2406+ id + = " ." ;
2407+ tk = token ();
2408+ switch (tk ) {
2409+ case TId (id2 ):
2410+ id + = id2 ;
2411+ default : unexpected (tk );
2412+ }
2413+ } else {
2414+ push (tk );
2415+ break ;
23962416 }
2397- } else {
2398- push (tk );
2399- break ;
24002417 }
2401- }
2402- mk (EIdent (id ), tokenMin , tokenMax );
2403- case TOp (" !" ):
2404- mk (EUnop (" !" , true , parsePreproCond ()), tokenMin , tokenMax );
2405- default :
2406- unexpected (tk );
2418+ return mk (EIdent (id ), tokenMin , tokenMax );
2419+ case TConst (c ):
2420+ return mk (EConst (c ), tokenMin , tokenMax );
2421+ case TOp (" !" ):
2422+ return mk (EUnop (" !" , true , parsePreproCond ()), tokenMin , tokenMax );
2423+ default :
2424+ return unexpected (tk );
24072425 }
24082426 }
24092427
2410- function evalPreproCond ( e : Expr ): Bool {
2411- switch ( expr (e ) ) {
2412- case EIdent (id ):
2413- return preprocValue (id ) != null ;
2414- case EField (e2 , f ):
2415- switch (expr (e2 )) {
2416- case EIdent (id ):
2417- return preprocValue (id + " ." + f ) != null ;
2418- default :
2419- error (EInvalidPreprocessor (" Can't eval " + expr (e ).getName () + " with " + expr (e2 ).getName ()), readPos , readPos );
2420- return false ;
2421- }
2422- case EUnop (" !" , _ , e ):
2423- return ! evalPreproCond (e );
2424- case EParent (e ):
2425- return evalPreproCond (e );
2426- case EBinop (" &&" , e1 , e2 ):
2427- return evalPreproCond (e1 ) && evalPreproCond (e2 );
2428- case EBinop (" ||" , e1 , e2 ):
2429- return evalPreproCond (e1 ) || evalPreproCond (e2 );
2430- default :
2431- error (EInvalidPreprocessor (" Can't eval " + expr (e ).getName ()), readPos , readPos );
2432- return false ;
2428+ function getValFromPreproExpr ( e : Expr ) : Dynamic
2429+ {
2430+ var edef : ExprDef = expr (e );
2431+ switch ( edef )
2432+ {
2433+ case EParent (e ):
2434+ return getValFromPreproExpr (e );
2435+ case EIdent (id ):
2436+ return preprocValue (id );
2437+ case EConst (c ):
2438+ return switch (c ) {
2439+ case CInt (v ): v ;
2440+ case CFloat (f ): f ;
2441+ case CString (s ): s ;
2442+ }
2443+ case ECall (expr (_ ) => EIdent (" version" ), expr (_ [0 ]) => EConst (CString (s ))):
2444+ try
2445+ {
2446+ (s : Version );
2447+ }
2448+ catch (_ )
2449+ {
2450+ error (EInvalidPreprocessor (' Invalid version string $s . Should follow SemVer.' ), readPos , readPos );
2451+ }
2452+ return s ;
2453+
2454+ default :
2455+ error (EInvalidPreprocessor (edef .getName ()), readPos , readPos );
2456+ return null ;
24332457 }
24342458 }
24352459
2460+ function evalPreproCond ( e : Expr ): Bool {
2461+ var edef : ExprDef = expr (e );
2462+ switch ( edef ) {
2463+ case EConst (c ):
2464+ return ! invalidPreprocessValues .contains (switch (c ) {
2465+ case CInt (v ): v ;
2466+ case CFloat (f ): f ;
2467+ case CString (s ): s ;
2468+ });
2469+ case EIdent (id ):
2470+ return ! invalidPreprocessValues .contains (preprocValue (id ));
2471+ case EField (e1 , f1 ):
2472+ switch (expr (e1 )) {
2473+ case EIdent (id ):
2474+ return ! invalidPreprocessValues .contains (preprocValue (' $id . $f1 ' ));
2475+ case edef2 :
2476+ error (EInvalidPreprocessor (" Can't eval " + edef .getName () + " with " + edef2 .getName ()), readPos , readPos );
2477+ return false ;
2478+ }
2479+ case EUnop (" !" , _ , e ):
2480+ return ! evalPreproCond (e );
2481+ case EParent (e ):
2482+ return evalPreproCond (e );
2483+ case EBinop (op , e1 , e2 ):
2484+ switch (op )
2485+ {
2486+ case " &&" :
2487+ return evalPreproCond (e1 ) && evalPreproCond (e2 );
2488+ case " ||" :
2489+ return evalPreproCond (e1 ) || evalPreproCond (e2 );
2490+ case op :
2491+ var e1 : Dynamic = getValFromPreproExpr (e1 );
2492+ var e2 : Dynamic = getValFromPreproExpr (e2 );
2493+ try {
2494+ var vers1 : Version = Std .string (e1 );
2495+ var vers2 : Version = Std .string (e2 );
2496+ switch (op ) {
2497+ case " ==" :
2498+ return vers1 == vers2 ;
2499+ case " !=" :
2500+ return vers1 != vers2 ;
2501+ case " >=" :
2502+ return vers1 >= vers2 ;
2503+ case " >" :
2504+ return vers1 > vers2 ;
2505+ case " <=" :
2506+ return vers1 <= vers2 ;
2507+ case " <" :
2508+ return vers1 < vers2 ;
2509+ default :
2510+ throw null ;
2511+ }
2512+ } catch (e : String ) { // doesn't capture SemVer error
2513+ } catch (e ) {
2514+ error (EInvalidPreprocessor (' Invalid operator \' $op \' for SemVer' ), readPos , readPos );
2515+ return false ;
2516+ }
2517+ try {
2518+ switch (op ) {
2519+ case " ==" :
2520+ return e1 == e2 ;
2521+ case " !=" :
2522+ return e1 != e2 ;
2523+ case " >=" :
2524+ return e1 >= e2 ;
2525+ case " >" :
2526+ return e1 > e2 ;
2527+ case " <=" :
2528+ return e1 <= e2 ;
2529+ case " <" :
2530+ return e1 < e2 ;
2531+ default :
2532+ }
2533+ } catch (_ ) {
2534+ error (EInvalidPreprocessor (' Invalid operator \' $op \' ' ), readPos , readPos );
2535+ return false ;
2536+ }
2537+ error (EInvalidPreprocessor (' Uncorrected operator \' $op \' ' ), readPos , readPos );
2538+ return false ;
2539+ }
2540+ default :
2541+ error (EInvalidPreprocessor (" Can't eval " + edef .getName ()), readPos , readPos );
2542+ return false ;
2543+ }
2544+ }
2545+
2546+ var _inIfPrepocess : Bool = false ;
24362547 function preprocess ( id : String ) : Token {
2437- switch ( id ) {
2438- case " if" :
2439- var e = parsePreproCond ();
2440- if ( evalPreproCond (e ) ) {
2441- preprocStack .push ({r : true });
2442- return token ();
2548+ inline function returnToken () {
2549+ return switch (token ()) {
2550+ case TPrepro (id = " if" | " else" | " elseif" | " end" | " error" ):
2551+ preprocess (id );
2552+ case t : t ;
24432553 }
2444- preprocStack .push ({r : false });
2445- skipTokens ();
2446- return token ();
2447- case " else" , " elseif" if ( preprocStack .length > 0 ):
2448- if ( preprocStack [preprocStack .length - 1 ].r ) {
2449- preprocStack [preprocStack .length - 1 ].r = false ;
2450- skipTokens ();
2451- return token ();
2452- } else if ( id == " else" ) {
2453- preprocStack .pop ();
2454- preprocStack .push ({r : true });
2455- return token ();
2456- } else {
2457- // elseif
2458- preprocStack .pop ();
2459- return preprocess (" if" );
2554+ }
2555+ if ( ! _inIfPrepocess ) {
2556+ switch ( id ) {
2557+ case " if" :
2558+ _inIfPrepocess = true ;
2559+ var result = evalPreproCond (parsePreproCond ());
2560+ _inIfPrepocess = false ;
2561+ preprocStack .push ({ r : result });
2562+ if (! result ) {
2563+ skipTokens ();
2564+ }
2565+ return returnToken ();
2566+ case " else" , " elseif" :
2567+ if ( preprocStack .length > 0 ) {
2568+ var last = preprocStack [preprocStack .length - 1 ];
2569+ if ( last .r ) {
2570+ skipTokens ();
2571+ last .r = false ;
2572+ return returnToken ();
2573+ } else if ( id == " else" ) {
2574+ preprocStack .pop ();
2575+ preprocStack .push ({ r : true });
2576+ return returnToken ();
2577+ } else {
2578+ // elseif
2579+ preprocStack .pop ();
2580+ return preprocess (" if" );
2581+ }
2582+ }
2583+ else
2584+ {
2585+ return unexpected (TPrepro (id ));
2586+ }
2587+ case " end" :
2588+ if ( preprocStack .length > 0 )
2589+ {
2590+ preprocStack .pop ();
2591+ return returnToken ();
2592+ }
2593+ else
2594+ {
2595+ return unexpected (TPrepro (id ));
2596+ }
2597+ case " error" if ( preprocStack .length == 0 || preprocStack [preprocStack .length - 1 ].r ):
2598+ var tokenMin = tokenMin ;
2599+ error (ECustom (Std .string (getValFromPreproExpr (parsePreproCond ()))), tokenMin ,tokenMax );
2600+ return returnToken ();
24602601 }
2461- case " end" if ( preprocStack .length > 0 ):
2462- preprocStack .pop ();
2463- return token ();
2464- default :
2465- return TPrepro (id );
24662602 }
2603+ return TPrepro (id );
24672604 }
24682605
24692606 function skipTokens (): Void {
@@ -2539,25 +2676,25 @@ class Parser {
25392676
25402677 function tokenString ( t : Token ): String {
25412678 return switch ( t ) {
2542- case TEof : " <eof>" ;
2543- case TConst (c ): constString (c );
2544- case TId (s ): s ;
2545- case TOp (s ): s ;
2546- case TPOpen : " (" ;
2547- case TPClose : " )" ;
2548- case TBrOpen : " {" ;
2549- case TBrClose : " }" ;
2550- case TDot : " ." ;
2551- case TQuestionDot : " ?." ;
2552- case TComma : " ," ;
2553- case TSemicolon : " ;" ;
2554- case TBkOpen : " [" ;
2555- case TBkClose : " ]" ;
2556- case TQuestion : " ?" ;
2557- case TDoubleDot : " :" ;
2558- case TMeta (id ): " @" + id ;
2559- case TPrepro (id ): " #" + id ;
2560- case TRegex (e , f ): ' ~/ $e / $f ' ;
2679+ case TEof : " <eof>" ;
2680+ case TConst (c ): constString (c );
2681+ case TId (s ): s ;
2682+ case TOp (s ): s ;
2683+ case TPOpen : " (" ;
2684+ case TPClose : " )" ;
2685+ case TBrOpen : " {" ;
2686+ case TBrClose : " }" ;
2687+ case TDot : " ." ;
2688+ case TQuestionDot : " ?." ;
2689+ case TComma : " ," ;
2690+ case TSemicolon : " ;" ;
2691+ case TBkOpen : " [" ;
2692+ case TBkClose : " ]" ;
2693+ case TQuestion : " ?" ;
2694+ case TDoubleDot : " :" ;
2695+ case TMeta (id ): " @" + id ;
2696+ case TPrepro (id ): " #" + id ;
2697+ case TRegex (e , f ): ' ~/ $e / $f ' ;
25612698 }
25622699 }
25632700
@@ -2569,4 +2706,4 @@ class Parser {
25692706@:structInit
25702707final class PreprocValue {
25712708 public var r : Bool ;
2572- }
2709+ }
0 commit comments