Skip to content
Browse files

Initial thoughts and design for the Gribble language.

  • Loading branch information...
1 parent 84dc584 commit 4221782ee367b4172cf43de90a7b79cc51cc62bf @BurntSushi committed
Showing with 110 additions and 0 deletions.
  1. +110 −0 GRIBBLE
View
110 GRIBBLE
@@ -0,0 +1,110 @@
+Some very preliminary notes on Gribble so I can get them out of my head.
+
+Goal
+====
+Gribble will be a very simple domain specific language to interact with Wingo.
+The idea is to provide a parser that works with Go structs and the reflect
+package to infer the signature of a command. (It should work in a similar
+fashion as the json and xml Go standard library packages.)
+
+The idea is that there will be a central parser that takes as input a string
+(one or more commands) and a slice of all possible commands (represented as
+structs) and returns one command from that slice that matches the input string
+or no commands on error (if the input string cannot be matched to one of the
+given command structs).
+
+So that one can define a command like so:
+
+type Move struct {
+ name string `Move`
+ client Command `1`
+ x int `2`
+ y int `3`
+}
+
+Where name must match "Move"; the name of the command. 'client' is itself a
+command that can return a value (in this case, a client id), and is the first
+argument. 'x' and 'y' are the coordinates to move 'client' to, and are the
+second and third arguments. An example of a program using the "Move" command:
+
+ Move (FocusedClient) 100 200
+
+Which ought to move the currently focused client to the position (100, 200).
+The implementation of Move can be in a method:
+
+func (cmd Move) Run() interface{} {
+ switch clientId := cmd.client.Run().(type) {
+ case int:
+ focus.Focus(findClient(clientId))
+ }
+}
+
+Which should be part of the Command interface:
+
+type Command interface {
+ Run() interface{}
+}
+
+Return values
+=============
+As I mention below, allowing commands as valid command arguments makes Gribble
+much more flexible and reusable. But it requires that commands are able to
+produce return values.
+
+In Wingo, the vast majority of commands are executed for a state-changing
+effect (moving windows, focusing another window, switching workspaces, etc.)
+But sometimes the user wants to query Wingo for state (list the clients and
+their geometry please), or perhaps the user wants to query Wingo for state and
+use the return value in another command.
+
+A perfect example of this is to ask Wingo to move the currently focused wingo.
+One could combine a "FocusedClient" command with a "Move" command (as shown
+above). In this case, the nature of the return value is known by the caller
+(i.e., "Move"), and so it can type switch to extract that value.
+
+But what if the user wants to use a command and print its result?
+
+The key to doing this is to always return values that implement the Stringer
+interface. For example, consider the "ListClientIds" command that returns a
+list of all client window identifiers. So we can define a client id list:
+
+type ClientIds []ClientId
+
+And implement the Stringer interface (assuming ClientId implements Stringer):
+
+func (cids ClientIds) String() string {
+ return strings.Join(cids, " ")
+}
+
+And thus, one need only to print the return value of any command to get a
+reasonable visual form.
+
+Organization
+============
+I really think I could use a domain specific language in areas other than
+window managing in the future, so I would like to put the parser and interface
+definitions in a separate package. Then a client or "user" of the package
+simply has to write types that implement the Command interface and pass a slice
+of them (and a Gribble program) to the parser.
+
+The central design choice that allows Gribble to be reusable is sub-commands
+(namely, commands can be used as arguments to other commands).
+This prevents Wingo-specific hacks to gather state (like what the currently
+focused client is) inside the parser.
+
+Grammar
+=======
+A feeble attempt at a grammar:
+
+program = command, { ";" command } ;
+
+command = [ "(" ], identifier, { param }, [ ")" ] ;
+
+param = { alpha | digit } | "(" command ")" ;
+
+identifier = "A" | ... | "Z", { alpha | digit } ;
+
+alpha = "A" | ... | "Z" | "a" | ... | "z"
+
+digit = "0" | ... | "9"
+

0 comments on commit 4221782

Please sign in to comment.
Something went wrong with that request. Please try again.