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.