PLUGIN array lang: "C++" version: "1.0" date: "2023-11-15" author: "Julien BRUGUIER" maintainer: "Julien BRUGUIER " synopsis: "Arrays enhancement" description: %{ The virtual machine is able to manage arrays represented by pointeurs in a basic way. .P This plugin enhances array management. %} example: "Basic handling" %{ .nf #!/usr/bin/env svm LOG MACHINE PLUGIN "===PLUGINMACHINELIB===" PLUGIN "svmint.so" PLUGIN "svmcom.so" PROCESS "basic" CODE "main" INLINE :memory PTR/array, STR/s :memory INT*5 -> &array [ 0 , 1 , 2 , 3 , 4 ] -> @&array :array.append @&array { -1 -2 } :array.print @&array -> &s :com.message @&s :array.insert @&array 2 { 10 11 12 } :array.print @&array -> &s :com.message @&s :array.erase @&array 4 3 :array.print @&array -> &s :com.message @&s :array.update @&array "inc" { 100 } :array.print @&array -> &s :com.message @&s :shutdown :label inc :shift @(P/2) (P/1) :return END END .fi %} example: "Transformations" %{ .nf #!/usr/bin/env svm LOG MACHINE PLUGIN "===PLUGINMACHINELIB===" LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmcom.so" PLUGIN "svmint.so" PROCESS "transform" CODE "main" INLINE :memory PTR/array, STR/s :memory INT*5 -> &array [ 0 , 1 , 2 , 3 , 4 ] -> @&array :memory PTR/map, PTR/hypermap :array.map @&array op.add { 10 } -> &map :array.print @&map -> &s :com.message @&s :array.map @&array "incsqr" { 10 } -> &hypermap :array.print @&hypermap -> &s :com.message @&s :memory INT/sum, INT/product :array.accumulate @&array op.add { } 0 -> &sum :com.message @&sum [ 1 ] -> product :array.accumulate @&map "prod" { } product :com.message @&product :memory PTR/filter :array.filter @&hypermap op.odd { } -> &filter :array.print @&filter -> &s :com.message @&s :memory PTR/remap, PTR/sorted :array.map @&hypermap "selectdec" { 100 } -> &remap :array.sort @&remap op.cmp 0 2 { < } -> &sorted :array.print @&sorted -> &s :com.message @&s :shutdown :label incsqr :shift @(P/3) (P/1) :int.mul @(P/1) @(P/1) -> (P/2) :return :label prod :int.mul @&@(P/2) @(P/1) -> &@(P/2) :return :label selectdec @(P/1) -> (P/2) :memory BLN, INT -> &P :int.mod @(P/1) 2 -> (@&P/1) :int.cmp @(@&P/1) = 0 -> &@&P :return :unless @&@&P TRUE :int.sub @(P/1) @(P/3) -> (P/2) :return END END .fi .P This application uses this little plugin: .nf PLUGIN op DEFINE FUNCTION op.add INT INT -> INT :{ auto l = ARGV_VALUE(0,integer); auto r = ARGV_VALUE(1,integer); return NEW_VALUE(integer,l+r); :} code: :{ template bool comp(const T& l, const T& r, const std::string& c) { if(c=="<") return l") return l>=r; if(c==">") return l>r; if(c=="<>") return l!=r; } :} FUNCTION op.cmp INT [ < <= = => > <> ] INT -> BLN :{ auto l = ARGV_VALUE(0,integer); auto c = ARGV_MARKER(1); auto r = ARGV_VALUE(2,integer); return NEW_VALUE(boolean,comp(l,r,c)?TRUE:FALSE); :} FUNCTION op.odd INT -> BLN :{ auto i = ARGV_VALUE(0,integer); return NEW_VALUE(boolean,(i%2==1)?TRUE:FALSE); :} .fi %} test: initialisation %{ cat > op.svm_plugin << EOM PLUGIN op DEFINE FUNCTION op.inc MUTABLE INT INT :{ auto l = ARGV_VALUE(0,integer); auto r = ARGV_VALUE(1,integer); ::svm_value_integer_set(svm,::svm_parameter_value_get(svm,argv[0]),l+r); :} FUNCTION op.add INT INT -> INT :{ auto l = ARGV_VALUE(0,integer); auto r = ARGV_VALUE(1,integer); return NEW_VALUE(integer,l+r); :} code: :{ template bool comp(const T& l, const T& r, const std::string& c) { if(c=="<") return l") return l>=r; if(c==">") return l>r; if(c=="<>") return l!=r; } :} FUNCTION op.cmp INT INT [ < <= = => > <> ] -> BLN :{ auto l = ARGV_VALUE(0,integer); auto r = ARGV_VALUE(1,integer); auto c = ARGV_MARKER(2); return NEW_VALUE(boolean,comp(l,r,c)?TRUE:FALSE); :} FUNCTION op.odd INT -> BLN :{ auto i = ARGV_VALUE(0,integer); return NEW_VALUE(boolean,(i%2==1)?TRUE:FALSE); :} EOM svm_plugin -fi op.svm_plugin | bash && ./svmpluginop/plugin_install -l %} test: finalisation %{ rm -rf op.svm_plugin svmpluginop %} test: "Append_inplace" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, PTR/v, BLN/b :memory INT*3 -> &a @&a -> &v [ 0 , 1 , 2 ] -> @&a :array.append @&a { 3 4 } :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/3) = 3 -> &b :shutdown 2 :unless @&b TRUE :int.cmp @(&@&v+3) = 3 -> &b :shutdown 3 :unless @&b TRUE END END %} test: "Append_move" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, PTR/v, BLN/b :memory INT*3 -> &a :memory AUTO @&a -> &v [ 0 , 1 , 2 ] -> @&a :array.append @&a { 3 4 } :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/3) = 3 -> &b :shutdown 2 :unless @&b TRUE :shutdown 3 :when &@&v DEFINED END END %} test: "Append_null" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, PTR/r, BLN/b :memory INT*3 -> &a :memory AUTO [ 0 , 1 , 2 ] -> @&a :array.append @&a 2 -> &r :shutdown 1 :when (@&a/3) INITIALISED [ 3 , 4 ] -> @&r :int.cmp @(@&a/3) = 3 -> &b :shutdown 2 :unless @&b TRUE END END %} test: "Insert_start" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*3 -> &a [ 0 , 1 , 2 ] -> @&a :array.insert @&a 0 { 3 4 } :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/0) = 3 -> &b :shutdown 2 :unless @&b TRUE END END %} test: "Insert_middle" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*3 -> &a [ 0 , 1 , 2 ] -> @&a :array.insert @&a 1 { 3 4 } :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/1) = 3 -> &b :shutdown 2 :unless @&b TRUE END END %} test: "Insert_end" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*3 -> &a [ 0 , 1 , 2 ] -> @&a :array.insert @&a 3 { 3 4 } :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/3) = 3 -> &b :shutdown 2 :unless @&b TRUE END END %} test: "Insert_errors" %{ PROCESS "test" CODE "main" INLINE :memory PTR/a :memory INT*3 -> &a [ 0 , 1 , 2 ] -> @&a :interruption !array.out_of_range e1 :array.insert @&a -1 { 3 4 } :shutdown 1 :label e1 :interruption !array.out_of_range e2 :array.insert @&a 4 { 3 4 } :shutdown 2 :label e2 END END %} test: "Insert_wrapped" %{ -w %} %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*3 -> &a [ 0 , 1 , 2 ] -> @&a :array.insert @&a -1 { 3 4 } :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/3) = 3 -> &b :shutdown 2 :unless @&b TRUE :array.insert @&a 6 { 3 4 } :int.cmp @(@&a/0) = 3 -> &b :shutdown 3 :unless @&b TRUE END END %} test: "Insert_null" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, PTR/r, BLN/b :memory INT*3 -> &a [ 0 , 1 , 2 ] -> @&a :array.insert @&a 1 2 -> &r :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE :shutdown 2 :when (@&a/1) INITIALISED [ 3 , 4 ] -> @&r :int.cmp @(@&a/1) = 3 -> &b :shutdown 3 :unless @&b TRUE END END %} test: "Erase_start" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*5 -> &a [ 0 , 1 , 2 , 3 , 4 ] -> @&a :array.erase @&a 0 2 :int.cmp SIZE @&a = 3 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/0) = 2 -> &b :shutdown 2 :unless @&b TRUE END END %} test: "Erase_middle" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*5 -> &a [ 0 , 1 , 2 , 3 , 4 ] -> @&a :array.erase @&a 1 2 :int.cmp SIZE @&a = 3 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&a/1) = 3 -> &b :shutdown 2 :unless @&b TRUE END END %} test: "Erase_end" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*5 -> &a [ 0 , 1 , 2 , 3 , 4 ] -> @&a :array.erase @&a 3 2 :int.cmp SIZE @&a = 3 -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Erase_nothing" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*5 -> &a [ 0 , 1 , 2 , 3 , 4 ] -> @&a :array.erase @&a 3 0 :int.cmp SIZE @&a = 5 -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Erase_errors" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/a, BLN/b :memory INT*5 -> &a [ 0 , 1 , 2 , 3 , 4 ] -> @&a :interruption FAILURE e1 :array.erase @&a 3 -1 :shutdown 1 :label e1 :interruption !array.out_of_range e2 :array.erase @&a 2 5 :shutdown 2 :label e2 :array.erase @&a 0 5 :interruption !array.out_of_range e3 :array.erase @&a 0 1 :shutdown 3 :label e3 END END %} test: "Copy" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/c, BLN/b :memory INT*3, STR*3 -> &t [ 0 , , 2 , "3" , , "5" ] -> @&t :array.copy @&t -> &c :int.cmp @(@&c/2) = 2 -> &b :shutdown 1 :unless @&b TRUE :shutdown 2 :unless (@&c/1) IS INT :shutdown :label f :shift @(P/2) (P/1) :return END END %} test: "Update_plugin" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.update @&t op.inc { 2 } :int.cmp @(@&t/2) = 4 -> &b :shutdown 1 :unless @&b TRUE :shutdown END END %} test: "Update_code" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.update @&t "f" { 2 } :int.cmp @(@&t/2) = 4 -> &b :shutdown 1 :unless @&b TRUE :shutdown :label f :shift @(P/2) (P/1) :return END END %} test: "Map_plugin" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/r, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.map @&t op.add { 2 } -> &r :int.cmp @(@&t/2) = 2 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&r/2) = 4 -> &b :shutdown 2 :unless @&b TRUE :shutdown END END %} test: "Map_code" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/r, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.map @&t "f" { 2 } -> &r :int.cmp @(@&t/2) = 2 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&r/2) = 4 -> &b :shutdown 2 :unless @&b TRUE :shutdown :label f :int.add @(P/3) @(P/1) -> (P/2) :return END END %} test: "Accumulate_plugin" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, INT/r, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.accumulate @&t op.add { } 0 -> &r :int.cmp @&r = 10 -> &b :shutdown 1 :unless @&b TRUE :shutdown END END %} test: "Accumulate_code" %{ PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, INT/r, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t [ 0 ] -> r :array.accumulate @&t "f" { } r :int.cmp @&r = 10 -> &b :shutdown 1 :unless @&b TRUE :shutdown :label f :shift @(P/1) &@(P/2) :return END END %} test: "Filter_cmp" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/r, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.filter @&t op.cmp { 3 < } -> &r :int.cmp SIZE @&r = 3 -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Filter_odd" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/r, BLN/b :memory INT*5 -> &t [ 0 , 1 , 2 , 3 , 4 ] -> @&t :array.filter @&t op.odd { } -> &r :int.cmp SIZE @&r = 2 -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Sort_asc" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/r, BLN/b :memory INT*5 -> &t [ 2 , 1 , 4 , 0 , 3 ] -> @&t :array.sort @&t op.cmp { < } -> &r :int.cmp SIZE @&r = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&r/0) = 0 -> &b :shutdown 2 :unless @&b TRUE :int.cmp @(@&r/4) = 4 -> &b :shutdown 3 :unless @&b TRUE END END %} test: "Sort_desc" %{ LOCAL PLUGIN "svmpluginop/libsvmop.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory PTR/t, PTR/r, BLN/b :memory INT*5 -> &t [ 2 , 1 , 4 , 0 , 3 ] -> @&t :array.sort @&t op.cmp { > } -> &r :int.cmp SIZE @&r = 5 -> &b :shutdown 1 :unless @&b TRUE :int.cmp @(@&r/0) = 4 -> &b :shutdown 2 :unless @&b TRUE :int.cmp @(@&r/4) = 0 -> &b :shutdown 3 :unless @&b TRUE END END %} includes: %{ #include %} code: %{ namespace Array { unsigned long long int index(const void *svm, const unsigned long long int index, const SVM_Size size) { unsigned long long int i=index; SVM_Value_Boolean b = ::svm_plugin_get_option(svm,CONST_PEP(array,wrap)); if(::svm_value_boolean_get(svm,b)) { i = i%(size+1); if(i<0) { i+=(size+1); } } else { if((i<0) or (i>size)) { ERROR_EXTERNAL(array,out_of_range,"Index out of range"); } } return i; } void swap(SVM_Value *&l, SVM_Value *& r) { SVM_Value t = *l; *l=*r; *r=t; } /* void display(const void *svm, const std::string& header, SVM_Value *start, SVM_Value *end, SVM_Value *pivot) { std::ostringstream oss; oss << header << " " << (pivot-start) << " |"; for(SVM_Value *i=start ; i=end) return; SVM_Value *t = end-1; SVM_Value *s = start; for(SVM_Value *i=start ; i PTR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); long long int s = 0; std::vector v; if(::svm_parameter_type_is_value(svm,argv[1])) { s = ARGV_VALUE(1,integer); } else { for(SVM_Size ii=2 ; ii<(argc-1) ; ++ii) { v.push_back(::svm_parameter_value_get(svm,argv[ii])); } s = v.size(); } SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); bool e = false; for(SVM_Size ii=0 ; ii PTR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); auto i = ARGV_VALUE(1,integer); long long int s = 0; std::vector v; if(::svm_parameter_type_is_value(svm,argv[2])) { s = ARGV_VALUE(2,integer); } else { for(SVM_Size ii=3 ; ii<(argc-1) ; ++ii) { v.push_back(::svm_parameter_value_get(svm,argv[ii])); } s = v.size(); } SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); i = Array::index(svm,i,as); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,as+s); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); SVM_Address pa = ::svm_value_pointer_get_address(svm,p); SVM_Size ps = ::svm_value_pointer_get_size(svm,p); SVM_Value_Pointer ts = ::svm_value_pointer_new__raw(svm,aa,i); SVM_Value_Pointer td = ::svm_value_pointer_new__raw(svm,pa,i); ::svm_memory_move(svm,CURRENT(kernel),ts,CURRENT(kernel),td); if(not v.empty()) { for(SVM_Size ii=0 ; iias) { ERROR_EXTERNAL(array,out_of_range,"Exceding array"); } if(s==0) RETURN; SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,as-s); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); SVM_Address pa = ::svm_value_pointer_get_address(svm,p); SVM_Size ps = ::svm_value_pointer_get_size(svm,p); SVM_Value_Pointer ts = ::svm_value_pointer_new__raw(svm,aa,i); SVM_Value_Pointer td = ::svm_value_pointer_new__raw(svm,pa,i); ::svm_memory_move(svm,CURRENT(kernel),ts,CURRENT(kernel),td); ts = ::svm_value_pointer_new__raw(svm,aa+i+s,as-i-s); td = ::svm_value_pointer_new__raw(svm,pa+i,as-i-s); ::svm_memory_move(svm,CURRENT(kernel),ts,CURRENT(kernel),td); ::svm_memory_free(svm,CURRENT(kernel),a); ::svm_memory_scope_set_global(svm,CURRENT(kernel),a); ::svm_value_pointer_set_addresssize__raw(svm,a,pa,ps); %} help: %{ This instruction erases elements from an array at the specified index. When the index is invalid, an !array.out_of_range can be raised. The array is always relocated, unless the deleted size is 0. %} INSTRUCTION array.sub PTR:array INT:index INT:size -> PTR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); auto i = ARGV_VALUE(1,integer); auto s = ARGV_VALUE(2,integer); SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); i = Array::index(svm,i,as); if(s<0) { ERROR_INTERNAL(FAILURE,"Invalid size"); } if(i+s>as) { ERROR_EXTERNAL(array,out_of_range,"Exceding array"); } return ::svm_value_pointer_new__raw(svm,aa+i,s); %} help: %{ This instruction returns a pointer referencing a sub-part of the array. .P When the index and the size are invalid, an !array.out_of_range interruption will be raised. .P When the size is negative, a FAILURE interruption will be raised. %} INSTRUCTION array.copy PTR:array -> PTR:copy %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Size as = ::svm_value_pointer_get_size(svm,a); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,as); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); ::svm_memory_copy(svm,CURRENT(kernel),a,CURRENT(kernel),p); return p; %} help: %{ This instruction copies an array. %} INSTRUCTION array.print PTR:array -> STR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); std::ostringstream oss; oss << "["; bool b = false; for(SVM_Address ii=aa ; ii<(aa+as) ; ++ii) { if(b) { oss << " ,"; } b = true; oss << " "; if(::svm_memory_address_is_initialised(svm,CURRENT(kernel),ii)) { SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),ii); SVM_String s = ::svm_value_print(svm,v); oss << RAW_STRING(s); } } oss << " ]"; return ::svm_value_string_new__buffer(svm,oss.str().c_str(),oss.str().size()); %} help: %{ This instruction generates a string from an array. %} INSTRUCTION array.update PTR:array ( PEP:function INT:element ? { . * } | [ STR SYM ]:function { VALUE * }) %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); SVM_Value f = ::svm_parameter_value_get(svm,argv[1]); if(::svm_value_type_is_pluginentrypoint(svm,f)) { SVM_Size index = 3; SVM_Size element = 0; if(::svm_parameter_type_is_value(svm,argv[2])) { auto i = ARGV_VALUE(2,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid element index"); } element = i; index = 4; } SVM_Parameter *p = ::svm_parameter_array_new(svm,argc-index); SVM_Size iii = 0; for(SVM_Size ii=index ; ii<(argc-1) ; ++ii) { for( ; ; ) { if(iii==element) { ++iii; } else { break; } } p[iii++]=argv[ii]; } for(SVM_Address ii=aa ; ii<(aa+as) ; ++ii) { SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),ii); p[element] = ::svm_parameter_value_new(svm,v); ::svm_function_call(svm,f,argc-index,p); VARIABLE_DELETE(p[element]); } } else { SVM_Address fa = 0; SVM_Value_Symbol fs = nullptr; if(::svm_value_type_is_symbol(svm,f)) { fs = f; } else { SVM_Code c = ::svm_processor_get_currentcode(svm,CURRENT(kernel)); fa = ::svm_code_label_get_address(svm,c,f); } SVM_Value *pv = ::svm_value_array_new(svm,argc-4); for(SVM_Size ii=3 ; ii<(argc-1) ; ++ii) { pv[ii-3] = ::svm_parameter_value_get(svm,argv[ii]); } SVM_Value_Pointer pc = ::svm_processor_get_currentpointer(svm,CURRENT(kernel)); for(SVM_Address ii=(aa+as) ; ii>aa ; --ii) { if(fs) { ::svm_processor_call_global(svm,CURRENT(kernel),fs,pc); } else { ::svm_processor_call_local(svm,CURRENT(kernel),fa,pc); } auto rii = ii-1; SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),rii); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,POINTER,1); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,argc-3); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); SVM_Address pa = ::svm_value_pointer_get_address(svm,p); SVM_Size ps = ::svm_value_pointer_get_size(svm,p); SVM_Value_Pointer vs = ::svm_value_pointer_new__raw(svm,rii,1); SVM_Value_Pointer vd = ::svm_value_pointer_new__raw(svm,pa+1,1); ::svm_memory_share(svm,CURRENT(kernel),vs,CURRENT(kernel),vd); ::svm_memory_write_pointer__raw(svm,CURRENT(kernel),pa+2,ps-2,pv); ::svm_processor_set_currentpointer(svm,CURRENT(kernel),p); } } %} help: %{ This instruction applies a function to each element of an array. The array is modified in place. .P The function can be: - A plugin function when the function is passed as a PEP: The array element is passed by default as first parameter in the function and is mutable, but the position of the element can be specified to another index, - A code function when the function is passed as a STR or a SYM: The array element is passed as second parameter - aka (P/1) - in the function, and (P/0) is set to a pointer to store local values. .P The values between { and } are extra parameters passed to the function. .P The instruction just launches the functions, and does not care about checking for eventual errors. It is up to the user to set correct interruption handlers to manage errors. %} INTERRUPTION array.invalid_return help: %{ This interruption is raised when a plugin function returns an invalid value. %} INSTRUCTION array.map PTR:array ( PEP:function INT:element ? { . * } | [ STR SYM ]:function { VALUE * }) -> PTR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); SVM_Value f = ::svm_parameter_value_get(svm,argv[1]); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,as); SVM_Value_Pointer r = ::svm_memory_allocate(svm,CURRENT(kernel),z); SVM_Address ra = ::svm_value_pointer_get_address(svm,r); if(::svm_value_type_is_pluginentrypoint(svm,f)) { SVM_Size index = 3; SVM_Size element = 0; if(::svm_parameter_type_is_value(svm,argv[2])) { auto i = ARGV_VALUE(2,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid element index"); } element = i; index = 4; } SVM_Parameter *p = ::svm_parameter_array_new(svm,argc-index); SVM_Size iii = 0; for(SVM_Size ii=index ; ii<(argc-1) ; ++ii) { for( ; ; ) { if(iii==element) { ++iii; } else { break; } } p[iii++]=argv[ii]; } for(SVM_Address ii=aa ; ii<(aa+as) ; ++ii,++ra) { SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),ii); p[element] = ::svm_parameter_value_new(svm,v); SVM_Variable rv = ::svm_function_call(svm,f,argc-index,p); if(not rv or not ::svm_variable_type_is_value(svm,rv)) { ERROR_EXTERNAL(array,invalid_return,"Function shall return a value"); } ::svm_value_state_set_movable(svm,rv); ::svm_memory_write_address(svm,CURRENT(kernel),ra,rv); VARIABLE_DELETE(p[element]); } } else { SVM_Address fa = 0; SVM_Value_Symbol fs = nullptr; if(::svm_value_type_is_symbol(svm,f)) { fs = f; } else { SVM_Code c = ::svm_processor_get_currentcode(svm,CURRENT(kernel)); fa = ::svm_code_label_get_address(svm,c,f); } SVM_Value *pv = ::svm_value_array_new(svm,argc-4); for(SVM_Size ii=3 ; ii<(argc-1) ; ++ii) { pv[ii-3] = ::svm_parameter_value_get(svm,argv[ii]); } SVM_Value_Pointer pc = ::svm_processor_get_currentpointer(svm,CURRENT(kernel)); SVM_Size rs = ::svm_value_pointer_get_size(svm,r); ra += rs; for(SVM_Address ii=(aa+as) ; ii>aa ; --ii) { --ra; if(fs) { ::svm_processor_call_global(svm,CURRENT(kernel),fs,pc); } else { ::svm_processor_call_local(svm,CURRENT(kernel),fa,pc); } auto rii = ii-1; SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),rii); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,POINTER,1); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,argc-2); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); SVM_Address pa = ::svm_value_pointer_get_address(svm,p); SVM_Size ps = ::svm_value_pointer_get_size(svm,p); ::svm_memory_write_address(svm,CURRENT(kernel),pa+1,v); SVM_Value_Pointer vs = ::svm_value_pointer_new__raw(svm,ra,1); SVM_Value_Pointer vd = ::svm_value_pointer_new__raw(svm,pa+2,1); ::svm_memory_share(svm,CURRENT(kernel),vs,CURRENT(kernel),vd); ::svm_memory_write_pointer__raw(svm,CURRENT(kernel),pa+3,ps-3,pv); ::svm_processor_set_currentpointer(svm,CURRENT(kernel),p); } } return r; %} help: %{ This instruction applies a function to each element of an array, and creates an array with the resulting values. .P The function can be: - A plugin function when the function is passed as a PEP: The array element is passed by default as first parameter in the function, but the position of the element can be specified to another index, - A code function when the function is passed as a STR or a SYM: The array element is passed as second parameter - aka (P/1) - in the function, and (P/0) is set to a pointer to store local values. .P The values between { and } are extra parameters passed to the function. .P The instruction just launches the functions, and does not care about checking for eventual errors. It is up to the user to set correct interruption handlers to manage errors. %} INSTRUCTION array.accumulate PTR:array ( PEP:function ( INT:element INT:accumulator ) ? { . * } VALUE:init | [ STR SYM ]:function { VALUE * } PTR:accumulator) -> [ VALUE PTR ] %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); SVM_Value f = ::svm_parameter_value_get(svm,argv[1]); if(::svm_value_type_is_pluginentrypoint(svm,f)) { SVM_Size index = 3; SVM_Size element = 0; SVM_Size accumulator = 1; if(::svm_parameter_type_is_value(svm,argv[2])) { auto i = ARGV_VALUE(2,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid element index"); } element = i; i = ARGV_VALUE(3,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid accumulator index"); } if(element==accumulator) { ERROR_INTERNAL(FAILURE,"Element and accumulator indexes can not be equal"); } accumulator = i; index = 5; } SVM_Parameter *p = ::svm_parameter_array_new(svm,argc-index); SVM_Size iii = 0; for(SVM_Size ii=index ; ii<(argc-1) ; ++ii) { for( ; ; ) { if(iii==element or iii==accumulator) { ++iii; } else { break; } } p[iii++]=argv[ii]; } p[accumulator] = argv[argc-1]; for(SVM_Address ii=aa ; ii<(aa+as) ; ++ii) { SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),ii); p[element] = ::svm_parameter_value_new(svm,v); SVM_Variable rv = ::svm_function_call(svm,f,argc-index,p); if(not rv or not ::svm_variable_type_is_value(svm,rv)) { ERROR_EXTERNAL(array,invalid_return,"Function shall return a value"); } VARIABLE_DELETE(p[element]); VARIABLE_DELETE(p[accumulator]); p[accumulator] = ::svm_parameter_value_new(svm,rv); } return ::svm_parameter_value_get(svm,p[accumulator]); } else { SVM_Address fa = 0; SVM_Value_Symbol fs = nullptr; if(::svm_value_type_is_symbol(svm,f)) { fs = f; } else { SVM_Code c = ::svm_processor_get_currentcode(svm,CURRENT(kernel)); fa = ::svm_code_label_get_address(svm,c,f); } SVM_Value *pv = ::svm_value_array_new(svm,argc-5); for(SVM_Size ii=3 ; ii<(argc-2) ; ++ii) { pv[ii-3] = ::svm_parameter_value_get(svm,argv[ii]); } SVM_Value_Pointer pp = ::svm_parameter_value_get(svm,argv[argc-1]); SVM_Value_Pointer pc = ::svm_processor_get_currentpointer(svm,CURRENT(kernel)); for(SVM_Address ii=(aa+as) ; ii>aa ; --ii) { if(fs) { ::svm_processor_call_global(svm,CURRENT(kernel),fs,pc); } else { ::svm_processor_call_local(svm,CURRENT(kernel),fa,pc); } auto rii = ii-1; SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),rii); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,POINTER,1); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,1); ::svm_memory_zone_append_internal__raw(svm,z,POINTER,1); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,argc-5); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); SVM_Address pa = ::svm_value_pointer_get_address(svm,p); SVM_Size ps = ::svm_value_pointer_get_size(svm,p); ::svm_memory_write_address(svm,CURRENT(kernel),pa+1,v); ::svm_memory_write_address(svm,CURRENT(kernel),pa+2,pp); ::svm_memory_write_pointer__raw(svm,CURRENT(kernel),pa+3,ps-3,pv); ::svm_processor_set_currentpointer(svm,CURRENT(kernel),p); } return pp; } %} help: %{ This instruction accumulates elements from an array into a value. .P This instruction has two execution modes: - With a plugin function: The initial value is passed as last parameter, and the accumulated value is returned by the instruction. Within the function, the array element is passed by default as first parameter, and the accumulator as second parameter. When the element and the accumulator indexes are specified, element and accumulator are placed at these indexes. - With a code function: The accumulator is passed as a pointer referencing the accumulated values. This pointer shall be initialised before the instruction call, and the result will be referenced by this pointer, returned by the instruction. Within the function, the first parameter is pointer usable for local allocations, the second parameter - (P/1) - is the array element, the third parameter - (P/2) - is the pointer to the accumulator. .P In both cases, parameters between { and } are extra parameters. .P The instruction raises an !array.invalid_return interruption if the plugin function does not return a value. %} INSTRUCTION array.filter PTR:array PEP:predicate INT:index ? { . * } -> PTR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Address aa = ::svm_value_pointer_get_address(svm,a); SVM_Size as = ::svm_value_pointer_get_size(svm,a); SVM_Value_PluginEntryPoint f = ::svm_parameter_value_get(svm,argv[1]); SVM_Value *r = ::svm_value_array_new(svm,as); SVM_Size rs = 0; SVM_Size index = 3; SVM_Size element = 0; if(::svm_parameter_type_is_value(svm,argv[2])) { auto i = ARGV_VALUE(2,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid element index"); } element = i; index = 4; } SVM_Parameter *p = ::svm_parameter_array_new(svm,argc-index); SVM_Size iii = 0; for(SVM_Size ii=index ; ii<(argc-1) ; ++ii) { for( ; ; ) { if(iii==element) { ++iii; } else { break; } } p[iii++]=argv[ii]; } for(SVM_Address ii=aa ; ii<(aa+as) ; ++ii) { SVM_Value v = ::svm_memory_read_address(svm,CURRENT(kernel),ii); p[element] = ::svm_parameter_value_new(svm,v); SVM_Variable rv = ::svm_function_call(svm,f,argc-index,p); if(not rv or not ::svm_variable_type_is_value(svm,rv) or not ::svm_value_type_is_boolean(svm,rv)) { ERROR_EXTERNAL(array,invalid_return,"Function shall return a boolean value"); } if(::svm_value_boolean_get(svm,rv)) { r[rs++]=v; } VARIABLE_DELETE(p[element]); } SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,rs); SVM_Value_Pointer pr = ::svm_memory_allocate(svm,CURRENT(kernel),z); ::svm_memory_write_pointer(svm,CURRENT(kernel),pr,r); return pr; %} help: %{ This instruction applies a predicate on each array element, and copies in a new array elements passing the test of the predicate. .P Within the plugin function, the array element is passed by default as first parameter. Parameters between { and } are passed as extra parameters to the predicate function. When the index is specified, the element is put at this index. .P The instruction raises an !array.invalid_return interruption if the plugin function does not return a boolean value. %} INSTRUCTION array.sort PTR:array PEP:comparator (INT:left INT: right) ? { . * } -> PTR %{ SVM_Value_Pointer a = ::svm_parameter_value_get(svm,argv[0]); SVM_Value_PluginEntryPoint f = ::svm_parameter_value_get(svm,argv[1]); SVM_Size index=2; SVM_Size left = 0; SVM_Size right = 1; if(::svm_parameter_type_is_value(svm,argv[2])) { auto i = ARGV_VALUE(2,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid left index"); } left = i; i = ARGV_VALUE(3,integer); if((i<0) or (i>=argc-4)) { ERROR_INTERNAL(FAILURE,"Invalid right index"); } right = i; if(left==right) { ERROR_INTERNAL(FAILURE,"Left and right indexes can not be equal"); } index = 4; } SVM_Parameter *p = ::svm_parameter_array_new(svm,argc-index); SVM_Size iii=0; for(SVM_Size ii=index+1 ; ii<(argc-1) ; ++ii) { for( ; ; ) { if(iii==left or iii==right) { ++iii; } else { break; } } p[iii++]=argv[ii]; } SVM_Value *v = ::svm_memory_read_pointer(svm,CURRENT(kernel),a); SVM_Size vs=0; for(SVM_Value *ii=v ; *ii ; ++ii) { v[vs] = ::svm_value_copy(svm,v[vs]); ::svm_value_state_set_movable(svm,v[vs]); ++vs; } Array::sort(svm,v,v+vs,f,argc-index,p,left,right); SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,AUTOMATIC,vs); SVM_Value_Pointer r = ::svm_memory_allocate(svm,CURRENT(kernel),z); ::svm_memory_write_pointer(svm,CURRENT(kernel),r,v); return r; %} help: %{ This instruction applies a sort algorithm using a plugin function as comparator, and creates a new array with sorted values. .P Within the plugin function, the two array elements are passed by default as first and second parameter. Parameters between { and } are passed as extra parameters to the comparator function. When the left and the right index are specified, the left value and the right values will be placed at these index on the comparator parameters. .P The instruction raises an !array.invalid_return interruption if the plugin function does not return a boolean value. %}