diff --git a/Docs/src/defines.but b/Docs/src/defines.but index ba93a6ba..747d3bbe 100644 --- a/Docs/src/defines.but +++ b/Docs/src/defines.but @@ -31,7 +31,7 @@ Removes an item from the global define list. Note that $\{SYMBOL\} where SYMBOL \S1{ifdef} !ifdef -\c gflag [bcheck [gflag [...]]] +\c gflag [bcheck gflag [...]]] This command, when paired with an !endif command, will tell the compiler whether or not to compile the lines in between the two lines. If gflag is globally defined (using !define or the /D switch), then the contained lines will be compiled. Otherwise, they will be skipped. 'bcheck' can be specified as & (boolean and) or | (boolean or) along with more gflags -- precedence is simple, left to right. @@ -46,13 +46,29 @@ This command, when paired with an !endif command, will tell the compiler whether \S1{ifndef} !ifndef -\c gflag [bcheck [gflag [...]]] +\c gflag [bcheck gflag [...]]] The opposite of !ifdef. The lines will be compiled when the gflag has not been defined. +\S1{if} !if + +\c [!] value [op value2] + +This command, when paired with an !endif command, will tell the compiler whether or not to compile the lines in between the two lines. If value is non-zero, or the comparison of value and value2 depending on the operator results in true, the contained lines will be compiled. Otherwise, they will be skipped. +op can be either == or != (string comparison), <=, < > or >= (float comparison), && or || (boolean comparison). +If [!] is set, return value will be switched from true to false and vice versa. + +\c !if 1 < 2 +\c !echo "1 is smaller than 2!!" +\c !else if ! 3.1 > 1.99 +\c !error "this line should never appear" +\c !else +\c !error "neither should this" +\c !endif + \S1{ifmacrodef} !ifmacrodef -\c gflag [bcheck [gflag [...]]] +\c gflag [bcheck gflag [...]]] This command, when paired with an !endif command, will tell the compiler whether or not to compile the lines in between the two lines. If the macro gflag exists, then the contained lines will be compiled. Otherwise, they will be skipped. 'bcheck' can be specified as & (boolean and) or | (boolean or) along with more gflags -- precedence is simple, left to right. @@ -64,13 +80,13 @@ This command, when paired with an !endif command, will tell the compiler whether \S1{ifmacrondef} !ifmacrondef -\c gflag [bcheck [gflag [...]]] +\c gflag [bcheck gflag [...]]] The opposite of !ifmacrodef. The lines will be compiled when the macro gflag does not exist. \S1{else} !else -\c [ifdef|ifndef|ifmacrodef|ifmacrondef [...]] +\c [if|ifdef|ifndef|ifmacrodef|ifmacrondef [...]] This command allows to easily insert different code when different defines or macros are set. You can create blocks like !ifdef/!else/!endif, !ifdef/!else ifdef/!else/!endif etc. @@ -82,7 +98,7 @@ This command allows to easily insert different code when different defines or ma \S1{endif} !endif -This command closes a block started with !ifdef, !ifndef, !ifmacrodef or !ifmacrondef. +This command closes a block started with !if, !ifdef, !ifndef, !ifmacrodef or !ifmacrondef. \S1{insertmacro} !insertmacro diff --git a/Source/Tests/preprocessor.nsi b/Source/Tests/preprocessor.nsi index cfcc6ef1..d1fb0349 100644 --- a/Source/Tests/preprocessor.nsi +++ b/Source/Tests/preprocessor.nsi @@ -51,6 +51,40 @@ d\ i\ f +# tests for !if statement +!if 'test' == 'test' + !if 1 <= 2 + !if ! 100 < 99.99 + !if 2.2 > 1.12 + !if ! 23 >= 37 + !if 1 && 1 + !if ! 0 || 0 + + # this should be compiled + + !else + !error "!if ! 0 || 0 is true!" + !endif + !else + !error "!if 1 && 1 is true!" + !endif + !else + !error "!if ! 23 >= 37 is true!" + !endif + !else + !error "!if 2.2 > 1.12 is true!" + !endif + !else + !error "!if ! 100 < 99.99 is true!" + !endif + !else + !error "!if 1 <= 2 is true!" + !endif +!else + !error "!if 'test' == 'test' is true!" +!endif + + # this should just give a warning, not an error !include /NONFATAL file_that_doesnt_exist.nsh diff --git a/Source/script.cpp b/Source/script.cpp index 156c370f..a94343f2 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -353,9 +353,15 @@ parse_again: if (cur_ifblock && cur_ifblock->inherited_ignore) return PS_OK; - if (!num_ifblock() || cur_ifblock->elseused) + if (!num_ifblock()) { - ERROR_MSG("!else: stray !else\n"); + ERROR_MSG("!else: no if block open (!if[macro][n][def])\n"); + return PS_ERROR; + } + + if (cur_ifblock->elseused) + { + ERROR_MSG("!else: else already used in current if block\n"); return PS_ERROR; } @@ -376,16 +382,17 @@ parse_again: line.eattoken(); - int v=line.gettoken_enum(0,"ifdef\0ifndef\0ifmacrodef\0ifmacrondef\0"); + int v=line.gettoken_enum(0,"if\0ifdef\0ifndef\0ifmacrodef\0ifmacrondef\0"); if (v < 0) PRINTHELP() if (line.getnumtokens() == 1) PRINTHELP() - int cmds[] = {TOK_P_IFDEF, TOK_P_IFNDEF, TOK_P_IFMACRODEF, TOK_P_IFMACRONDEF}; + int cmds[] = {TOK_P_IF, TOK_P_IFDEF, TOK_P_IFNDEF, TOK_P_IFMACRODEF, TOK_P_IFMACRONDEF}; tkid = cmds[v]; if_from_else++; } if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF || - tkid == TOK_P_IFMACRODEF || tkid == TOK_P_IFMACRONDEF) + tkid == TOK_P_IFMACRODEF || tkid == TOK_P_IFMACRONDEF || + tkid == TOK_P_IF) { if (!if_from_else) start_ifblock(); @@ -398,29 +405,74 @@ parse_again: int istrue=0; int mod=0; - int p; - - // pure left to right precedence. Not too powerful, but useful. - for (p = 1; p < line.getnumtokens(); p ++) - { - if (p & 1) - { - int new_s; - if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF) - new_s=!!definedlist.find(line.gettoken_str(p)); - else - new_s=MacroExists(line.gettoken_str(p)); - if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFMACRONDEF) - new_s=!new_s; - - if (mod == 0) istrue = istrue || new_s; - else istrue = istrue && new_s; + + int p=0; + + if (tkid == TOK_P_IF) { + if(!strcmp(line.gettoken_str(1),"!")) { + p = 1; + line.eattoken(); } - else + + if(line.getnumtokens() == 2) + istrue = line.gettoken_int(1); + + else if (line.getnumtokens() == 4) { + mod = line.gettoken_enum(2,"=\0==\0!=\0<=\0<\0>\0>=\0&\0&&\0|\0||\0"); + + switch(mod) { + case 0: + case 1: + istrue = strcmp(line.gettoken_str(1),line.gettoken_str(3)) == 0; break; + case 2: + istrue = strcmp(line.gettoken_str(1),line.gettoken_str(3)) != 0; break; + case 3: + istrue = line.gettoken_float(1) <= line.gettoken_float(3); break; + case 4: + istrue = line.gettoken_float(1) < line.gettoken_float(3); break; + case 5: + istrue = line.gettoken_float(1) > line.gettoken_float(3); break; + case 6: + istrue = line.gettoken_float(1) >= line.gettoken_float(3); break; + case 7: + case 8: + istrue = line.gettoken_int(1) && line.gettoken_int(3); break; + case 9: + case 10: + istrue = line.gettoken_int(1) || line.gettoken_int(3); break; + default: + PRINTHELP() + } + } + else PRINTHELP() + + if(p) istrue = !istrue; + } + + else { + + // pure left to right precedence. Not too powerful, but useful. + for (p = 1; p < line.getnumtokens(); p ++) { - mod=line.gettoken_enum(p,"|\0&\0||\0&&\0"); - if (mod == -1) PRINTHELP() - mod &= 1; + if (p & 1) + { + int new_s; + if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF) + new_s=!!definedlist.find(line.gettoken_str(p)); + else + new_s=MacroExists(line.gettoken_str(p)); + if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFMACRONDEF) + new_s=!new_s; + + if (mod == 0) istrue = istrue || new_s; + else istrue = istrue && new_s; + } + else + { + mod=line.gettoken_enum(p,"|\0&\0||\0&&\0"); + if (mod == -1) PRINTHELP() + mod &= 1; + } } } @@ -437,7 +489,7 @@ parse_again: if (tkid == TOK_P_ENDIF) { if (!num_ifblock()) { - ERROR_MSG("!endif: no !ifdef open\n"); + ERROR_MSG("!endif: no if block open (!if[macro][n][def])\n"); return PS_ERROR; } end_ifblock(); diff --git a/Source/tokens.cpp b/Source/tokens.cpp index 00ce420b..d9805ce3 100644 --- a/Source/tokens.cpp +++ b/Source/tokens.cpp @@ -225,12 +225,13 @@ static tokenType tokenlist[TOK__LAST] = {TOK_P_ADDINCLUDEDIR,"!AddIncludeDir",1,0,"dir",TP_ALL}, {TOK_P_INCLUDE,"!include",1,1,"[/NONFATAL] filename.nsh",TP_ALL}, {TOK_P_CD,"!cd",1,0,"absolute_or_relative_new_directory",TP_ALL}, +{TOK_P_IF,"!if",1,3,"[!] value [(==,!=,<=,<,>,>=,&&,||) value2] [...]",TP_ALL}, {TOK_P_IFDEF,"!ifdef",1,-1,"symbol [| symbol2 [& symbol3 [...]]]",TP_ALL}, {TOK_P_IFNDEF,"!ifndef",1,-1,"symbol [| symbol2 [& symbol3 [...]]]",TP_ALL}, {TOK_P_ENDIF,"!endif",0,0,"",TP_ALL}, {TOK_P_DEFINE,"!define",1,2,"[/date] symbol [value]",TP_ALL}, {TOK_P_UNDEF,"!undef",1,1,"symbol [value]",TP_ALL}, -{TOK_P_ELSE,"!else",0,-1,"[ifdef|ifndef symbol [|symbol2 [& symbol3 [...]]]]",TP_ALL}, +{TOK_P_ELSE,"!else",0,-1,"[if[macro][n][def] ...]",TP_ALL}, {TOK_P_ECHO,"!echo",1,0,"message",TP_ALL}, {TOK_P_WARNING,"!warning",0,1,"[warning_message]",TP_ALL}, {TOK_P_ERROR,"!error",0,1,"[error_message]",TP_ALL}, diff --git a/Source/tokens.h b/Source/tokens.h index 26a8351e..e10f4c0a 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -71,6 +71,7 @@ enum TOK_FILEBUFSIZE, // system "preprocessor"ish tokens + TOK_P_IF, TOK_P_IFDEF, TOK_P_IFNDEF, TOK_P_ELSE,