Skip to content

Commit

Permalink
can-lehmann#115 Update gui-DSL for clearer stateRef Syntax
Browse files Browse the repository at this point in the history
Modifies both parsing the gui-DSL into Node-types as well as generating code from those Node-types.

First it allows parsing expressions such as "<Widget> as <someStateRefVariable>".
This is supposed to express an assignment of <someStateRefVariable>
to the "valStateRef" Field on the <Widget> instance.
The variable gets stored in the "widgetRefVar" field on "Node".
There it is optional, as expressions such as "<Widget>:" without the "as <someStateRefVariable>" syntax will not contain assignments.

The "<Widget> as <someStateRefVariable>" syntax creates an infix expression which is part of nnkCallKinds.
Therefore in parseGui I removed it from the nnkCallKinds group.

In the code-generation step, when generating a NodeWidget there now is a small check if the gui-DSL contained such an assignment. If so, the variable <someStateRefVariable> gets assigned to the Widgets "valStateRef" field.

This is functionally equivalent to just having this syntax:
Widget:
  stateRef = <someStateRefVariable>

But is more readable.
  • Loading branch information
PhilippMDoerner committed Jun 22, 2024
1 parent faa291f commit d06c1cb
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
3 changes: 1 addition & 2 deletions examples/widgets/search_entry.nim
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ method view(app: AppState): Widget =
app.text = ""
app.filteredItems = app.items

ScrolledWindow:
stateRef = app.keyCaptureRef
ScrolledWindow as app.keyCaptureRef:
ListBox:
selectionMode = SelectionSingle
if app.selected < app.filteredItems.len:
Expand Down
36 changes: 34 additions & 2 deletions owlkettle/guidsl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

# Domain-specific language for specifying GUI layouts

import std/[macros, strutils, genasts]
import std/[macros, strutils, genasts, options]
when defined(nimPreviewSlimSystem):
import std/assertions
import common, widgetdef
Expand All @@ -45,6 +45,7 @@ type
of NodeWidget:
widget: seq[string]
adder: Adder
widgetRefVar: Option[NimNode] # Contains a variable of type StateRef that may receive a reference to the constructed widget.
of NodeField:
name: string
value: NimNode
Expand Down Expand Up @@ -82,7 +83,7 @@ proc parseAdder(node: NimNode): Adder =

proc parseGui(node: NimNode): Node =
case node.kind:
of nnkCallKinds:
of nnkCallKinds - {nnkInfix}:
if node[0].unwrapName().eqIdent("insert"):
if node.len != 2:
error("The insert statement must have exactly one argument", node)
Expand All @@ -93,6 +94,28 @@ proc parseGui(node: NimNode): Node =
result = node[0].parseGui()
for it in 1..<node.len:
result.children.add(node[it].parseGui())
of nnkInfix: # For expressions like "<Widget> as <stateRefVariable>"
let asNode = node[0]
let isRefAssignmentExpression = asNode.kind == nnkIdent and $asNode == "as"
if not isRefAssignmentExpression:
error("You can only use infix for assigning stateReferences. That must be done via '<Widget> as <stateRefVariable>' syntax")
let widgetName = node[1]
let widgetRefVar = node[2]
let widgetContent = node[3]

if widgetName.isQualifiedName:
result = Node(
kind: NodeWidget,
widget: widgetName.qualifiedName,
lineInfo: widgetContent,
widgetRefVar: some(widgetRefVar)
)
else:
result = widgetName.parseGui()

for it in 3..<node.len: # Parse content of Widget. Ignore NimNodes for "as", WidgetName and WidgetRefVar
result.children.add(node[it].parseGui())

of nnkPragmaExpr:
if node[0].isQualifiedName:
result = Node(kind: NodeWidget, widget: node[0].qualifiedName, lineInfo: node)
Expand Down Expand Up @@ -220,6 +243,15 @@ proc gen(node: Node, stmts, parent: NimNode) =
body.add(newLetStmt(name, newCall(widgetTyp)))
for child in node.children:
child.gen(body, name)

let hasRefAssignment = node.widgetRefVar.isSome()
if hasRefAssignment:
let refVar = node.widgetRefVar.get()
let refAssignment = quote do:
`name`.hasStateRef = true
`name`.valStateRef = `refVar`
body.add(refAssignment)

if not parent.isNil:
body.add(node.adder.gen(name, parent))
else:
Expand Down

0 comments on commit d06c1cb

Please sign in to comment.