|
39 | 39 | #include "program.h"
|
40 | 40 | #include "renderer.h"
|
41 | 41 | #include "runtime.h"
|
| 42 | +#include "symbol.h" |
42 | 43 | #include "utf8.h"
|
43 | 44 | #include "variables.h"
|
44 | 45 |
|
@@ -811,6 +812,116 @@ COMMAND_BODY(Filter)
|
811 | 812 | }
|
812 | 813 |
|
813 | 814 |
|
| 815 | +algebraic_p sum_product(symbol_g name, |
| 816 | + large a, |
| 817 | + large b, |
| 818 | + program_g expr, |
| 819 | + bool product) |
| 820 | +// ---------------------------------------------------------------------------- |
| 821 | +// Perform a sum or product |
| 822 | +// ---------------------------------------------------------------------------- |
| 823 | +{ |
| 824 | + algebraic_g result = integer::make(uint(product)); |
| 825 | + algebraic_g value; |
| 826 | + save<symbol_g *> iref(expression::independent, &name); |
| 827 | + |
| 828 | + for (large i = a; i <= b; i++) |
| 829 | + { |
| 830 | + value = integer::make(i); |
| 831 | + value = algebraic::evaluate_function(expr, value); |
| 832 | + if (!value) |
| 833 | + return nullptr; |
| 834 | + result = product ? result * value : result + value; |
| 835 | + } |
| 836 | + |
| 837 | + return result; |
| 838 | +} |
| 839 | + |
| 840 | + |
| 841 | +static object::result pair_map(object::id cmd) |
| 842 | +// ---------------------------------------------------------------------------- |
| 843 | +// Shared code for map, reduce and filter |
| 844 | +// ---------------------------------------------------------------------------- |
| 845 | +{ |
| 846 | + size_t depth = rt.depth(); |
| 847 | + if (rt.args(1)) |
| 848 | + { |
| 849 | + object_p obj = rt.stack(0); |
| 850 | + object::id ty = obj->type(); |
| 851 | + if (ty == object::ID_list || ty == object::ID_array) |
| 852 | + { |
| 853 | + object_p result = list_p(obj)->reduce(command::static_object(cmd)); |
| 854 | + if (result && rt.top(result)) |
| 855 | + return object::OK; |
| 856 | + } |
| 857 | + else if (rt.args(4)) |
| 858 | + { |
| 859 | + symbol_g name = rt.stack(3)->as_quoted<symbol>(); |
| 860 | + if (!name) |
| 861 | + goto error; |
| 862 | + object_g init = rt.stack(2); |
| 863 | + object_g last = rt.stack(1); |
| 864 | + object_g expr = rt.stack(0); |
| 865 | + if (!expr->is_program()) |
| 866 | + { |
| 867 | + rt.type_error(); |
| 868 | + goto error; |
| 869 | + } |
| 870 | + |
| 871 | + if (init->is_symbolic() || last->is_symbolic()) |
| 872 | + { |
| 873 | + object_g prg = command::static_object(cmd); |
| 874 | + expr = rt.make<list>(object::ID_expression, |
| 875 | + name, init, last, expr, prg); |
| 876 | + if (expr && rt.drop(3) && rt.top(expr)) |
| 877 | + return object::OK; |
| 878 | + goto error; |
| 879 | + } |
| 880 | + else if (init->is_integer() && last->is_integer()) |
| 881 | + { |
| 882 | + bool prod = cmd == object::ID_Product; |
| 883 | + program_g prg = program_p(expr.Safe()); |
| 884 | + large a = init->as_int64(); |
| 885 | + large b = last->as_int64(); |
| 886 | + expr = sum_product(name, a, b, prg, prod); |
| 887 | + if (expr && rt.drop(3) && rt.top(expr)) |
| 888 | + return object::OK; |
| 889 | + } |
| 890 | + else |
| 891 | + { |
| 892 | + rt.type_error(); |
| 893 | + } |
| 894 | + } |
| 895 | + else |
| 896 | + { |
| 897 | + rt.type_error(); |
| 898 | + } |
| 899 | + } |
| 900 | +error: |
| 901 | + if (rt.depth() > depth) |
| 902 | + rt.drop(rt.depth() - depth); |
| 903 | + return object::ERROR; |
| 904 | +} |
| 905 | + |
| 906 | + |
| 907 | +COMMAND_BODY(Sum) |
| 908 | +// ---------------------------------------------------------------------------- |
| 909 | +// Return the sum of a list or array |
| 910 | +// ---------------------------------------------------------------------------- |
| 911 | +{ |
| 912 | + return pair_map(ID_add); |
| 913 | +} |
| 914 | + |
| 915 | + |
| 916 | +COMMAND_BODY(Product) |
| 917 | +// ---------------------------------------------------------------------------- |
| 918 | +// Return the product of a list or array |
| 919 | +// ---------------------------------------------------------------------------- |
| 920 | +{ |
| 921 | + return pair_map(ID_mul); |
| 922 | +} |
| 923 | + |
| 924 | + |
814 | 925 | object_p list::head() const
|
815 | 926 | // ----------------------------------------------------------------------------
|
816 | 927 | // Return the first element in the list
|
|
0 commit comments