Babbly cover image

Babbly

Babbly is a programming language designed for easily generating texts. The language is used in most of my Twitterbots.

Structures

Disjunctions

Babbly allows for easily specifying several options for slot declarations, e.g., the following example would generate "hello world!", "hello universe!" and "hello earth!".

main = hello <place>!
place = world|universe|earth

Weighted disjunctions

Suppose you want specific options to have a higher probability of being used in generation than others. In that case, you can easily specify this, e.g. in this example, "hello world!" will be generated 80% of the time.

main = hello <place>!
place = {
    8: world
    1: universe,
    1: world
}

Importing files

Importing word lists

A typical design pattern when making such generative grammars is specifying word lists. As such, one can make a .words file where all words are newline separated and import this. It can then be used just like any other declared generator.

firstname.words:

An
Bob
Charlie
Dave

main.decl

import firstname.words

main = hello my name is <firstname>!

Importing declaration files

One can also import other .decl files to import all these declarations.

import proverb_generator.decls

main = My <relative> always used to say: "<proverb>"!
relative = granddad|grandmother|father|mother

From Java

When you run Babbly from Java, you can also pass the generate function as a parameter controlling its initial generator declarations. This way, you can pass arbitrary static strings, other Babbly generators, or even more complex Java string generator functions as a named declaration to the file. This is useful, e.g., for responding to messages or incorporating certain input words.

Regex-like syntax

Babbly also allows several RegEx-inspired shorthands.

Repetition

Placing {n,m} after any part repeats the last part n to m times. The example below would generate "hello", "heello", "heeello", "heeeello" and "heeeeello". Alternatively, brackets can be used to repeat more than just a letter.

main = He{1,5}llo

Optionals

Putting a number between 0 and 1 between curly brackets will optionally generate the previous part. E.g., in the example below, "Hello there friend" is generated 70% of the time, "Hello friend" 30% of the time.

main = Hello (there){.7} friend.

Stored declarations

Often, you want your generated text to refer to the same generated thing multiple times. To achieve this, you can store these using a colon followed by a name, e.g. <declarationname:name>. This name can also just be blank.

name = An|Bob|Charlie|Dave
main = <name:protagonist> went to visit <name:>. <name:> said: "You look great, <name:protagonist>."

Functions

Babbly supports some basic functions and allows you to easily create any new (optional) string conversion functions in Java. Functions are specified within a declaration reference and follow a period. These can also easily be chained.

animal = cat|dog|goose
main = <animal.title.plural> are amazing!

Cascades: backing up generators

Since a function could be defined that does not always return a value, or certain declarations are missing from the context, cascades can be declared to specify backup options. They are specified using a /.

The example below will generate a fact if the Java function can generate one. If this does not return something valid, it will try to find the number of legs of the generated animal. Suppose this also fails (e.g., due to needing more information about the number of legs). In that case, it will just say that their animal is awesome.

animal = cat|dog|goose
main = My favorite fact is: (<animal.related_fact>) / (<animal.plural> have <animal.number_of_legs> legs!) / (My <animal> is awesome!)

Examples

Given all these constructs, you can easily create some complex text generators where you have complete control over their probabilities.

import firstname.words

food = pasta|pizza|sushi
main = {
  3: <firstname> loves <food>!
  1: <firstname> (quite|reasonably|fairly) likes eating <food>. Oo{1,3}h, I really hope they'll join!
  1: <firstname:protagonist> is not (quite){.5} fond of <food:>. <firstname:protagonist> will thus not go to the <food:> (restaurant|place).
}

Other examples can be found by going to the sources of some of my Twitterbots.

Back to projects