From b5eaa3beddfd556ffa9b88519acf9accdbc41418 Mon Sep 17 00:00:00 2001 From: Tanasart <22589759+Ttanasart-pt@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:43:18 +0200 Subject: [PATCH] [PCX] Negative array index, unary substraction bug. --- PixelComposer.resource_order | 3 +- PixelComposer.yyp | 5 +- scripts/globals/globals.gml | 6 +- scripts/node_number/node_number.gml | 40 +- scripts/node_value/node_value.gml | 6 +- .../string_eval.gml => pcx_ast/pcx_ast.gml} | 433 +----------------- .../pxl_server.yy => pcx_ast/pcx_ast.yy} | 2 +- scripts/pcx_parse/pcx_parse.gml | 410 +++++++++++++++++ .../string_eval.yy => pcx_parse/pcx_parse.yy} | 2 +- .../pcx_server.gml} | 0 scripts/pcx_server/pcx_server.yy | 11 + 11 files changed, 478 insertions(+), 440 deletions(-) rename scripts/{string_eval/string_eval.gml => pcx_ast/pcx_ast.gml} (57%) rename scripts/{pxl_server/pxl_server.yy => pcx_ast/pcx_ast.yy} (88%) create mode 100644 scripts/pcx_parse/pcx_parse.gml rename scripts/{string_eval/string_eval.yy => pcx_parse/pcx_parse.yy} (88%) rename scripts/{pxl_server/pxl_server.gml => pcx_server/pcx_server.gml} (100%) create mode 100644 scripts/pcx_server/pcx_server.yy diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index c566e4536..5dc4b09de 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -644,7 +644,7 @@ {"name":"draw_sprite_ext_override","order":9,"path":"scripts/draw_sprite_ext_override/draw_sprite_ext_override.yy",}, {"name":"node_array_add","order":9,"path":"scripts/node_array_add/node_array_add.yy",}, {"name":"o_dialog_textbox_function_guide","order":7,"path":"objects/o_dialog_textbox_function_guide/o_dialog_textbox_function_guide.yy",}, - {"name":"pxl_server","order":2,"path":"scripts/pxl_server/pxl_server.yy",}, + {"name":"pcx_server","order":2,"path":"scripts/pcx_server/pcx_server.yy",}, {"name":"s_node_array_set","order":9,"path":"sprites/s_node_array_set/s_node_array_set.yy",}, {"name":"node_dust","order":21,"path":"scripts/node_dust/node_dust.yy",}, {"name":"node_noise_cell","order":2,"path":"scripts/node_noise_cell/node_noise_cell.yy",}, @@ -684,6 +684,7 @@ {"name":"s_node_convolution","order":48,"path":"sprites/s_node_convolution/s_node_convolution.yy",}, {"name":"fd_rectangle_get_velocity_time_step","order":25,"path":"scripts/fd_rectangle_get_velocity_time_step/fd_rectangle_get_velocity_time_step.yy",}, {"name":"node_string_regex_match","order":10,"path":"scripts/node_string_regex_match/node_string_regex_match.yy",}, + {"name":"pcx_parse","order":3,"path":"scripts/pcx_parse/pcx_parse.yy",}, {"name":"node_9slice","order":5,"path":"scripts/node_9slice/node_9slice.yy",}, {"name":"fd_rectangle_add_velocity_surface","order":24,"path":"scripts/fd_rectangle_add_velocity_surface/fd_rectangle_add_velocity_surface.yy",}, {"name":"BBMOD_Vec2","order":4,"path":"scripts/BBMOD_Vec2/BBMOD_Vec2.yy",}, diff --git a/PixelComposer.yyp b/PixelComposer.yyp index 12b9f1f70..6418e0ea7 100644 --- a/PixelComposer.yyp +++ b/PixelComposer.yyp @@ -915,7 +915,7 @@ {"id":{"name":"__node","path":"scripts/__node/__node.yy",},}, {"id":{"name":"fd_rectangle_add_velocity","path":"scripts/fd_rectangle_add_velocity/fd_rectangle_add_velocity.yy",},}, {"id":{"name":"sh_level_selector","path":"shaders/sh_level_selector/sh_level_selector.yy",},}, - {"id":{"name":"string_eval","path":"scripts/string_eval/string_eval.yy",},}, + {"id":{"name":"pcx_ast","path":"scripts/pcx_ast/pcx_ast.yy",},}, {"id":{"name":"s_node_struct","path":"sprites/s_node_struct/s_node_struct.yy",},}, {"id":{"name":"byte_writer","path":"scripts/byte_writer/byte_writer.yy",},}, {"id":{"name":"checkboxGroup","path":"scripts/checkboxGroup/checkboxGroup.yy",},}, @@ -1225,7 +1225,7 @@ {"id":{"name":"draw_sprite_ext_override","path":"scripts/draw_sprite_ext_override/draw_sprite_ext_override.yy",},}, {"id":{"name":"node_array_add","path":"scripts/node_array_add/node_array_add.yy",},}, {"id":{"name":"o_dialog_textbox_function_guide","path":"objects/o_dialog_textbox_function_guide/o_dialog_textbox_function_guide.yy",},}, - {"id":{"name":"pxl_server","path":"scripts/pxl_server/pxl_server.yy",},}, + {"id":{"name":"pcx_server","path":"scripts/pcx_server/pcx_server.yy",},}, {"id":{"name":"s_node_array_set","path":"sprites/s_node_array_set/s_node_array_set.yy",},}, {"id":{"name":"node_dust","path":"scripts/node_dust/node_dust.yy",},}, {"id":{"name":"node_noise_cell","path":"scripts/node_noise_cell/node_noise_cell.yy",},}, @@ -1269,6 +1269,7 @@ {"id":{"name":"s_node_convolution","path":"sprites/s_node_convolution/s_node_convolution.yy",},}, {"id":{"name":"fd_rectangle_get_velocity_time_step","path":"scripts/fd_rectangle_get_velocity_time_step/fd_rectangle_get_velocity_time_step.yy",},}, {"id":{"name":"node_string_regex_match","path":"scripts/node_string_regex_match/node_string_regex_match.yy",},}, + {"id":{"name":"pcx_parse","path":"scripts/pcx_parse/pcx_parse.yy",},}, {"id":{"name":"node_9slice","path":"scripts/node_9slice/node_9slice.yy",},}, {"id":{"name":"fd_rectangle_add_velocity_surface","path":"scripts/fd_rectangle_add_velocity_surface/fd_rectangle_add_velocity_surface.yy",},}, {"id":{"name":"BBMOD_Vec2","path":"scripts/BBMOD_Vec2/BBMOD_Vec2.yy",},}, diff --git a/scripts/globals/globals.gml b/scripts/globals/globals.gml index 2251a6225..3af813834 100644 --- a/scripts/globals/globals.gml +++ b/scripts/globals/globals.gml @@ -101,10 +101,10 @@ globalvar VERSION, SAVE_VERSION, VERSION_STRING, BUILD_NUMBER; - VERSION = 11500; + VERSION = 11510; SAVE_VERSION = 11500; - VERSION_STRING = "1.15"; - BUILD_NUMBER = 11500; + VERSION_STRING = "1.15.1"; + BUILD_NUMBER = 11501; globalvar APPEND_MAP; APPEND_MAP = ds_map_create(); diff --git a/scripts/node_number/node_number.gml b/scripts/node_number/node_number.gml index 547cb8768..26db5e02e 100644 --- a/scripts/node_number/node_number.gml +++ b/scripts/node_number/node_number.gml @@ -30,15 +30,15 @@ function Node_Number(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) co outputs[| 0] = nodeValue("Number", self, JUNCTION_CONNECT.output, VALUE_TYPE.float, 0); static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) { - var __ax = inputs[| 0].getValue(); + var __ax = inputs[| 0].getValueCached(); if(is_array(__ax)) return; inputs[| 0].drawOverlay(active, _x, _y, _s, _mx, _my, _snx, _sny); } function step() { - var int = inputs[| 1].getValue(); - var disp = inputs[| 2].getValue(); + var int = inputs[| 1].getValueCached(); + var disp = inputs[| 2].getValueCached(); w = 96; min_h = 56; @@ -75,15 +75,17 @@ function Node_Number(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) co } static process_data = function(_output, _data, _output_index, _array_index = 0) { - return _data[1]? round(_data[0]) : _data[0]; + var _res = _data[1]? round(_data[0]) : _data[0]; + display_output = _res; + return _res; } static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { var bbox = drawGetBbox(xx, yy, _s); - var val = getSingleValue(0,, true); - var disp = inputs[| 2].getValue(); - var rang = inputs[| 3].getValue(); - var stp = inputs[| 4].getValue(); + var val = display_output; + var disp = inputs[| 2].getValueCached(); + var rang = inputs[| 3].getValueCached(); + var stp = inputs[| 4].getValueCached(); if(inputs[| 0].value_from != noone || disp == 0) { draw_set_text(f_h1, fa_center, fa_center, COLORS._main_text); @@ -96,7 +98,7 @@ function Node_Number(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) co switch(disp) { case 1 : draw_set_text(f_p0, fa_center, fa_center, COLORS._main_text); - var str = string(getSingleValue(0,, true)); + var str = string(val); var ss = min(1, string_scale(str, bbox.w, 20)); draw_text_transformed(bbox.xc, bbox.y0 + 20 / 2, str, ss, ss, 0); @@ -177,8 +179,8 @@ function Node_Vector2(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c wd_pan_my = 0; static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) { - var __ax = inputs[| 0].getValue(); - var __ay = inputs[| 1].getValue(); + var __ax = inputs[| 0].getValueCached(); + var __ay = inputs[| 1].getValueCached(); if(is_array(__ax) || is_array(__ay)) return; @@ -226,8 +228,8 @@ function Node_Vector2(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c } function step() { - var int = inputs[| 2].getValue(); - var disp = inputs[| 3].getValue(); + var int = inputs[| 2].getValueCached(); + var disp = inputs[| 3].getValueCached(); for( var i = 0; i < 2; i++ ) { inputs[| i].type = int? VALUE_TYPE.integer : VALUE_TYPE.float; @@ -255,7 +257,7 @@ function Node_Vector2(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c } static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { - var disp = inputs[| 3].getValue(); + var disp = inputs[| 3].getValueCached(); var vec = getSingleValue(0,, true); var bbox = drawGetBbox(xx, yy, _s); @@ -410,7 +412,7 @@ function Node_Vector3(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c .setDisplay(VALUE_DISPLAY.vector); function step() { - var int = inputs[| 3].getValue(); + var int = inputs[| 3].getValueCached(); for( var i = 0; i < 3; i++ ) { inputs[| i].type = int? VALUE_TYPE.integer : VALUE_TYPE.float; inputs[| i].editWidget.slide_speed = int? 1 : 0.1; @@ -465,7 +467,7 @@ function Node_Vector4(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c .setDisplay(VALUE_DISPLAY.vector); function step() { - var int = inputs[| 4].getValue(); + var int = inputs[| 4].getValueCached(); for( var i = 0; i < 4; i++ ) { inputs[| i].type = int? VALUE_TYPE.integer : VALUE_TYPE.float; inputs[| i].editWidget.slide_speed = int? 1 : 0.1; @@ -528,11 +530,9 @@ function Node_Vector_Split(_x, _y, _group = noone) : Node_Processor(_x, _y, _gro static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { draw_set_text(f_h1, fa_center, fa_center, COLORS._main_text); - var str = string(outputs[| 0].getValue()) + "\n" + string(outputs[| 1].getValue()) - + "\n" + string(outputs[| 2].getValue()) + "\n" + string(outputs[| 3].getValue()); - + var str = $"{outputs[| 0].getValueCached()}\n{outputs[| 1].getValueCached()}\n{outputs[| 2].getValueCached()}\n{outputs[| 3].getValueCached()}"; var bbox = drawGetBbox(xx, yy, _s); - var ss = string_scale(str, bbox.w, bbox.h); + var ss = string_scale(str, bbox.w, bbox.h); draw_text_transformed(bbox.xc, bbox.yc, str, ss, ss, 0); } } \ No newline at end of file diff --git a/scripts/node_value/node_value.gml b/scripts/node_value/node_value.gml index ab441fb92..21a02b4be 100644 --- a/scripts/node_value/node_value.gml +++ b/scripts/node_value/node_value.gml @@ -1075,6 +1075,10 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru } #region[#eb004b20] === GetValue === + static getValueCached = function(_time = PROJECT.animator.current_frame, applyUnit = true, arrIndex = 0) { + return getValue(_time, applyUnit, arrIndex, true); + } + static getValue = function(_time = PROJECT.animator.current_frame, applyUnit = true, arrIndex = 0, useCache = false) { if(type == VALUE_TYPE.trigger) useCache = false; @@ -1086,7 +1090,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru cache_hit &= cache_value[2] != undefined; cache_hit &= connect_type == JUNCTION_CONNECT.input; cache_hit &= unit.reference == noone || unit.mode == VALUE_UNIT.constant; - cache_hit &= !expUse; + //cache_hit &= !expUse; if(cache_hit) { global.cache_hit++; diff --git a/scripts/string_eval/string_eval.gml b/scripts/pcx_ast/pcx_ast.gml similarity index 57% rename from scripts/string_eval/string_eval.gml rename to scripts/pcx_ast/pcx_ast.gml index 575d3845d..e1948846a 100644 --- a/scripts/string_eval/string_eval.gml +++ b/scripts/pcx_ast/pcx_ast.gml @@ -1,40 +1,6 @@ #region data - global.LOG_EXPRESSION = false; - global.EVALUATE_HEAD = noone; - global.EQUATION_PRES = ds_map_create(); - global.EQUATION_PRES[? "+"] = 1; - global.EQUATION_PRES[? "-"] = 1; - global.EQUATION_PRES[? "∸"] = 9; //unary negative - global.EQUATION_PRES[? "*"] = 2; - global.EQUATION_PRES[? "/"] = 2; - global.EQUATION_PRES[? "%"] = 2; - global.EQUATION_PRES[? "$"] = 3; - - global.EQUATION_PRES[? "&"] = 5; - global.EQUATION_PRES[? "|"] = 4; - global.EQUATION_PRES[? "^"] = 3; - global.EQUATION_PRES[? "<"] = 3; - global.EQUATION_PRES[? "»"] = 6; - global.EQUATION_PRES[? "«"] = 6; - global.EQUATION_PRES[? "~"] = 9; - - global.EQUATION_PRES[? "="] = -99; - global.EQUATION_PRES[? "⊕"] = -99; //+= - global.EQUATION_PRES[? "⊖"] = -99; //-= - global.EQUATION_PRES[? "⊗"] = -99; //*= - global.EQUATION_PRES[? "⊘"] = -99; ///= - - global.EQUATION_PRES[? "⩵"] = -1; //== - global.EQUATION_PRES[? "≠"] = -1; //!= - global.EQUATION_PRES[? "<"] = 0; - global.EQUATION_PRES[? ">"] = 0; - global.EQUATION_PRES[? "≤"] = 0; - global.EQUATION_PRES[? "≥"] = 0; - - global.EQUATION_PRES[? "@"] = 5; //array accerssor symbol - global.FUNCTIONS = ds_map_create(); global.FUNCTIONS[? "sin"] = [ ["radian"], function(val) { return sin(val[0]); } ]; global.FUNCTIONS[? "cos"] = [ ["radian"], function(val) { return cos(val[0]); } ]; @@ -69,6 +35,12 @@ return arr; } ]; + global.FUNCTIONS[? "length"] = [ ["value"], function(val) { + if(is_array(val)) return array_length(val); + if(is_string(val)) return string_length(val); + return 0; + } ]; + globalvar PROJECT_VARIABLES; PROJECT_VARIABLES = {}; @@ -93,49 +65,6 @@ PROJECT_VARIABLES.Device.timeYear = function() /*=>*/ {return current_year}; #endregion -function functionStringClean(fx) { - var ch = "", ind = 0, len = string_length(fx); - var _fx = "", str = false; - while(ind++ <= len) { - ch = string_char_at(fx, ind); - - if(ch == " ") { - if(str) - _fx += ch; - } else - _fx += ch; - - if(ch == "\"") - str = !str; - } - - fx = _fx; - - - fx = string_replace_all(fx, "\n", ""); - fx = string_replace_all(fx, "**", "$"); - fx = string_replace_all(fx, "<<", "«"); - fx = string_replace_all(fx, ">>", "»"); - - fx = string_replace_all(fx, "==", "⩵"); - fx = string_replace_all(fx, "!=", "≠"); - fx = string_replace_all(fx, "<>", "≠"); - fx = string_replace_all(fx, ">=", "≥"); - fx = string_replace_all(fx, "<=", "≤"); - - fx = string_replace_all(fx, "++", "⊕1"); - fx = string_replace_all(fx, "--", "⊖1"); - - fx = string_replace_all(fx, "+=", "⊕"); - fx = string_replace_all(fx, "-=", "⊖"); - fx = string_replace_all(fx, "*=", "⊗"); - fx = string_replace_all(fx, "/=", "⊘"); - - fx = string_trim(fx); - - return fx; -} - #region evaluator enum EXPRESS_TREE_ANIM { none, @@ -399,14 +328,23 @@ function functionStringClean(fx) { if(symbol == "") { res = v1; - } else if(symbol == "【") { //array builder + } else if(symbol == "【") { // array builder res = array_create(array_length(v1)); for( var i = 0, n = array_length(res); i < n; i++ ) res[i] = getVal(v1[i], params); - } else if(symbol == "@") { - if(isLeft) res = [ v1, v2 ]; - else res = is_real(v2)? array_safe_get(v1, v2) : 0; - } else if(symbol == "=") { + } else if(symbol == "@") { // array getter + if(isLeft) + res = [ v1, v2 ]; + else if(is_real(v2)) { + if(is_array(v1)) { + if(v2 < 0) v2 = array_length(v1) + v2; + res = array_safe_get(v1, v2); + } else if(is_string(v1)) { + if(v2 < 0) v2 = string_length(v1) + v2; + res = string_char_at(v1, v2 + 1); + } + } + } else if(symbol == "=") { // value assignment if(is_array(v1)) { var val = params[$ v1[0]]; val = array_safe_set(val, v1[1], v2); @@ -416,7 +354,7 @@ function functionStringClean(fx) { params[$ v1] = v2; res = v2; } - } else if(is_array(v1) && !is_array(v2)) { + } else if(is_array(v1) && !is_array(v2)) { // evaluate value res = array_create(array_length(v1)); for( var i = 0, n = array_length(res); i < n; i++ ) res[i] = eval_real(array_safe_get(v1, i), v2); @@ -470,8 +408,8 @@ function functionStringClean(fx) { if(is_real(v1) && is_real(v2)) return v1 + v2; return 0; case "-": + case "∸": case "⊖": return (is_real(v1) && is_real(v2))? v1 - v2 : 0; - case "∸": return is_real(v1)? -v1 : 0; case "*": case "⊗": return (is_real(v1) && is_real(v2))? v1 * v2 : 0; case "$": return (is_real(v1) && is_real(v2))? power(v1, v2) : 0; @@ -506,333 +444,6 @@ function functionStringClean(fx) { } } - function functionStrip(fx) { - var el_st = 1; - var el_ed = 1; - - for( var i = 1; i <= string_length(fx); i++ ) { - var cch = string_char_at(fx, i); - if(cch == "(") { - el_st = i + 1; - break; - } - } - - for( var i = string_length(fx); i >= 1; i-- ) { - var cch = string_char_at(fx, i); - if(cch == ")") { - el_ed = i; - break; - } - } - - return string_copy(fx, el_st, el_ed - el_st) - } - - function evaluateFunctionList(fx) { - fx = string_replace_all(fx, "{", "\n{\n"); - fx = string_replace_all(fx, "}", "\n}\n"); - - var fxs = string_split(fx, "\n", true); - - var flist = new __funcList(); - - var call_st = ds_stack_create(); - var blok_st = ds_stack_create(); - ds_stack_push(call_st, flist); - - for( var i = 0, n = array_length(fxs); i < n; i++ ) { - var _fx = functionStringClean(fxs[i]); - //print($"Eval line {i}: {_fx} [stack size = {ds_stack_size(call_st)}]"); - - if(_fx == "" || _fx == "{") continue; - if(_fx == "}") { - ds_stack_pop(call_st); - continue; - } - - var _fx_sp = string_split(_fx, "("); - var _cmd = string_trim(_fx_sp[0]); - var _cond = functionStrip(_fx); - - switch(_cmd) { - case "if": - var con_if = new __funcIf(); - con_if.condition = evaluateFunctionTree(_cond); - ds_stack_top(call_st).addFunction(con_if); - ds_stack_push(call_st, con_if.if_true); - ds_stack_push(blok_st, con_if); - continue; - case "elseif": - var con_if = ds_stack_pop(blok_st); - var con_elif = new __funcIf(); - con_elif.condition = evaluateFunctionTree(_cond); - - con_if.if_false.addFunction(con_elif); - ds_stack_push(call_st, con_elif.if_true); - ds_stack_push(blok_st, con_elif); - continue; - case "else": - var con_if = ds_stack_pop(blok_st); - - ds_stack_push(call_st, con_if.if_false); - continue; - case "for": - var con_for = new __funcFor(); - var cond = string_splice(_cond, ":"); - if(array_length(cond) == 2) { - con_for.itr_array = true; - con_for.cond_arr = evaluateFunctionTree(cond[1]); - - cond[0] = string_trim(cond[0]); - var _itr = string_split(cond[0], ","); - if(array_length(_itr) == 1) - con_for.cond_iter = cond[0]; - else if(array_length(_itr) == 2) { - con_for.cond_indx = string_trim(_itr[0]); - con_for.cond_iter = string_trim(_itr[1]); - } - } else if(array_length(cond) == 3) { - con_for.itr_array = false; - con_for.cond_init = evaluateFunctionTree(cond[0]); - con_for.cond_iter = evaluateFunctionTree(cond[1]); - con_for.cond_term = evaluateFunctionTree(cond[2]); - } - ds_stack_top(call_st).addFunction(con_for); - ds_stack_push(call_st, con_for.action); - continue; - } - - if(ds_stack_empty(call_st)) { - print("Block stack empty, how?"); - } else { - var _top = ds_stack_top(call_st); - _top.addFunction(evaluateFunctionTree(_fx)); - } - } - - ds_stack_destroy(call_st); - ds_stack_destroy(blok_st); - - return flist; - } - - function evaluateFunctionTree(fx) { - static __BRACKETS = [ "(", ")", "[", "]" ]; - - var pres = global.EQUATION_PRES; - var vl = ds_stack_create(); - var op = ds_stack_create(); - var last_push = ""; - - var len = string_length(fx); - var l = 1; - var ch = ""; - var cch = ""; - var _ch = ""; - var in_str = false; - - printIf(global.LOG_EXPRESSION, $"===== Evaluating function: {fx} ====="); - - while(l <= len) { - ch = string_char_at(fx, l); - - //print($"Analyzing {ch}"); - - if(ds_map_exists(pres, ch)) { //symbol is operator - last_push = "op"; - - if(ds_stack_empty(op)) ds_stack_push(op, ch); - else { - var _top = ds_stack_top(op); - if(_top == "(" || ds_map_exists(global.FUNCTIONS, _top) || pres[? ch] > pres[? _top]) { - ds_stack_push(op, ch); - } else { - if(ch == "-" && ds_map_exists(pres, _ch)) ch = "∸"; //unary negative - - while(pres[? ch] <= pres[? ds_stack_top(op)] && !ds_stack_empty(op)) - ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); - ds_stack_push(op, ch); - } - } - - l++; - } else if (ch == "(") { - if(last_push == "fn") ds_stack_push(op, [ "〚", ds_stack_size(vl) ]); - else ds_stack_push(op, ch); - last_push = "op"; - l++; - } else if (ch == ")") { - while(!ds_stack_empty(op)) { - var _top = ds_stack_pop(op); - if(_top == "(") break; - if(is_array(_top) && _top[0] == "〚") { - var arr = []; - while(ds_stack_size(vl) > _top[1]) - array_insert(arr, 0, ds_stack_pop(vl)); - - ds_stack_push(vl, new __funcTree(ds_stack_pop(op), arr)); - break; - } - - ds_stack_push(vl, buildFuncTree(_top, vl)); - } - - last_push = "vl"; - l++; - } else if (ch == "[") { - if(last_push == "vl") { - ds_stack_push(op, "@"); - ds_stack_push(op, ch); - } else - ds_stack_push(op, [ "{", ds_stack_size(vl) ]); - - last_push = "op"; - l++; - } else if (ch == "]") { - while(!ds_stack_empty(op)) { - var _top = ds_stack_pop(op); - if(_top == "[") break; - if(is_array(_top) && _top[0] == "{") { - var arr = []; - while(ds_stack_size(vl) > _top[1]) - array_insert(arr, 0, ds_stack_pop(vl)); - ds_stack_push(vl, new __funcTree("【", arr)); - break; - } - - ds_stack_push(vl, buildFuncTree(_top, vl)); - } - - last_push = "vl"; - l++; - } else if (ch == ",") { - while(!ds_stack_empty(op)) { - var _top = ds_stack_top(op); - if(_top == "[" || _top == "(" || (is_array(_top) && _top[0] == "{")) break; - - ds_stack_push(vl, buildFuncTree(_top, vl)); - } - - last_push = "vl"; - l++; - } else { - var vsl = ""; - - while(l <= len) { - cch = string_char_at(fx, l); - if(ds_map_exists(pres, cch) || array_exists(__BRACKETS, cch)) break; - if(cch == ",") { - l++; - break; - } - - vsl += cch; - l++; - } - - if(vsl == "") continue; - - if(ds_map_exists(global.FUNCTIONS, vsl)) { //function - ds_stack_push(op, vsl); - last_push = "fn"; - } else { - vsl = string_trim(vsl); - - switch(vsl) { - case "e" : ds_stack_push(vl, 2.71828); break; - case "pi": ds_stack_push(vl, pi); break; - default : ds_stack_push(vl, isNumber(vsl)? toNumber(vsl) : vsl); break; - } - - last_push = "vl"; - } - } - - //print($"op: {ds_stack_size(op)}; vl: {ds_stack_size(vl)}"); - - _ch = ch; - } - - while(!ds_stack_empty(op)) - ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); - - var tree = ds_stack_empty(vl)? noone : ds_stack_pop(vl); - - ds_stack_destroy(op); - ds_stack_destroy(vl); - - if(!is_struct(tree)) - tree = new __funcTree("", tree); - - printIf(global.LOG_EXPRESSION, tree); - printIf(global.LOG_EXPRESSION, ""); - - return tree; - } - - function buildFuncTree(operator, vl) { - if(ds_stack_empty(vl)) return noone; - - if(ds_map_exists(global.FUNCTIONS, operator)) { - if(ds_stack_empty(vl)) - return noone; - - var _v1 = ds_stack_pop(vl); - return new __funcTree(operator, _v1); - } - - switch(operator) { - case "-": //deal with preceeding negative number -5 - if(ds_stack_size(vl) >= 2) { - var _v1 = ds_stack_pop(vl); - var _v2 = ds_stack_pop(vl); - return new __funcTree("-", _v2, _v1); - } else - return new __funcTree("-", ds_stack_pop(vl), 0); - - case "@": - var _v1 = ds_stack_pop(vl); - var _v2 = ds_stack_pop(vl); - return new __funcTree(operator, _v2, _v1); - - case "+": //binary operators - case "*": - case "$": - case "/": - case "%": - - case "|": - case "&": - case "^": - case "»": - case "«": - - case "=": - case "⩵": - case "≠": - case "≤": - case "≥": - case "<": - case ">": - - case "⊕": - case "⊖": - case "⊗": - case "⊘": - - if(ds_stack_size(vl) >= 2) { - var _v1 = ds_stack_pop(vl); - var _v2 = ds_stack_pop(vl); - return new __funcTree(operator, _v2, _v1); - } - - default: return new __funcTree(operator, ds_stack_pop(vl)); - } - - return noone; - } - function evaluateFunction(fx, params = {}) { if(isNumber(fx)) return toNumber(fx); return evaluateFunctionList(fx).eval(params); diff --git a/scripts/pxl_server/pxl_server.yy b/scripts/pcx_ast/pcx_ast.yy similarity index 88% rename from scripts/pxl_server/pxl_server.yy rename to scripts/pcx_ast/pcx_ast.yy index 4f559a3ab..7fb4ae3e8 100644 --- a/scripts/pxl_server/pxl_server.yy +++ b/scripts/pcx_ast/pcx_ast.yy @@ -1,7 +1,7 @@ { "resourceType": "GMScript", "resourceVersion": "1.0", - "name": "pxl_server", + "name": "pcx_ast", "isCompatibility": false, "isDnD": false, "parent": { diff --git a/scripts/pcx_parse/pcx_parse.gml b/scripts/pcx_parse/pcx_parse.gml new file mode 100644 index 000000000..023ed3b34 --- /dev/null +++ b/scripts/pcx_parse/pcx_parse.gml @@ -0,0 +1,410 @@ +#region symbols + global.LOG_EXPRESSION = true; + + global.EQUATION_PRES = ds_map_create(); + global.EQUATION_PRES[? "+"] = 1; + global.EQUATION_PRES[? "-"] = 1; + global.EQUATION_PRES[? "∸"] = 9; //unary negative + global.EQUATION_PRES[? "*"] = 2; + global.EQUATION_PRES[? "/"] = 2; + global.EQUATION_PRES[? "%"] = 2; + global.EQUATION_PRES[? "$"] = 3; + + global.EQUATION_PRES[? "&"] = 5; + global.EQUATION_PRES[? "|"] = 4; + global.EQUATION_PRES[? "^"] = 3; + global.EQUATION_PRES[? "<"] = 3; + global.EQUATION_PRES[? "»"] = 6; + global.EQUATION_PRES[? "«"] = 6; + global.EQUATION_PRES[? "~"] = 9; + + global.EQUATION_PRES[? "="] = -99; + global.EQUATION_PRES[? "⊕"] = -99; //+= + global.EQUATION_PRES[? "⊖"] = -99; //-= + global.EQUATION_PRES[? "⊗"] = -99; //*= + global.EQUATION_PRES[? "⊘"] = -99; ///= + + global.EQUATION_PRES[? "⩵"] = -1; //== + global.EQUATION_PRES[? "≠"] = -1; //!= + global.EQUATION_PRES[? "<"] = 0; + global.EQUATION_PRES[? ">"] = 0; + global.EQUATION_PRES[? "≤"] = 0; + global.EQUATION_PRES[? "≥"] = 0; + + global.EQUATION_PRES[? "@"] = 5; //array accerssor symbol + +#endregion + +#region parser + function functionStringClean(fx) { + static __BRACKETS = [ "(", "[" ]; + + var ch = "", ind = 0, len = string_length(fx); + var _fx = "", str = false; + var _prevSym = true; + + while(ind++ <= len) { + ch = string_char_at(fx, ind); + + if(ch == " ") { + if(str) _fx += ch; + } else { + if(ch == "-" && _prevSym) + _fx += $"0∸"; + else + _fx += ch; + + _prevSym = ds_map_exists(global.EQUATION_PRES, ch) || array_exists(__BRACKETS, ch); + } + + if(ch == "\"") + str = !str; + } + + fx = _fx; + + fx = string_replace_all(fx, "\n", ""); + fx = string_replace_all(fx, "**", "$"); + fx = string_replace_all(fx, "<<", "«"); + fx = string_replace_all(fx, ">>", "»"); + + fx = string_replace_all(fx, "==", "⩵"); + fx = string_replace_all(fx, "!=", "≠"); + fx = string_replace_all(fx, "<>", "≠"); + fx = string_replace_all(fx, ">=", "≥"); + fx = string_replace_all(fx, "<=", "≤"); + + fx = string_replace_all(fx, "++", "⊕1"); + fx = string_replace_all(fx, "--", "⊖1"); + + fx = string_replace_all(fx, "+=", "⊕"); + fx = string_replace_all(fx, "-=", "⊖"); + fx = string_replace_all(fx, "*=", "⊗"); + fx = string_replace_all(fx, "/=", "⊘"); + + fx = string_trim(fx); + + return fx; + } + + function functionStrip(fx) { + var el_st = 1; + var el_ed = 1; + + for( var i = 1; i <= string_length(fx); i++ ) { + var cch = string_char_at(fx, i); + if(cch == "(") { + el_st = i + 1; + break; + } + } + + for( var i = string_length(fx); i >= 1; i-- ) { + var cch = string_char_at(fx, i); + if(cch == ")") { + el_ed = i; + break; + } + } + + return string_copy(fx, el_st, el_ed - el_st) + } + + function evaluateFunctionList(fx) { + fx = string_replace_all(fx, "{", "\n{\n"); + fx = string_replace_all(fx, "}", "\n}\n"); + + var fxs = string_split(fx, "\n", true); + + var flist = new __funcList(); + + var call_st = ds_stack_create(); + var blok_st = ds_stack_create(); + ds_stack_push(call_st, flist); + + for( var i = 0, n = array_length(fxs); i < n; i++ ) { + var _fx = functionStringClean(fxs[i]); + //print($"Eval line {i}: {_fx} [stack size = {ds_stack_size(call_st)}]"); + + if(_fx == "" || _fx == "{") continue; + if(_fx == "}") { + ds_stack_pop(call_st); + continue; + } + + var _fx_sp = string_split(_fx, "("); + var _cmd = string_trim(_fx_sp[0]); + var _cond = functionStrip(_fx); + + switch(_cmd) { + case "if": + var con_if = new __funcIf(); + con_if.condition = evaluateFunctionTree(_cond); + ds_stack_top(call_st).addFunction(con_if); + ds_stack_push(call_st, con_if.if_true); + ds_stack_push(blok_st, con_if); + continue; + case "elseif": + var con_if = ds_stack_pop(blok_st); + var con_elif = new __funcIf(); + con_elif.condition = evaluateFunctionTree(_cond); + + con_if.if_false.addFunction(con_elif); + ds_stack_push(call_st, con_elif.if_true); + ds_stack_push(blok_st, con_elif); + continue; + case "else": + var con_if = ds_stack_pop(blok_st); + + ds_stack_push(call_st, con_if.if_false); + continue; + case "for": + var con_for = new __funcFor(); + var cond = string_splice(_cond, ":"); + if(array_length(cond) == 2) { + con_for.itr_array = true; + con_for.cond_arr = evaluateFunctionTree(cond[1]); + + cond[0] = string_trim(cond[0]); + var _itr = string_split(cond[0], ","); + if(array_length(_itr) == 1) + con_for.cond_iter = cond[0]; + else if(array_length(_itr) == 2) { + con_for.cond_indx = string_trim(_itr[0]); + con_for.cond_iter = string_trim(_itr[1]); + } + } else if(array_length(cond) == 3) { + con_for.itr_array = false; + con_for.cond_init = evaluateFunctionTree(cond[0]); + con_for.cond_iter = evaluateFunctionTree(cond[1]); + con_for.cond_term = evaluateFunctionTree(cond[2]); + } + ds_stack_top(call_st).addFunction(con_for); + ds_stack_push(call_st, con_for.action); + continue; + } + + if(ds_stack_empty(call_st)) { + print("Block stack empty, how?"); + } else { + var _top = ds_stack_top(call_st); + _top.addFunction(evaluateFunctionTree(_fx)); + } + } + + ds_stack_destroy(call_st); + ds_stack_destroy(blok_st); + + return flist; + } + + function evaluateFunctionTree(fx) { + static __BRACKETS = [ "(", ")", "[", "]" ]; + + var pres = global.EQUATION_PRES; + var vl = ds_stack_create(); + var op = ds_stack_create(); + var last_push = ""; + + fx = functionStringClean(fx); + var len = string_length(fx); + var l = 1; + var ch = ""; + var cch = ""; + var _ch = ""; + var in_str = false; + + printIf(global.LOG_EXPRESSION, $"===== Evaluating function: {fx} ====="); + + while(l <= len) { + ch = string_char_at(fx, l); + + //print($"Analyzing {ch}"); + + if(ds_map_exists(pres, ch)) { //symbol is operator + last_push = "op"; + + if(ds_stack_empty(op)) ds_stack_push(op, ch); + else { + var _top = ds_stack_top(op); + if(_top == "(" || ds_map_exists(global.FUNCTIONS, _top) || pres[? ch] > pres[? _top]) { + ds_stack_push(op, ch); + } else { + while(pres[? ch] <= pres[? ds_stack_top(op)] && !ds_stack_empty(op)) + ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); + ds_stack_push(op, ch); + } + } + + l++; + } else if (ch == "(") { + if(last_push == "fn") ds_stack_push(op, [ "〚", ds_stack_size(vl) ]); + else ds_stack_push(op, ch); + last_push = "op"; + l++; + } else if (ch == ")") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_pop(op); + if(_top == "(") break; + if(is_array(_top) && _top[0] == "〚") { + var arr = []; + while(ds_stack_size(vl) > _top[1]) + array_insert(arr, 0, ds_stack_pop(vl)); + + ds_stack_push(vl, new __funcTree(ds_stack_pop(op), arr)); + break; + } + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else if (ch == "[") { + if(last_push == "vl") { + ds_stack_push(op, "@"); + ds_stack_push(op, ch); + } else + ds_stack_push(op, [ "{", ds_stack_size(vl) ]); + + last_push = "op"; + l++; + } else if (ch == "]") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_pop(op); + if(_top == "[") break; + if(is_array(_top) && _top[0] == "{") { + var arr = []; + while(ds_stack_size(vl) > _top[1]) + array_insert(arr, 0, ds_stack_pop(vl)); + ds_stack_push(vl, new __funcTree("【", arr)); + break; + } + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else if (ch == ",") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_top(op); + if(_top == "[" || _top == "(" || (is_array(_top) && _top[0] == "{")) break; + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else { + var vsl = ""; + + while(l <= len) { + cch = string_char_at(fx, l); + if(ds_map_exists(pres, cch) || array_exists(__BRACKETS, cch)) break; + if(cch == ",") { + l++; + break; + } + + vsl += cch; + l++; + } + + if(vsl == "") continue; + + if(ds_map_exists(global.FUNCTIONS, vsl)) { //function + ds_stack_push(op, vsl); + last_push = "fn"; + } else { + vsl = string_trim(vsl); + + switch(vsl) { + case "e" : ds_stack_push(vl, 2.71828); break; + case "pi": ds_stack_push(vl, pi); break; + default : ds_stack_push(vl, isNumber(vsl)? toNumber(vsl) : vsl); break; + } + + last_push = "vl"; + } + } + + //print($"op: {ds_stack_size(op)}; vl: {ds_stack_size(vl)}"); + + _ch = ch; + } + + while(!ds_stack_empty(op)) + ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); + + var tree = ds_stack_empty(vl)? noone : ds_stack_pop(vl); + + ds_stack_destroy(op); + ds_stack_destroy(vl); + + if(!is_struct(tree)) + tree = new __funcTree("", tree); + + printIf(global.LOG_EXPRESSION, tree); + printIf(global.LOG_EXPRESSION, ""); + + return tree; + } + + function buildFuncTree(operator, vl) { + if(ds_stack_empty(vl)) return noone; + + if(ds_map_exists(global.FUNCTIONS, operator)) { + if(ds_stack_empty(vl)) + return noone; + + var _v1 = ds_stack_pop(vl); + return new __funcTree(operator, _v1); + } + + switch(operator) { + case "@": + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree(operator, _v2, _v1); + + case "-": + case "∸": + + case "+": //binary operators + case "*": + case "$": + case "/": + case "%": + + case "|": + case "&": + case "^": + case "»": + case "«": + + case "=": + case "⩵": + case "≠": + case "≤": + case "≥": + case "<": + case ">": + + case "⊕": + case "⊖": + case "⊗": + case "⊘": + + if(ds_stack_size(vl) >= 2) { + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree(operator, _v2, _v1); + } + + default: return new __funcTree(operator, ds_stack_pop(vl)); + } + + return noone; + } +#endregion \ No newline at end of file diff --git a/scripts/string_eval/string_eval.yy b/scripts/pcx_parse/pcx_parse.yy similarity index 88% rename from scripts/string_eval/string_eval.yy rename to scripts/pcx_parse/pcx_parse.yy index 94ab13beb..f8c92eacb 100644 --- a/scripts/string_eval/string_eval.yy +++ b/scripts/pcx_parse/pcx_parse.yy @@ -1,7 +1,7 @@ { "resourceType": "GMScript", "resourceVersion": "1.0", - "name": "string_eval", + "name": "pcx_parse", "isCompatibility": false, "isDnD": false, "parent": { diff --git a/scripts/pxl_server/pxl_server.gml b/scripts/pcx_server/pcx_server.gml similarity index 100% rename from scripts/pxl_server/pxl_server.gml rename to scripts/pcx_server/pcx_server.gml diff --git a/scripts/pcx_server/pcx_server.yy b/scripts/pcx_server/pcx_server.yy new file mode 100644 index 000000000..f08291ab2 --- /dev/null +++ b/scripts/pcx_server/pcx_server.yy @@ -0,0 +1,11 @@ +{ + "resourceType": "GMScript", + "resourceVersion": "1.0", + "name": "pcx_server", + "isCompatibility": false, + "isDnD": false, + "parent": { + "name": "eval", + "path": "folders/functions/eval.yy", + }, +} \ No newline at end of file