#!/usr/bin/env node const fs = require('fs'); const assert = require('assert'); const lines = fs.readFileSync(process.argv[2], {encoding:'utf8'}).split("\n"); function getRecordStream(lineList) { var recs = []; const blankRx = /^\s*$/; lineList.forEach(function(line) { if (blankRx.test(line)) return; try { const record = JSON.parse(line); recs.push(record); } catch (e) { console.error("Invalid line: ", line); console.error(e); } }); return recs; } function parseRecordStream(recs) { var stk = []; var ret = null; recs.forEach(function(current) { if (current.op && current.op == 'DEFINE-COL') { var objColumn = { name: current.name, flags: current.flags, attr: [], }; while (stk.length > 0) { const rec = stk.pop(); if ('attr' in rec) objColumn.attr.push(rec); else if ('type' in rec) objColumn.type = rec.type; else if (rec.op && rec.op == 'START-COL') break; else { assert.fail('unhandled rec: ' + JSON.stringify(rec)); } } stk.push(objColumn); } else if (current.op && current.op == 'CREATE-TABLE') { var objTable = { verb: 'CREATE_TABLE', name: current.name, temp: current.temp, if_n_exists: current.if_n_exists, columns: [], }; var wantCols = current.n_cols; while (wantCols-- > 0) { const col = stk.pop(); assert(col !== undefined); objTable.columns.push(col); } stk.push(objTable); } else if (current.op && current.op == 'DROP-TABLE') { var objTab = { verb: 'DROP_TABLE', temp: current.temp, if_exists: current.if_exists, tables: [], }; var wantTabs = current.n_tables; while (wantTabs-- > 0) { const tab = stk.pop(); assert(tab !== undefined); objTab.tables.push(tab.name); } stk.push(objTab); } else if (current.op && current.op == 'INSERT') { var objInsert = { verb: 'INSERT', tbl_name: current.tbl_name, opts: current.opts, values: [], columns: [], }; var wantVals = current.n_vals; while (wantVals-- > 0) { const val = stk.pop(); assert(val !== undefined); objInsert.values.unshift(val.values); } var wantCols = current.n_cols; assert(wantCols <= 1); if (wantCols > 0) { const val = stk.pop(); assert(val !== undefined); objInsert.columns = val; } stk.push(objInsert); } else if ('INSERT-COLS' in current) { var arrCols = []; var wantVals = current['INSERT-COLS']; while (wantVals-- > 0) { const val = stk.pop(); assert(val !== undefined); arrCols.unshift(val['COLUMN']); } stk.push(arrCols); } else if (current.op && current.op == 'CREATE-DB') { var objDb = { verb: 'CREATE_DATABASE', name: current.name, if_ne: current.if_ne, }; stk.push(objDb); } else if (current.op && current.op == 'DROP-DB') { var objDb = { verb: 'DROP_DATABASE', name: current.name, if_exists: current.if_exists, }; stk.push(objDb); } else if (current.op && current.op == 'SELECT') { var objSelect = { verb: 'SELECT', opts: current.opts, tables: [], exprs: [], }; var wantTabs = current.n_tbl_ref; while (wantTabs-- > 0) { const tab = stk.pop(); assert(tab !== undefined); objSelect.tables.push(tab.name); } var wantExpr = current.n_expr; while (wantExpr-- > 0) { const an_expr = stk.pop(); assert(an_expr !== undefined); objSelect.exprs.push(an_expr); } stk.push(objSelect); } else if (current.op && current.op == 'STMT') { const stmt = stk.pop(); assert(stk.length === 0); ret = stmt; } else if ('INT/NUMBER' in current) { const objVal = { type: 'number', val: current['INT/NUMBER'], }; stk.push(objVal); } else if ('STRING' in current) { const objVal = { type: 'string', val: current.STRING, }; stk.push(objVal); } else if ('VALUES' in current) { const objVal = { type: 'value_list', values: [], }; var wantVals = current.VALUES; while (wantVals-- > 0) { const val = stk.pop(); assert(val !== undefined); objVal.values.unshift(val); } stk.push(objVal); } else if ('result' in current) { // EOF; do nothing } else { // console.log("PUSH", current); stk.push(current); } }); return ret; } const recs = getRecordStream(lines); // console.dir(recs); const stmt = parseRecordStream(recs); console.log(JSON.stringify(stmt, null, 2));