Skip to content

Scripting interpreter

Implementation in src/bqemulator/scripting/. See ADR 0011.

Parse

parser.py uses SQLGlot's BigQuery dialect to parse the entire script into a single AST rooted at a Script node. Multi-statement scripts produce a tree with child statements.

Interpret

interpreter.py walks the tree. For each node:

  • DECLARE: allocate a variable in the current frame with the declared type; initialize if a DEFAULT clause is present.
  • SET: evaluate an expression and assign to a named variable.
  • IF / ELSEIF / ELSE: evaluate the predicate; execute the matching branch.
  • WHILE / LOOP / FOR: Python-level loop driving the body.
  • BREAK / CONTINUE: thrown as typed exceptions caught by the enclosing loop.
  • BEGIN … EXCEPTION WHEN … END: exception boundary; raised errors are matched against WHEN handlers and routed.
  • CALL: invoke a stored procedure (resolved from the catalog).
  • EXECUTE IMMEDIATE: translate + execute a dynamic SQL string.
  • RETURN: exit the enclosing procedure.
  • SQL statement (SELECT, INSERT, UPDATE, …): translate and execute through the standard SQL pipeline.

Scoping

frames.py maintains a stack of lexical scopes. Each BEGIN/END and each procedure invocation pushes a new frame. Variable resolution walks the stack outward.

Error mapping

Uncaught script errors map to InvalidQueryError (syntax) or the appropriate domain error subclass. Errors caught by a handler are swallowed and execution continues with the handler block.