{"id":13659110,"url":"https://github.com/Lokaltog/baba-core","last_synced_at":"2025-04-24T12:30:51.027Z","repository":{"id":15848299,"uuid":"18588436","full_name":"Lokaltog/baba-core","owner":"Lokaltog","description":"Mini-language for creating random text generators.","archived":false,"fork":false,"pushed_at":"2021-01-08T09:12:39.000Z","size":792,"stargazers_count":134,"open_issues_count":2,"forks_count":3,"subscribers_count":6,"default_branch":"develop","last_synced_at":"2024-08-16T14:04:08.579Z","etag":null,"topics":["generator","grammar","parser","random"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lokaltog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-04-09T07:03:29.000Z","updated_at":"2024-05-28T17:09:28.000Z","dependencies_parsed_at":"2022-09-24T05:00:48.329Z","dependency_job_id":null,"html_url":"https://github.com/Lokaltog/baba-core","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lokaltog%2Fbaba-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lokaltog%2Fbaba-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lokaltog%2Fbaba-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lokaltog%2Fbaba-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lokaltog","download_url":"https://codeload.github.com/Lokaltog/baba-core/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223952675,"owners_count":17230933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["generator","grammar","parser","random"],"created_at":"2024-08-02T05:01:05.349Z","updated_at":"2024-11-10T12:31:17.942Z","avatar_url":"https://github.com/Lokaltog.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"![Baba](resources/logo.svg \"Baba\")\n\n**Mini-language for creating random text generators, inspired by the [Dada \nEngine](http://dev.null.org/dadaengine/).**\n\n## Introduction\n\nThis repo contains a Jison-based parser for the Baba language, and a compiler \nfor outputting JS modules. The compiler outputs JS modules that may be imported \nand used in the browser or Node.js.\n\n## Usage\n\nInstall baba with npm:\n\n```bash\nnpm install -g baba-core\n```\n\nPass your grammar file to `baba` to receive your text generator as a JS module:\n\n```bash\necho \"@export('test', [foo, bar, baz])\" \u003e my-grammar.baba\n\nbaba my-grammar.baba \u003e my-grammar.js\n```\n\nRun `baba --help` for more information about its arguments.\n\nYou may now import `my-grammar.js` and use it in your project. The generated \nfile doesn't have any dependencies and works standalone:\n\n```js\nimport myGrammar from './my-grammar';\n\nconst generator = myGrammar();\n\nconsole.log(generator.test());\n// Outputs \"foo\", \"bar\" or \"baz\"\n```\n\nYou may also generate test output from all exported identifiers:\n\n```bash\nbaba my-grammar.baba --test-output\n\n# Example output:\n# git-verb\n#   → stash\n#   → reset\n#   → index\n#   → annotate\n```\n\n## Resources\n\n* [Vim syntax](https://github.com/Lokaltog/vim-baba)\n* AUR package\n\n## Examples\n\n* [Git man page generator](https://github.com/Lokaltog/baba-grammar-git-man-page-generator)\n\n## User guide\n\n### Creating your first grammar\n\n## The Baba language\n\n### Comments\n\nBaba supports **one-line comments**, prefixed with `#`. Comments may appear \nanywhere. The parser will ignore anything from the comment prefix to the next \ntoken.\n\n#### Example\n\n```\n# This is a comment\n```\n\n### Whitespace\n\nWhitespace characters (tabs, spaces, newlines) are ignored, except inside \n[strings](#strings).\n\nWhitespace surrounding [unquoted list elements](#lists) is removed, but \nwhitespace inside unquoted list elements (i.e. between words) is preserved.\n\n### Identifiers\n\nAn **identifier** is any sequence of letters, digits, underscores, hyphens and \nperiods, and starts with an underscore or a letter. Periods have a special \nmeaning in identifiers, and are used to refer to [scoped blocks](#blocks).\n\nVariable identifiers follow the same rules as other identifiers, and are \nprefixed with `$`.\n\n#### Example\n\n```\nthis-is-an-identifier\nscope.subscope.identifier\n_43baz\n$my-variable\n```\n\n#### Syntax\n\n```ebnf\nvar-identifier = \"$\", identifier ;\nidentifier     = string, { string | number | special } ;\nstring         = ? [a-zA-Z]+ ? | \"_\" ;\nnumber         = ? [0-9]+ ? ;\nspecial        = \"-\" | \".\" ;\n```\n\n### Blocks\n\nA Baba grammar is composed of **blocks**. A block is a structure identified by \nan [identifier](#identifiers) which returns text. You may refer to a block by \nits identifier anywhere in your grammar.\n\nThe following elements are valid block structures:\n\n* [Scope](#scopes)\n* [List](#lists)\n* [Tag](#tags)\n* [String](#strings)\n\n#### Syntax\n\n```ebnf\nblock = identifier, ( scope | list | tag | string ) ;\n```\n\n### Scopes\n\n**Scoping** is useful to structure a grammar in a hierarchy. Baba grammars \nalways begin in an unnamed _root scope_. Scopes cannot be \n[exported](#meta-statements).\n\nScope blocks may be nested, and each scope may contain any number of [meta \nstatements](#meta-statements), [blocks](#blocks), [mappings](#mappings) and \n[functions](#functions).\n\nNested scope blocks must be referred to with the full scope path, with levels \nseparated by `.`:\n\n```\na { b { c [ ... ] } }\n# The innermost scope `c` must be referred to with the identifier a.b.c\n```\n\n#### Syntax\n\n```ebnf\nbaba-grammar  = scope-element, ? EOF ? ;\n\nscope         = \"{\", { scope-element }, \"}\" ;\nscope-element = meta-statement | block | mapping | function;\n```\n\n### Lists\n\n**Lists** are collections of one or more [strings](#strings). When evaluated, \na random list element is returned. Lists may be [exported](#meta-statements).\n\nStrings may be either quoted or unquoted. List elements are separated by `,`. \nWhitespace surrounding the list delimiters and list separators is removed.\n\n#### Example\n\n```\n[ separated, list, element ] # -\u003e ['separated', 'list', 'element']\n[ \"quoted\", 'quoted', unquoted ] # -\u003e ['quoted', 'quoted', 'unquoted']\n[ symbols like \\, must be escaped in unquoted elements ] # -\u003e ['symbols like , must be...']\n```\n\n#### Syntax\n\n```ebnf\nlist         = \"[\", { list-element, [ \",\" ] }, \"]\" ;\nlist-element = quoted-string | literal ;\n```\n\n### Tags\n\n**Tags** are collections of one or more tag elements and expressions. When \nevaluated, a tag returns a concatenated string of its contents. Tags may be \n[exported](#meta-statements).\n\nConsecutive tag elements without a separator will be concatenated.\n\nTag elements may act as a [list](#lists) by separating each element with `|`. \nThis will cause a random element to be returned. The `|` operator has \npresedence over concatenation.\n\nTags may contain [tag expressions](#tag-expressions).\n\nTags may be nested. This is useful for grouping tag elements.\n\nA tag may have a quantifier. `?` will insert the tag 0 or 1 times (\"optional\"). \n`*` will insert the tag 0 or more times. `+` will insert the tag 1 or more \ntimes.\n\n#### Examples\n\n```\n\u003ca b c d|e|f g h i\u003e # -\u003e (a + b + c) + (d OR e OR f) + (g + h + i)\n\u003ca' 'b c\u003e           # -\u003e a + ' ' + b + c\n\u003ca?\u003e\u003cb?\u003e            # -\u003e (a OR '') + (b OR '')\n\u003ca' '?\u003e             # -\u003e (a + ' ') OR ''\n\u003c\u003ca b|c\u003e|d e\u003e       # -\u003e (a + (b OR c)) OR (d + e)\n```\n\n#### Syntax\n\n```ebnf\ntag                = \"\u003c\", tag-element-concat, [ tag-quantifier ], \"\u003e\" ;\ntag-quantifier     = \"?\" | \"+\" | \"*\" ;\ntag-element-concat = ( tag-element-concat, tag-element-choice )\n                   | tag-element-choice ;\ntag-element-choice = ( tag-element-choice, \"|\", tag-element )\n                   | tag-element ;\ntag-element        = transform-expr | tag ;\n```\n\n### Tag expressions\n\n**Tag expressions** provide advanced functionality like variable assignment, \ntransforms and function calls.\n\n#### Variables\n\nVariables may be assigned values inside tags with a **variable assign \nexpression**. Currently only identifiers can be assigned to variables.\n\n**Regular variable assignment** uses the `=` operator, and will always assign \nthe value.\n\n**Optional variable assignment** uses the `?=` operator, and will assign the \nvalue only if the variable hasn't been assigned a value yet.\n\n#### Transforms\n\nIdentifiers in tags may be transformed by external functions with a **transform \nexpression**. When a transform is applied, the transform function is called \nwith the _evaluated identifier value_ (a string) as its only argument. The \ntransform function must return a string.\n\n#### Functions\n\nTags may also include **function expressions**. Function expressions call \nexternal functions which must return a function which is evaluated at runtime. \nThe returned function must return a string.\n\n#### Examples\n\n```\n\u003ca:b:c\u003e       # -\u003e c(b(a))\n\u003ca:b(c)\u003e      # -\u003e b(c)(a)\n\u003ca:b(c):d(e)\u003e # -\u003e d(e)(b(c)(a))\n\u003c$a=b\u003e\u003c$a\u003e    # -\u003e Assign b to $a, then output $a + b (= b + b)\n\u003ca()\u003e         # -\u003e Return the output from external function a()\n\u003c$a=b:c()\u003e    # -\u003e Assign the raw value of b to $a, then transform b as c()(b)\n```\n\n#### Syntax\n\n```ebnf\ntransform-expr   = transform-expr, \":\", function-expr\n                 | function-expr ;\nfunction-expr    = ( var-assign-expr, argument-list )\n                 | var-assign-expr ;\nvar-assign-expr  = ( var-assign-expr, ( \"?=\" | \"=\" ), var-assign-value )\n                 | var-assign-value ;\nvar-assign-value = identifier\n                 | quoted-string ;\n\nargument-list         = \"(\", [ argument-list-body ], \")\" ;\nargument-list-body    = argument-list-element, [ { \",\", argument-list-element } ] ;\nargument-list-element = identifier | quoted-string | tag | list ;\n```\n\n### Strings\n\nBaba supports **literal strings** (enclosed by single quotes), and \n**interpolated strings** (enclosed by double quotes). Strings may be \n[exported](#meta-statements).\n\nLiteral strings will be returned verbatim.\n\nInterpolated strings may contain [tags](#tags). They may also be weighted by \nappending `+` and a number indicating its weight. This effectively duplicates \nthe string in its containing list, making it more likely to be returned.\n\nStrings may span multiple lines, and may contain any character (some characters \nmay need to be escaped depending on the string type).\n\nBaba supports unquoted literal strings in [lists](#lists). Unquoted strings \nprovide superior readability for lists containing short, plain text elements. \nThey may contain any character, but the characters in the list below must be \nescaped. Because of this restriction unquoted strings are most useful for \nsimple word lists.\n\n#### Special characters\n\nThe characters listed below must be escaped with `\\`, e.g. a double quote in \na double quoted string must be escaped as `\\\"`.\n\n| String type         | Special characters      |\n| ------------------- | ----------------------- |\n| Literal string      | `\\` `'`                 |\n| Interpolated string | `\\` `\"`                 |\n| Unquoted string     | `\\` `'` `\"` `,` `[` `\u003c` |\n\n#### Examples\n\n```\n'A \"literal string\"'\n\"An \\\"interpolated string\\\" which may contain \u003ctag\u003es\"\n```\n\n#### Syntax\n\n```ebnf\nstring                = literal-string | interp-string ;\nliteral-string        = \"'\", { ? string literal ? }, \"'\" ;\ninterp-string         = '\"', { interp-string-element }, '\"', [ interp-string-weight ] ;\ninterp-string-weight  = \"+\", ? number ? ;\ninterp-string-element = ? string literal ? | tag ;\n```\n\n### Functions\n\n**Functions** are inline JS functions that may be used in tag expressions. \nFunctions may receive any type and number of arguments, including tags and \nidentifiers.\n\nFunctions must be valid JS. Behind the scenes functions are parsed by Babylon \nand the resulting AST is inserted into the grammar AST as arrow function \nexpressions.\n\nBecause of identifier mangling applied internally by Baba, you cannot reference \nother Baba functions inside a function body.\n\n#### Examples\n\n```\nuppercase(str) {\n    return str.toUpperCase();\n}\ndemo-function(arg) {\n    return element =\u003e element + '-' + arg;\n}\n@export('demo', \u003c'a':demo-function(\u003c'b'|'c'\u003e):uppercase\u003e)\n# -\u003e demo = \"A-B\" OR \"A-C\"\n```\n\n#### Syntax\n\n```ebnf\nfunction = identifier, argument-list, \"{\", ? function body ?, \"}\";\n```\n\n### Mappings\n\n**Mappings** are used to transform a string into another string. Mappings \nsupport regular expression or literal string replacement. They are applied on \nthe resulting string of a tag expression.\n\nMappings may be bidirectional. One-directional mappings are separated with \n`-\u003e`, bidirectional mappings are separated with `\u003c-\u003e`.\n\n#### Examples\n\n```\npluralize {\n    /(.*)/i -\u003e '$1s'\n}\n# Note: there's a better version available in baba-grammar-common\n# \u003c'word':pluralize\u003e =\u003e \"words\"\n\nsize-swap {\n    'large' \u003c-\u003e 'small'\n}\n# \u003c'large':size-swap\u003e =\u003e \"small\"\n# \u003c'small':size-swap\u003e =\u003e \"large\"\n# \u003c'medium':size-swap\u003e =\u003e \"medium\"\n\ncolor-transform {\n    'blue'   -\u003e 'red'\n    'yellow' -\u003e 'purple'\n}\n# \u003c'blue':color-transform\u003e =\u003e \"red\"\n# \u003c'yellow':color-transform\u003e =\u003e \"purple\"\n# \u003c'brown':color-transform\u003e =\u003e \"brown\"\n```\n\n#### Syntax\n\n```ebnf\nmapping           = mapping-from, mapping-direction, mapping-to;\nmapping-from      = literal-string | ? regular expression ? ;\nmappnig-to        = literal-string;\nmapping-direction = \"-\u003e\" | \"\u003c-\u003e\" ;\n```\n\n### Meta statements\n\n**Meta statements** provide information about the grammar, e.g. which data \nshould be exported.\n\n#### Examples\n\n```\n# Import verb transforms and make them available in the `verb` scope\n@import('baba-grammar-common/transforms/verb', verb)\n\n# Export an identifier - makes `myList` callable in the exported grammar object\n@export('myList', my-list)\n\n# Export an anonymous list that returns a random literal string\n@export('myList', [ foo, bar, baz ])\n```\n\n#### Syntax\n\n```ebnf\nmeta-statement = \"@\", identifier, argument-list ;\n```\n\n#### `export(key: string, value: ( identifier | list | tag | string ))`\n\nAdds a key/value pair to the exported module object.\n\n#### `import(file: string, scope: identifier)`\n\nImports a Baba file into a scope.\n\n## Compilation process\n\nTODO\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLokaltog%2Fbaba-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLokaltog%2Fbaba-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLokaltog%2Fbaba-core/lists"}