Graffiticode Technical Overview

Graffiticode is a collection of language services that each define a vocabulary, compiler and viewer. Languages share a common syntax. Each service compiles code and data to produce object data.

Language

The vocabulary is defined by a lexicon, which is used to guide parsing of Graffiticode tasks. The viewer is a kind of front-end browser component. The compiler translates code to data.

Lexicon

To translate human readable and writeable source code into machine readable code, we need a parser and a vocabulary that defines what words are accepted by language. Each language provides a lexicon that that defines its vocabulary.

Compiler

Each language service processes code in its particular domain specific language using a compiler. The compiler takes as input code and data values, and produces a data value. The compiler is invoked through the /compile endpoint:

POST /compile { code, data } -> { data }

The code value is an abstract syntax tree (AST) that has been parsed using the languages lexicon. The data value is an object that is passed as an argument that is available as a parameter of the code.

Form

The data produced by the compiler is viewable in a browser using the form view. This view is used both in development and production. In development is allows the author to “see” the shape of data that might not otherwise be seen by the ultimate end-user.

The form view is accessed through the /form endpoint with either a url for the source of the object code data, or the data directly.

GET /form?url=dataUrl -> html
GET /form?data=data -> html

API

Tasks are stored and dispatched to their corresponding web services by the graffiticode API. Compiles are dispatched to the various language services by the API. An API serves several basic functions:

  • Maps tasks to ids, persistently
  • Dispatches compiles to the appropriate language compiler
  • Batch compiling items
  • Chaining tasks as a pipeline

Mapping tasks to ids

POST /tasks [ { lang, code }, ... ] -> [ id ]

Compiling tasks to data

GET /data?ids=[ id ] --> [ { data }, ... ]

Batch compiling items to data

POST /compile [ { id, data }, ... ] -> [ { data }, ... ]
POST /compile [ { lang, code, data }, ... ] -> [ { data }, ... ]

Task pipelines

Tasks may be chained together into a task pipeline, where the data produced by one task is passed as data to the next task in the pipeline. Task pipelines are composed by simply concatenating their ids with + as a separator, as in id1+id2+id3.

An example of chaining tasks is in generating and scraping custom charts using L1 (data), L147 (chart type), and L146 (chart scraper)

L1 -> L147 -> L146

First, the individual tasks are constructed:

POST /task { lang: "1", code: dataCode } -> { id: dataId }
POST /task { lang: "147", code: chartCode } -> { id: chartId }
POST /task { lang: "146", code: scraperCode } -> { id: scraperId }

Next, the pipeline’s task id is composed and compiled:

const id = `${scraperId}+${chartId}+${dataId}`
GET /data?id=id -> { data }

Form view

Each language defines a form view, a kind of micro front-end for its object data.
The form view of a task is fetched through the API /form endpoint:

GET /form?id=id -> html

where id is the id of the task to be viewed.

NOTE: We refer to pipelines as composite tasks, or just tasks.

1 Like