Preprocessing for WeiDU

Multi-language server and extension for vscode-based editors. Supports various Infinity Engine and Fallout syntaxes.
Post Reply
User avatar
Magus
Site Admin
Posts: 474
Joined: Mon Nov 21, 2016 9:13 am
Contact:

Preprocessing for WeiDU

Post by Magus »

After being annoyed with WeiDU syntax verboseness for some time, I decided to try and add some preprocessing and/or templating capabilities to MLS/IElib.

Gcc was my first thought, being one the most common preprocessors, and that's what I went with.

Some example snippets:

BAF

Code: Select all

IF
  See(NearestEnemyOf(Myself))
  Global("abi_dalzim","LOCALS",0)
  LevelGT(LastSeenBy(Myself),15) // Level 16+
  !GlobalTimerNotExpired("delay","LOCALS")
THEN
 RESPONSE #100
    SetGlobalTimer("delay","LOCALS",6)
    IncrementGlobal("doomed","LOCALS",1)
    IncrementGlobal("abi_dalzim","LOCALS",1)
    ReallyForceSpell(NearestEnemyOf(Myself),WIZARD_ABI_DALZIMS_HORRID_WILTING)
END

IF
  See(NearestEnemyOf(Myself))
  Global("efreeti","LOCALS",0)
  LevelGT(LastSeenBy(Myself),15) // Level 16+
  !GlobalTimerNotExpired("delay","LOCALS")
THEN
  RESPONSE #100
    SetGlobalTimer("delay","LOCALS",6)
    IncrementGlobal("doomed","LOCALS",1)
    IncrementGlobal("efreeti","LOCALS",1)
    ReallyForceSpell(Myself,WIZARD_SUMMON_EFREET)
END

IF
  See(NearestEnemyOf(Myself)
  Global("sunfire","LOCALS",0)
  LevelGT(LastSeenBy(Myself),15) // Level 16+
  !GlobalTimerNotExpired("delay","LOCALS")
THEN
  RESPONSE #100
    SetGlobalTimer("delay","LOCALS",6)
    IncrementGlobal("doomed","LOCALS",1)
    IncrementGlobal("sunfire","LOCALS",1)
    ReallyForceSpell(NearestEnemyOf(Myself),WIZARD_SUN_FIRE)
END

gcc equivalent

Code: Select all

#define HASH1 # // special character shenanigans
#define HASH2(x) x
#define cast_spell_level(SYMBOL, TARGET, SPELL_VAR, MIN_LEVEL) \
IF \
  See(NearestEnemyOf(Myself)) \
  Global(#SPELL_VAR,"LOCALS",0) \
  LevelGT(LastSeenBy(Myself),MIN_LEVEL) \
  !GlobalTimerNotExpired("delay","LOCALS") \
THEN \
  RESPONSE HASH2(HASH1)100 \
    SetGlobalTimer("delay","LOCALS",6) \
    IncrementGlobal("doomed","LOCALS",1) \
    IncrementGlobal(#SPELL_VAR,"LOCALS",1) \
    ReallyForceSpell(SYMBOL, TARGET) \
END

cast_spell_level(WIZARD_ABI_DALZIMS_HORRID_WILTING, NearestEnemyOf(Myself), abi_dalzim, 15)
cast_spell_level(WIZARD_SUMMON_EFREET, Myself, efreeti, 15)
cast_spell_level(WIZARD_SUN_FIRE, Myself, sunfire, 15)

Of course, complex baf is already dominated by SSL, so this is mostly useful in less complex scripts.
But on the other hand, the applications are not limited to baf.

Code: Select all

// never again confuse "GLOBAL" and "LOCALS" types
#define LocalGT(x,y) GlobalGT(x, "LOCALS", y)
IF
  LocalGT("my_var", value)
  ...

TP2

Code: Select all

// just because I'm tired of typing COPY_EXISING_REGEXP all the time
#define copy_er COPY_EXISING_REGEXP
copy_er GLOB ~*.itm~ ~override~

Code: Select all

// or take it further
#include header.h
// header.h:
#define POUND1 $ // more shenanigans
#define POUND2(x,y) x ## y
#define POUND3(x,y) POUND2(x,y)
#define POUND_APPEND(x) POUND3(x,POUND1)
#define copy_erg(FILE_EXT) COPY_EXISTING_REGEXP GLOB ~^.+\.POUND_APPEND(FILE_EXT)~ ~override~
// end header.h

// actual code
copy_erg(dlg)
  DECOMPILE_AND_PATCH BEGIN x = 0 END
BUT_ONLY

D

Code: Select all

// this is too long...
IF ~~ study1
  SAY @14
  IF ~OR(2) Global("wm_book_spell","LOCALS",0) Global("wm_book_spell","LOCALS",1)~ REPLY @20 GOTO 00 // -> +6 = 6/7
  IF ~OR(2) Global("wm_book_spell","LOCALS",0) Global("wm_book_spell","LOCALS",6)~ REPLY @22 GOTO 02 // -> +1 = 1/7
  IF ~OR(2) Global("wm_book_spell","LOCALS",7) Global("wm_book_spell","LOCALS",8)~ REPLY @23 GOTO 03 // -> +2 = 9/10
  IF ~OR(2) Global("wm_book_spell","LOCALS",7) Global("wm_book_spell","LOCALS",9)~ REPLY @24 GOTO 04 // -> +1 = 8/10

// how about this
#define if_node(value1, value2, tra, goto) \
  IF ~OR(2) Global("wm_book_spell","LOCALS",value1) Global("wm_book_spell","LOCALS",value2)~ REPLY tra GOTO goto

IF ~~ study1
  SAY @14
  if_node(0,1,@20,00)
  if_node(0,6,@22,02)
  if_node(7,8,@23,03)
  if_node(7,9,@20,04)

Technically, all this already can be done manually with command line. But with some glue code in various places it could be automated similarly to how SSL works.

To be clear, gcc with its c++ heritage is not "great" for weidu. But weidu syntaxes are unique and diverse enough that according to my analysis, there's no preprocessor or templating engine that is "great". The reason to choose it is that it's very common, simple to use, has lots of documentation and examples, and easy to implement too. That makes it a good starting point, from which the feature can improve.

So, I added rudimentary support for gcc preprocessing to MLS. To make use of it, add ".tpl" extension to the file (".baf.tpl", ".tpa.tpl", etc). Press CTRL+R to preprocess and parse. "test.baf.tpl" will be preprocessed into "test.baf", then test.baf will be parsed with weidu normally.
Of course, this is still pretty manual - each file has to be preprocessed separately. But it's just a start. It can be improved later with various techniques.
(Also, you need gcc in system PATH for this to work).

This feature is tech preview. It may get changed or removed later on. I'm entertaining various ideas, and welcome feedback, help moreso.
Please do not PM or email me about my mods and projects. Use forums. Also, see our talk channels.
Post Reply