11# plx Architecture
22
3- plx lets a function body be written in a Ruby, PHP, JavaScript, or Python
4- dialect and executed by the standard plpgsql interpreter. This document
5- describes how that works in the extension as built.
3+ plx lets a function body be written in a Ruby, PHP, JavaScript, TypeScript,
4+ Python, Go, COBOL, Oracle PL/SQL, or Transact-SQL dialect and executed by the
5+ standard plpgsql interpreter. This document describes how that works in the
6+ extension as built.
67
78## The core idea
89
@@ -85,36 +86,66 @@ It is dialect-pluggable through a `PlxSurface` (in `plx_int.h`) that each dialec
8586supplies. The surface describes what varies between languages:
8687
8788- the keyword table, mapping each dialect's spellings to canonical keywords;
88- - the block style: keyword-delimited ( ` end ` ), brace-delimited ( ` { } ` ), or
89- indentation (INDENT/DEDENT );
89+ - the block style, used as a lexer hint (indentation-tokenized vs.
90+ newline-tokenized );
9091- comment syntax, the variable sigil (for example ` $ ` ), the string-concatenation
9192 operator, and how string interpolation is written (` #{} ` , ` $var ` and ` {$e} ` ,
92- ` ${} ` template literals, or f-strings).
93-
94- The shared code (` plx_transpile.c ` ) is dialect-neutral: the lexer, the three
95- block parsers, the expression rewriter, DECLARE-hoisting and type inference, the
96- statement lowering, and the intrinsics (` query ` , ` fetch_one ` , ` perform ` ,
97- ` execute ` , ` return_query ` , cursors, and so on) are all driven by the surface.
93+ ` ${} ` template literals, or f-strings);
94+ - ` parse_body ` , the front-end entry point (see below), and
95+ ` self_contained_block ` , a flag for dialects that emit their own
96+ ` DECLARE ` /` BEGIN ` /` END ` (PL/SQL).
97+
98+ ### Engine and front ends
99+
100+ The transpiler is split into a dialect-neutral ** engine** and per-dialect
101+ ** front ends** , selected through the ` parse_body ` function pointer on the
102+ surface (a vtable method). ` plx_transpile() ` just calls
103+ ` cx->surf->parse_body(cx) ` and then runs one assemble tail; there is no
104+ per-dialect branching in the driver.
105+
106+ - The ** engine** lives in ` plx_transpile.c ` and is declared to the front ends
107+ through ` plx_engine.h ` : the shared byte lexer (` plx_lex ` ), the expression
108+ rewriter (` plx_rewrite_expr ` ), the leaf-statement emitter and intrinsics
109+ (` query ` , ` fetch_one ` , ` perform ` , ` execute ` , ` return_query ` , cursors, and so
110+ on), the symbol table, string/interpolation decoding, and the final
111+ DECLARE-hoisting + assemble. It contains no dialect-specific code.
112+ - Each ** front end** owns its dialect's tokenizer, parser, and statement
113+ lowering, and implements ` parse_body ` by transforming ` cx->body ` into
114+ ` cx->out ` . The text-family dialects (` php ` /` js ` /` ts ` ) share a brace parser in
115+ ` plx_parse_brace.c ` ; Ruby (keyword-` end ` ) and Python (indentation) parse on
116+ top of the shared lexer inside their own translation units; and the
117+ standalone dialects (COBOL, PL/SQL, T-SQL, Go) run their own tokenizer and
118+ emitter, calling back into the engine only for shared services.
98119
99120## Files
100121
101122```
102123plx.control, plx--1.0.sql extension control and install SQL
103124src/plx.h public ABI (PlxDialect, PlxFuncMeta)
104125src/plx_int.h internal ABI (PlxSurface, canonical keywords)
126+ src/plx_engine.h engine interface: PlxCtx, tokens, symtab, and the
127+ plx_* entry points the front ends call
105128src/plx_core.c PL handler binding, registry, generic validator
106129 and inline handler
107- src/plx_transpile.c the shared transpiler
108- src/plx_dialect_ruby.c the plxruby surface and trampolines
109- src/plx_dialect_php.c the plxphp surface and trampolines
110- src/plx_dialect_js.c the plxjs surface and trampolines
111- src/plx_dialect_python.c the plxpython3 surface and trampolines
130+ src/plx_transpile.c the dialect-neutral engine + plx_transpile() driver
131+ src/plx_strbuild.c string-builder intrinsic helpers
132+ src/plx_parse_brace.c shared brace front end (php/js/ts) + TS preprocess
133+ src/plx_dialect_ruby.c the plxruby surface + Ruby front end
134+ src/plx_dialect_php.c the plxphp surface (parse_body -> brace front end)
135+ src/plx_dialect_js.c the plxjs surface (parse_body -> brace front end)
136+ src/plx_dialect_ts.c the plxts surface (parse_body -> brace front end)
137+ src/plx_dialect_python.c the plxpython3 surface + Python front end
138+ src/plx_dialect_go.c the plxgo surface + Go front end
139+ src/plx_dialect_cobol.c the plxcobol surface + COBOL front end
140+ src/plx_dialect_plsql.c the plxplsql surface + PL/SQL front end
141+ src/plx_dialect_tsql.c the plxtsql surface + T-SQL front end
112142```
113143
114- Everything links into a single ` plx.so ` . A dialect is a ` PlxSurface ` plus three
115- small trampolines (validator, inline handler, and the shared call-handler
116- binding), registered in ` _PG_init ` . Adding a dialect is a new surface and a few
117- ` CREATE LANGUAGE ` lines; it does not touch the shared transpiler.
144+ Everything links into a single ` plx.so ` . A dialect is a ` PlxSurface ` (including
145+ its ` parse_body ` front end) plus small trampolines (validator, inline handler,
146+ and the shared call-handler binding), registered in ` _PG_init ` . Adding a dialect
147+ is a new ` plx_dialect_X.c ` (a surface with its ` parse_body ` , plus a few
148+ ` CREATE LANGUAGE ` lines), and does not touch the shared engine.
118149
119150## Trust
120151
@@ -132,4 +163,6 @@ fuzzed (see `test/fuzz.py`).
132163- [ TRANSPILER.md] ( TRANSPILER.md ) : the original transpiler design specification.
133164- [ PARITY.md] ( PARITY.md ) : the plpgsql construct parity matrix.
134165- The per-dialect chapters: [ plxruby] ( plxruby.md ) , [ plxphp] ( plxphp.md ) ,
135- [ plxjs] ( plxjs.md ) , [ plxpython3] ( plxpython3.md ) .
166+ [ plxjs] ( plxjs.md ) , [ plxts] ( plxts.md ) , [ plxpython3] ( plxpython3.md ) ,
167+ [ plxgo] ( plxgo.md ) , [ plxcobol] ( plxcobol.md ) , [ plxplsql] ( plxplsql.md ) ,
168+ [ plxtsql] ( plxtsql.md ) .
0 commit comments