Bundle LPeg (and ICU4Lua?)

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Bundle LPeg (and ICU4Lua?)

Post by aubergine18 »

I'm working on a GUI abstraction layer that uses a domain specific language; it's likely that I'll need to use LPeg for accurate (and maintainable) parsing of the DSL. Could LPeg be bundled with Factorio?

A rough example (WIP) of creating a dialog using the DSL:

Code: Select all

Design
  '@dlgContent' [[
      label #msg 'dlg-label'
  ]]
  
  '@dlgButtons' [[
      button #cancel  'dlg-button-cancel' .btn-cancel
      button #confirm 'dlg-button-ok'     .btn-confirm
  ]]
--      ↑        ↑          ↑                  ↑
--     type     name     caption             style
  
local dlg = Dialog 'Hello World' '@dlgContent' '@dlgButtons'

dlg.on('close', function(eventName,eventData) {
  game.player.print eventData.button.caption -- localised caption of button clicked
}

dlg.show() -- defaults to local player (player 1)
The UI chunks are "compiled" only once (by LPeg), when the game starts, turning them in to a Lua table representation of the DSL. The 'compiled' tables are set up for fast runtime use. Each time the UI needs to be shown, it's a simple matter of passing the table to a function that renders the UI using LuaGui and LuaGuiElement.

Using this approach, it's possible to create 'custom' components, essentially re-usable UI patterns that mods can incorporate in to their own UI.

I also plan on adding DSLs for defining prototypes in a much simpler, more maintainable manner.

If it's not possible to get LPeg bundled, I can fall back to LulPeg which is written entirely in Lua, but obviously a bit slower than LPeg. Both libraries have identical API, I'm doing my initial dev in LulPeg. There are some weird errors in LulPeg, so if possible I'd really *really* prefer to use the proper LPeg library.

Code: Select all

local success, lpeg = pcall(require, "lpeg")
lpeg = success and lpeg or require "lulpeg":register(not _ENV and _G)
Note: The lpeg.locale features only work on single-byte chars, so if there is a need for UTF-8 support then ICU4Lua will also be needed - I can't find a Lua-only implementation of this so if UTF-8 is required it would definitely need bundling with Factorio (no workarounds available).
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.
User avatar
Adil
Filter Inserter
Filter Inserter
Posts: 945
Joined: Fri Aug 15, 2014 8:36 pm
Contact:

Re: Bundle LPeg (and ICU4Lua?)

Post by Adil »

If you're working on gui-creation library, which is honorable endeavor, wouldn't only modder ever have to deal with dsl anyway?
You could bundle your library with additional application to compile the code into file usable by the game.

Also I can't help but notice that your dsl bears resemblance to moonscript, which is already bundled with to-lua compiler.
I do mods. Modding wiki is friend, it teaches how to mod. Api docs is friend too...
I also update mods, some of them even work.
Recently I did a mod tutorial.
User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: Bundle LPeg (and ICU4Lua?)

Post by aubergine18 »

IIRC, Moonscript also uses LPeg, but I don't think Factorio includes it.

I've just finished the LPeg grammar, complete with error checking - here's a preview:

Image

The parsed 'script' is turned in to a bunch of objects, which are then linked (indentation denotes GUI element hierarchy). I'm now starting on the function that will turn those tables in to the actual rendered GUI (pretty simple - each table will get a metatable assigned based on it's "type", and then calling the table - which triggers the metatable __call event - will render the GUI using the standard Factorio API).
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.
User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: Bundle LPeg (and ICU4Lua?)

Post by aubergine18 »

A summary of the syntax:

Code: Select all

(indent)    -> defines parent/child hierarchy
elementType -> type = 'elementType' (only applies to first keyword)
[val]       -> value = val (typecast as applicable)
#keyword    -> name = '#keyword'
>#keyword   -> target = '#keyword'
@design     -> import = '@design'
!fullpath   -> glyph = 'fullpath'
-- txt      -> tooltip = 'txt'
key=value   -> key = value (typecast as applicable)
'str'       -> caption = 'str'
-keyword    -> keyword = false
keyword     -> keyword = true
.stylesheet -> style = 'stylesheet'
(gibberish) -> Error @ line:char = gibberish
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.
User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: Bundle LPeg (and ICU4Lua?)

Post by aubergine18 »

Initial draft of proxy object properties and operators:

Code: Select all

-- traversal

	p(query) - like jquery for p.fui, returns table of matching p's

	p.id -- #id
	p.fui -- FUI tree that p is in

	-- hierarchy/order
		p.root - the root node for this FUI
		p.parent -- parent proxy (how to deal with top level?)

		p ^ q -- in same FUI?
		p > q -- is p ancestor of q?
		p < q -- is p descendent of q?
		p.sib(q) -- are p and q siblings?
		p == q -- p and q the same?

		-- descendents
			#p -- num direct descendents
			p.descendents -- list of direct descendents

			p + q -- append q descendent to p, return p
			p - q -- remove q descendent from p, return p

			p <= q -- if siblings, reorder q before p, return p
			p >= q -- if siblings, reorder p after q, return p

			pairs(p) -- iterate direct descendents with ids
			ipairs(p) -- iterate all direct descendents in order

-- tagging
	p.tags -- set of tags
	p .. q -- tag p qith q, returs p
	p / q  -- remove tag q from p, returns p
	p % q -- is p tagged with q?

-- rendering

	p.gui -- rendered element (nil if not rendered)
	p.uid -- .name used for the LuaGuiEntity

	p.vsible -- is p rendered? (RW)
	p * q -- set render state of p to q, returns p or nil
		true = visible (rendered),
		false = hidden (not rendered),
		nil = prune

-- general settings
	-p -- get full settings obj
	   -- note: most sttings can be get/set via p[settingName]
	p.caption
	p.player -- player (or nil if not rendered)
	p.state -- toggle state
	p.value -- input value: numeric (progress), boolean (checked state), string (text box)
	p.style -- style sheet *name*
	p.name -- #name
	p.type -- the FUI type (R)
	tostring(p) -- p.type p.id ?
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.
Post Reply

Return to “Modding interface requests”