Re: Architectural Discussion: Implementing ECS and Data-Oriented Programming (DOP)
- Posted by jmduro 3 weeks ago
- 195 views
Here is the class library:
namespace classes -- classes.e -- do not modify this file ------------------------------------------------------------------------------ -- INTERNAL CONSTANTS ------------------------------------------------------------------------------ constant CLASS_NAME =1, CLASS_PROPERTY=2, CLASS_METHOD=3 constant PROPERTY_NAME=1, PROPERTY_VALUE=2 constant METHOD_NAME =1, METHOD_ROUTINE_ID=2 constant ENTITY_CLASS =1, ENTITY_VALUES=2 ------------------------------------------------------------------------------ -- GLOBAL CLASS FUNCTIONS ------------------------------------------------------------------------------ -- define a Class public function class(sequence className) return {className, {}, {}} end function ------------------------------------------------------------------------------ -- define a Class property public function addProperty(sequence class, sequence propertyName, object defaultValue) class[CLASS_PROPERTY] = append(class[CLASS_PROPERTY], {propertyName, defaultValue}) return class end function ------------------------------------------------------------------------------ -- define a Class method public function addMethod(sequence class, sequence methodName, integer routineId) class[CLASS_METHOD] = append(class[CLASS_METHOD], {methodName, routineId}) return class end function ------------------------------------------------------------------------------ -- find property public function findProperty(sequence class, sequence property) for i = 1 to length(class[CLASS_PROPERTY]) do if equal(property, class[CLASS_PROPERTY][i][PROPERTY_NAME]) then return i end if end for return 0 end function ------------------------------------------------------------------------------ -- find method routine_id public function findMethod(sequence class, sequence method) for i = 1 to length(class[CLASS_METHOD]) do if equal(method, class[CLASS_METHOD][i][METHOD_NAME]) then return class[CLASS_METHOD][i][METHOD_ROUTINE_ID] end if end for return 0 end function ------------------------------------------------------------------------------ -- GLOBAL ENTITY FUNCTIONS ------------------------------------------------------------------------------ -- create an Entity of the class public function new(sequence class) sequence values = {} for i = 1 to length(class[CLASS_PROPERTY]) do values = append(values, class[CLASS_PROPERTY][i][PROPERTY_VALUE]) end for return {class, values} end function ------------------------------------------------------------------------------ -- get property value public function getProperty(sequence entity, sequence property, object defaultValue=0) integer propertyID = findProperty(entity[ENTITY_CLASS], property) if propertyID then return entity[ENTITY_VALUES][propertyID] end if return defaultValue end function ------------------------------------------------------------------------------ -- set property value public function setProperty(sequence entity, sequence property, object val) integer propertyID = findProperty(entity[ENTITY_CLASS], property) if propertyID then entity[ENTITY_VALUES][propertyID] = val end if return entity end function ------------------------------------------------------------------------------ -- call a method (function) within an Entity public function callMethod(sequence entity, sequence method, object methodParams= {}) integer methodID = findMethod(entity[ENTITY_CLASS], method) if methodID then return call_func(methodID, {entity, methodParams}) end if return -1 end function
And an outdated version of the preprocessor that I began to update but I did not finish the job because noone was interested in.
include std/io.e include std/text.e include std/regex.e include std/search.e include std/sequence.e include std/datetime.e include std/console.e include common.e constant ATTR=1, PROC=2, FUNC=3 ------------------------------------------------------------------------------ function get_next_non_white(sequence code, integer from) -- skip white while (code[from] = ' ') or (code[from] = '\t') do from += 1 if from > length(code) then return 0 end if end while return from end function ------------------------------------------------------------------------------ function manage_routine(sequence code, sequence lines, integer start) integer from, upto for i = start+1 to length(lines) do if begins("end ", trim(lines[i])) then code &= lines[i] & "\n" start = i exit end if sequence rule = "self\\.([_A-Za-z][_A-Za-z0-9]*)" -- puts(f_out, rule & "\n") regex r = regex:new(rule) object found = regex:find_all(r, lines[i]) if sequence(found) then for j = 1 to length(found) do {from, upto} = found[j][2] sequence name = lines[i][from..upto] {from, upto} = found[j][1] lines[i] = replace(lines[i], sprintf("entity[%s]", {upper(name)}), from, upto) end for code &= lines[i] & "\n" puts(f_debug, lines[i] & "\n") end if end for return {code, start} end function ------------------------------------------------------------------------------ procedure main(sequence cmd) f_debug = open(InitialDir & "debug.log", "w") debug_level = DEBUG debug_time_stamp = 0 sequence inFileName, outFileName for i = 3 to length(cmd) do switch cmd[i] do case "-i" then inFileName = cmd[i+1] case "-o" then outFileName = cmd[i+1] end switch end for integer f_out = open(outFileName, "w") sequence lines = read_lines(inFileName) integer from, upto object found, found2 sequence class_name = "", name, params, elements = {} integer start = 0 sequence code = "" -- find class definition regex r = regex:new("class (.*)$") for i = 1 to length(lines) do puts(f_debug, lines[i] & "\n") found = regex:find(r, lines[i]) if sequence(found) then {from, upto} = found[2] class_name = lines[i][from..upto] start = i exit else code &= lines[i] & "\n" end if end for -- add target sequence attributes code &= "enum type %ENUM_TYPE% %ENUM_ITEMS% end type\n\n" code &= "sequence %CLASS_NAME% = {%CLASS_CONTENT%}\n\n" -- analyze class definition sequence enums = {} sequence class_definition = {} integer i = start+1 while i <= length(lines) do sequence trimmed = trim(lines[i]) puts(f_debug, lines[i] & "\n") if match("end class", lines[i]) then start = i exit end if if begins("integer", trimmed) then r = regex:new("integer (.*)$") class_definition= append(class_definition, "0") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) elements = append(elements, {name, ATTR}) elsif begins("atom", trimmed) then r = regex:new("atom (.*)$") class_definition= append(class_definition, "0.0") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) elements = append(elements, {name, ATTR}) elsif begins("sequence", trimmed) then r = regex:new("sequence (.*)$") class_definition= append(class_definition, "\"\"") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) elements = append(elements, {name, ATTR}) elsif begins("object", trimmed) then r = regex:new("object (.*)$") class_definition= append(class_definition, "0") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) elements = append(elements, {name, ATTR}) elsif begins("datetime", trimmed) then r = regex:new("datetime (.*)$") class_definition= append(class_definition, "now()") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) elements = append(elements, {name, ATTR}) elsif begins("procedure", trimmed) then r = regex:new("procedure (.*)\\((.*)\\)$") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) {from, upto} = found[3] params = lines[i][from..upto] code &= sprintf("procedure %s(sequence entity, sequence params)\n", {name}) {code, i} = manage_routine(code, lines, i) elements = append(elements, {name, PROC}) elsif begins("function", trimmed) then r = regex:new("function (.*)\\((.*)\\)$") found = regex:find(r, lines[i]) {from, upto} = found[2] name = lines[i][from..upto] enums = append(enums, upper(name)) {from, upto} = found[3] params = lines[i][from..upto] code &= sprintf("function %s(sequence entity, sequence params)\n", {name}) {code, i} = manage_routine(code, lines, i) elements = append(elements, {name, FUNC}) elsif begins("end procedure", trimmed) then class_definition= append(class_definition, "0") code &= lines[i] & "\n" code &= sprintf("%s[%s] = routine_id(\"%s\")\n", {class_name, upper(name), name}) elsif begins("end function", trimmed) then class_definition= append(class_definition, "0") code &= lines[i] & "\n" code &= sprintf("%s[%s] = routine_id(\"%s\")\n", {class_name, upper(name), name}) else common:error_message("Unexpected variable type!", 1) end if i += 1 end while analyze_object(class_definition, class_name, DEBUG) analyze_object(enums, "enums", DEBUG) -- replace target sequence attributes code = replace_all(code, "%ENUM_TYPE%", upper(class_name)) code = replace_all(code, "%ENUM_ITEMS%", join(enums, ',')) code = replace_all(code, "%CLASS_NAME%", class_name) code = replace_all(code, "%CLASS_CONTENT%", join(class_definition, ',')) -- add converted code puts(f_out, code) -- add internal functions puts(f_out, "\n") puts(f_out, "procedure class_proc(sequence entity, integer method, sequence params = {})\n") puts(f_out, " call_proc(entity[method], {entity, params})\n") puts(f_out, "end procedure\n") puts(f_out, "\n") puts(f_out, "function class_func(sequence entity, integer method, sequence params = {})\n") puts(f_out, " return call_func(entity[method], {entity, params})\n") puts(f_out, "end function\n") puts(f_out, "\n") -- manage class entities sequence entity_name = "" sequence entities = "" for l = start+1 to length(lines) do -- lines[l] = trim(lines[l]) puts(f_debug, lines[l] & "\n") sequence rule = sprintf("sequence (.*) = new\\(%s\\)$", {class_name}) -- puts(f_out, rule & "\n") r = regex:new(rule) found = regex:find(r, lines[l]) if sequence(found) then {from, upto} = found[2] entity_name = lines[l][from..upto] entities = append(entities, entity_name) printf(f_out, "sequence %s = %s\n", {entity_name, class_name}) else r = regex:new("([_A-Za-z0-9]*)\\.([_A-Za-z0-9]*)") found = regex:find(r, lines[l]) if sequence(found) then {from, upto} = found[2] entity_name = lines[l][from..upto] if find(entity_name, entities) then -- class referenced -- check if it refers to a routine {from, upto} = found[3] name = lines[l][from..upto] {from, upto} = found[1] integer p = vlookup(name, elements, 1, 2, 0) printf(f_debug, "p = %d\n", {p}) switch p do case ATTR then lines[l] = replace(lines[l], sprintf("%s[%s]", {entity_name, upper(name)}), from, upto) case PROC then from = find('(', lines[l], upto+1) upto = find(')', lines[l], upto+1) if upto > from+1 then params = lines[l][from+1..upto-1] else params = {} end if lines[l] = sprintf("class_proc(%s, %s, %s)\n", {entity_name, upper(name), params}) case FUNC then from = find('(', lines[l], upto+1) upto = find(')', lines[l], upto+1) if upto > from+1 then params = lines[l][from+1..upto-1] else params = {} end if lines[l] = sprintf("class_proc(%s, %s, %s)\n", {entity_name, upper(name), params}) case else end switch end if end if puts(f_out, lines[l] & "\n") end if end for analyze_object(entities, "entities", DEBUG) close(f_out) close(f_debug) end procedure -- main ------------------------------------------------------------------------------ -- Main main(command_line()) maybe_any_key()
As it was a work in progress, I'm not sure it runs again without modifications.
Jean-Marc

