Skip to content

Commit 09a2cf6

Browse files
authored
Update Parser.hx
1 parent cb9fbb3 commit 09a2cf6

1 file changed

Lines changed: 229 additions & 92 deletions

File tree

hscript/Parser.hx

Lines changed: 229 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* DEALINGS IN THE SOFTWARE.
2121
*/
2222
package hscript;
23+
24+
import hscript.thx_semver.Version;
2325
import hscript.Expr;
2426

2527
using 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
25702707
final class PreprocValue {
25712708
public var r : Bool;
2572-
}
2709+
}

0 commit comments

Comments
 (0)