Jump to content

How to build WeiDU arrays dynamically ?


argent77

Recommended Posts

I'd like to build an array dynamically from lines read from a text file. I thought the following code would accomplish that:

DEFINE_ACTION_FUNCTION READ_LINES
RET
  lines
BEGIN
  COPY - ~testfile.txt~ ~testfile.txt~
    READ_ASCII 0 text (SOURCE_SIZE)
    INNER_PATCH_SAVE null_char ~ ~ BEGIN WRITE_BYTE 0 0 END
    INNER_PATCH_SAVE text ~%text%~ BEGIN  
      REPLACE_TEXTUALLY ~\(%WNL%\)\|\(%LNL%\)\|\(%MNL%\)~ ~%null_char%~
    END
    INNER_PATCH ~%text%~ BEGIN
      SET strlen = STRING_LENGTH ~%text%~
      SET ofs = 0
      SET idx = 0
      WHILE (ofs < strlen) BEGIN
        READ_ASCII ofs line ELSE ~~ (strlen - ofs) NULL
        TEXT_SPRINT $EVAL lines(~%idx%~) ~%line%~
        SET idx += 1
        SET ofs += (STRING_LENGTH ~%line%~) + 1
      END
    END
END

LAF READ_LINES RET lines END
ACTION_PHP_EACH lines AS _ => line BEGIN
  PRINT ~Line: %line%~
END

But it only triggers the following error message when I execute it:

ERROR: Failure("Uninitialised return value: lines")


The WeiDU docs are very sparse when it comes to array constructs. Am I missing something?

Link to comment

EDIT - I didn't understand the question properly, ignore me...

 

You could give your text file a .2da extension and then do stuff like

 

COPY ~text.2da~

COUNT_2DA_ROWS rows

FOR (row = 1 ; row < rows ; ++rows)

READ_2DA_ENTRY row 0 1 ~first~

ACTION_DEFINE_ASSOCIATIVE_ARRAY ~lines~ ...

...etc.

Link to comment

It looks like the issue is caused by the array construct itself. Even static arrays returned by a function are triggering this error message:

DEFINE_ACTION_FUNCTION READ_LINES
RET
  lines
BEGIN
  ACTION_DEFINE_ARRAY lines BEGIN ~first line~ ~second line~ ~third line~ END
END

LAF READ_LINES RET lines END    // triggers error message: ERROR: Failure("Uninitialised return value: lines")


Is there a working method for returning arrays or what can be used as an alternative option to return a variable number of strings from a function?

Link to comment

The function's output is kinda broken, RET will fail unless the exact variable gets set in the function. Feel free to ask Wisp to adjust it, I asked Bigg twice but here we are still :) The other half of the problem is that RET interprets "lines" as a string, not array.

In other words, you can't build an array with a function and then access it in outside environment. Use macro instead - you'll have to manually initialize and clear any internal variables, but the array itself will be accessible outside of it.

 

PS I suppose, you could also make a function that will write new functions from a blueprint and run them via REINCLUDE, one per item, but macro is probably easier.

 

PPS Or, if you're comfortable with parsing a text file, you could instead morph it into array definition code and then run normally.

Link to comment

Frankly, since you only replace the line breaks, you should be able to achieve the same effect by just wrapping the list into

ACTION_DEFINE_ARRAY lines BEGIN
// testfile.txt contents
END

and INCLUDE'ing it as tph.

Link to comment

How exactly would I do this? Isn't DEFINE_ARRAY only useful for defining static arrays?

 

Btw, I have only posted a simplified example in my first post. I'm also doing some filtering. The full code is (currently):

 

DEFINE_PATCH_MACRO GET_WEIDU_LINES
// RET weiduEntries
BEGIN
  LOCAL_TEXT_SPRINT weidu ~~
  LOCAL_TEXT_SPRINT null_char ~ ~
  LOCAL_TEXT_SPRINT regWeidu ~~
  LOCAL_SET curIdx = 0
  LOCAL_SET strlen = 0
  LOCAL_SET ofs = 0

  READ_ASCII 0 weidu (SOURCE_SIZE)
  INNER_PATCH_SAVE null_char ~%null_char%~ BEGIN WRITE_BYTE 0 0 END
  INNER_PATCH_SAVE weidu ~%weidu%~ BEGIN
    REPLACE_TEXTUALLY ~\(%WNL%\)\|\(%LNL%\)\|\(%MNL%\)~ ~%null_char%~
  END
  INNER_PATCH ~%weidu%~ BEGIN
    TEXT_SPRINT regWeidu "^[%TAB% ]*\(~[^~]+~[%TAB% ]*#[0-9]+[%TAB% ]*#[0-9]+\).*$"
    SET strlen = STRING_LENGTH ~%weidu%~
    WHILE (ofs < strlen) BEGIN
      READ_ASCII ofs line ELSE ~~ (strlen - ofs) NULL
      PATCH_IF (~%line%~ STRING_MATCHES_REGEXP ~%regWeidu%~ = 0) BEGIN
        INNER_PATCH_SAVE line ~%line%~ BEGIN
          REPLACE_TEXTUALLY ~%regWeidu%~ ~\1~
        END
        TEXT_SPRINT $EVAL weiduEntries(~%curIdx%~) ~%line%~
        SET curIdx += 1
      END
      SET ofs += (STRING_LENGTH ~%line%~) + 1
    END
  END
END

COPY - ~weidu.log~ ~weidu.log~
  LPM GET_WEIDU_LINES

ACTION_PHP_EACH weiduEntries AS _ => weiduEntry BEGIN
  // ...
END

 

Link to comment
Isn't DEFINE_ARRAY only useful for defining static arrays?

 

DEFINE_ARRAY is more like a shortcut for a batch of SET $array("index")=value actions, than anything else. You can initiate D_A, then append it with several manual SETs/SPRINTs, then partially overwrite and/or append with another D_A, and WeiDU will still take it.

 

The only thing it can't do is to change the range of PHP_EACH action while it's running, i.e. although you still can append the array with new entries, only the subsequent PHP_EACH will be able to grab them. Beside that, everything is pretty much as dynamic as it can get.

 

Btw, I have only posted a simplified example in my first post. I'm also doing some filtering.

 

Ah. I thought you were only reading a list of simple strings :)

 

By the way, if you're later disassembling the entry into text and strrefs, you can set them as separate arguments when reading from file (not sure it can actually evaluate like this, but you should get the idea):

 

 

INNER_PATCH ~%weidu%~ BEGIN
  TEXT_SPRINT regWeidu "^[%TAB% ]*\(~\([^~]+\)~[%TAB% ]*#\([0-9]+\)[%TAB% ]*#\([0-9]+\)\).*$"
  SET strlen = STRING_LENGTH ~%weidu%~
  WHILE (ofs < strlen) BEGIN
    READ_ASCII ofs line ELSE ~~ (strlen - ofs) NULL
    PATCH_IF (~%line%~ STRING_MATCHES_REGEXP ~%regWeidu%~ = 0) BEGIN
      INNER_PATCH_SAVE line ~%line%~ BEGIN
        REPLACE_TEXTUALLY ~%regWeidu%~ ~\1~
      END
      TEXT_SPRINT $EVAL weiduEntries(~%curIdx%~ ~\3~ ~\4~) ~\2~
      SET curIdx += 1
    END
    SET ofs += (STRING_LENGTH ~%line%~) + 1
  END
END

// ...

ACTION_PHP_EACH weiduEntries AS idx => weiduEntry BEGIN
  // curidx = idx
  strref1 = idx_1
  strref2 = idx_2
  SPRINT text ~%weiduEntry%~
  // ...
END

 

 

Link to comment

Sounds like an interesting approach. I'm currently splitting each entry with three separate REPLACE_TEXTUALLY calls.

 

Edit: I couldn't get it to work. Since RegExp groups can only be captured within the action that processed the regular expression (such as REPLACE_TEXTUALLY) it would require multiple PATCH_SAVE blocks anyway.

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...