From 99bd64cd1130d92cb151fa81faa0616f09a3638d Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 18 May 2015 21:54:31 -0500 Subject: [PATCH] Fix incorrect check expression eval. It turns out the expression eval was just not implemented and only really worked for the require checks as those are ok with duplicate properties. Now full and/or expression parsing an evaluation is implemented. --- check/predef.jam | 146 ++++++++++++++++++++++++++++++++++++------- test/build.jam | 3 +- test/check_value.cpp | 26 ++++++++ 3 files changed, 151 insertions(+), 24 deletions(-) create mode 100644 test/check_value.cpp diff --git a/check/predef.jam b/check/predef.jam index 0638703..795c333 100644 --- a/check/predef.jam +++ b/check/predef.jam @@ -13,6 +13,7 @@ import string ; import toolset ; import modules ; import path ; +import "class" : new ; # Create a project for our targets. project.extension predef check ; @@ -54,35 +55,42 @@ rule check ( expressions + : language ? : true-properties * : false-properties * local project_target = [ project.target $(__name__) ] ; project.push-current $(project_target) ; + local terms ; local result ; for expression in $(expressions) { - # The check program to use. - local exe_target = [ $(_check_exe_($(language))).name ] ; - exe_target = /check/predef//$(exe_target) ; - - # Create the check run if we don't have one yet. - local key = [ MD5 $(language)::$(expression) ] ; - if ! ( $(key) in $(_checks_) ) + if $(expression:L) in "and" "or" { - _checks_ += $(key) ; - make - $(key).txt : - $(exe_target) : - @$(__name__).predef_check_action : - $(expression) ; - explicit - $(key).txt ; + terms += $(expression:L) ; + } + else + { + # The check program to use. + local exe_target = [ $(_check_exe_($(language))).name ] ; + exe_target = /check/predef//$(exe_target) ; + + # Create the check run if we don't have one yet. + local key = [ MD5 $(language)::$(expression) ] ; + if ! ( $(key) in $(_checks_) ) + { + _checks_ += $(key) ; + _message_(/check/predef//$(key).txt) = $(expression) ; + make + $(key).txt : + $(exe_target) : + @$(__name__).predef_check_action : + $(expression) ; + explicit + $(key).txt ; + } + + terms += /check/predef//$(key).txt ; } - - local check_target = [ check-target-builds - /check/predef//$(key).txt $(expression) - : $(true-properties) - : $(false-properties) ] ; - - result += $(check_target) ; } - project.pop-current ; + local instance = [ new check-expression-evaluator + $(terms) : $(true-properties) : $(false-properties) ] ; + result = @$(instance).check ; + project.pop-current ; return $(result) ; } @@ -104,3 +112,95 @@ actions predef_check_action bind PREDEF_CHECK_EXPRESSION { $(>) "$(PREDEF_CHECK_EXPRESSION)" > $(<) } + +class check-expression-evaluator +{ + import configure ; + + rule __init__ ( expression + : true-properties * : false-properties * ) + { + self.expression = $(expression) ; + self.true-properties = $(true-properties) ; + self.false-properties = $(false-properties) ; + } + + rule check ( properties * ) + { + local to-eval ; + local tokens = "and" "or" ; + # Go through the expression and: eval the target values, + # and normalize to a full expression. + for local term in $(self.expression) + { + if ! ( $(term:L) in $(tokens) ) + { + # A value is a target reference that will evan to "true" + # or "false". + if $(to-eval[-1]:L) && ! ( $(to-eval[-1]:L) in $(tokens) ) + { + # Default to "and" operation. + to-eval += "and" ; + } + local message = [ modules.peek predef : _message_($(term)) ] ; + if [ configure.builds $(term) : $(properties) : $(message) ] + { + to-eval += "true" ; + } + else + { + to-eval += "false" ; + } + } + else + { + to-eval += $(term) ; + } + } + # Eval full the expression. + local eval-result = [ eval $(to-eval) ] ; + # And resolve true/false properties. + if $(eval-result) = "true" + { + return $(self.true-properties) ; + } + else + { + return $(self.false-properties) ; + } + } + + rule eval ( e * ) + { + local r ; + if $(e[1]) && $(e[2]) && $(e[3]) + { + if $(e[2]) = "and" + { + if $(e[1]) = "true" && $(e[3]) = "true" + { + r = [ eval "true" $(e[4-]) ] ; + } + else + { + r = [ eval "false" $(e[4-]) ] ; + } + } + else if $(e[2]) = "or" + { + if $(e[1]) = "true" || $(e[3]) = "true" + { + r = [ eval "true" $(e[4-]) ] ; + } + else + { + r = [ eval "false" $(e[4-]) ] ; + } + } + } + else + { + r = $(e[1]) ; + } + return $(r) ; + } +} diff --git a/test/build.jam b/test/build.jam index 28e1473..b760f90 100755 --- a/test/build.jam +++ b/test/build.jam @@ -4,7 +4,7 @@ # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -import ../check/predef : require : predef-require ; +import ../check/predef : require check : predef-require predef-check ; local predef-include-root ; local predef-dependency ; @@ -57,4 +57,5 @@ test-suite predef : [ run make.cpp ] [ compile macos_endian.c : [ predef-require "BOOST_OS_MACOS" : cpp ] ] [ compile macos_vs_bsd.c : [ predef-require "BOOST_OS_MACOS" : cpp ] ] + #[ run check_value.cpp : : : [ predef-check "BOOST_COMP_CLANG >= 4.0" "BOOST_OS_MACOS == 0" : : -DCHECK_VALUE=true : -DCHECK_VALUE=false ] ] ; diff --git a/test/check_value.cpp b/test/check_value.cpp new file mode 100644 index 0000000..86bed68 --- /dev/null +++ b/test/check_value.cpp @@ -0,0 +1,26 @@ +/* +Copyright Rene Rivera 2015 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt) +*/ + +/* + * Simple program that just prints out the externally + * defined CHECK_VALUE def. It's used to test the check + * program and the related BB support. + */ + +#include +#include +#include + +#ifndef CHECK_VALUE +#define CHECK_VALUE "undefined" +#endif + +int main(int argc, const char ** argv) +{ + std::cout << "CHECK_VALUE == " << CHECK_VALUE << "\n" ; + return 0; +}