#ifndef DSLUISCHEMA_H #define DSLUISCHEMA_H #include "ast.h" #include enum class UiFieldKind { ScalarU8, ScalarI8, ScalarU16, ScalarI16, ScalarU32, ScalarI32, ScalarU64, ScalarI64, GenericValue, Bool }; struct UiField { QString name; QString displayName; UiFieldKind kind = UiFieldKind::GenericValue; bool visible = true; bool readOnly = false; int firstLine = 1; int firstCol = 1; bool isTable = false; QString tableTitle; QStringList columns; QHash formats; }; inline UiFieldKind toUiKind(ScalarType t) { switch (t) { case ScalarType::U8: return UiFieldKind::ScalarU8; case ScalarType::I8: return UiFieldKind::ScalarI8; case ScalarType::U16: return UiFieldKind::ScalarU16; case ScalarType::I16: return UiFieldKind::ScalarI16; case ScalarType::U32: return UiFieldKind::ScalarU32; case ScalarType::I32: return UiFieldKind::ScalarI32; case ScalarType::U64: return UiFieldKind::ScalarU64; case ScalarType::I64: return UiFieldKind::ScalarI64; case ScalarType::Bool: return UiFieldKind::Bool; } return UiFieldKind::GenericValue; } inline bool isBoolExpr(const Expr& e) { if (std::holds_alternative(e.node)) { const auto& u = std::get(e.node); if (u.op == "!") return true; return isBoolExpr(*u.rhs); } if (std::holds_alternative(e.node)) { const auto& b = std::get(e.node); const QString& op = b.op; if (op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=" || op == "&&" || op == "||") { return true; } return isBoolExpr(*b.lhs) || isBoolExpr(*b.rhs); } return false; } inline UiFieldKind inferKindFromAssignExpr(const ExprPtr& value) { if (!value) return UiFieldKind::GenericValue; if (isBoolExpr(*value)) return UiFieldKind::Bool; return UiFieldKind::GenericValue; } inline QStringList splitCsvCols(const QString& s) { QStringList out; for (const QString& part : s.split(',', Qt::SkipEmptyParts)) { const QString trimmed = part.trimmed(); if (!trimmed.isEmpty()) out.push_back(trimmed); } return out; } inline void collectFieldsFromBlock(const QVector& blk, QMap& out, const Module* mod = nullptr); inline void collectFieldsFromStmt(const Stmt& s, QMap& out, const Module* mod = nullptr) { auto add = [&](const QString& name, UiFieldKind kind, bool visible, bool readOnly, const QString& display, const UiFlags* flags) { if (name.isEmpty()) return; if (!visible) return; if (!out.contains(name)) { UiField f; f.name = name; f.displayName = display.isEmpty() ? name : display; f.kind = kind; f.visible = visible; f.readOnly = readOnly; f.firstLine = s.line; f.firstCol = s.col; if (flags && flags->isTable()) { f.isTable = true; f.tableTitle = flags->tableTitle; f.columns = splitCsvCols(flags->columnsCsv); f.formats = flags->formats; } out.insert(name, f); } else { if (!display.isEmpty()) out[name].displayName = display; if (out[name].kind == UiFieldKind::GenericValue && kind != UiFieldKind::GenericValue) out[name].kind = kind; out[name].readOnly = out[name].readOnly || readOnly; if (flags && flags->isTable() && !out[name].isTable) { out[name].isTable = true; out[name].tableTitle = flags->tableTitle; out[name].columns = splitCsvCols(flags->columnsCsv); out[name].formats = flags->formats; } } }; if (std::holds_alternative(s.node)) { const auto& rs = std::get(s.node); add(rs.name, toUiKind(rs.type), rs.ui.visible(), rs.ui.readOnly, rs.ui.display, &rs.ui); return; } if (std::holds_alternative(s.node)) { const auto& as = std::get(s.node); const bool vis = as.ui.visible(); const bool ro = as.ui.readOnly || vis; add(as.name, inferKindFromAssignExpr(as.value), vis, ro, as.ui.display, &as.ui); return; } if (std::holds_alternative(s.node)) { const auto& iff = std::get(s.node); collectFieldsFromBlock(iff.thenBody, out, mod); collectFieldsFromBlock(iff.elseBody, out, mod); return; } if (std::holds_alternative(s.node)) { const auto& wh = std::get(s.node); collectFieldsFromBlock(wh.body, out, mod); return; } if (std::holds_alternative(s.node)) { const auto& rp = std::get(s.node); collectFieldsFromBlock(rp.body, out, mod); return; } if (std::holds_alternative(s.node)) { const auto& fr = std::get(s.node); add(fr.var, UiFieldKind::GenericValue, false, true, "", {}); collectFieldsFromBlock(fr.body, out, mod); return; } // Handle CallStmt for parse_here - merge UI fields from referenced type if (std::holds_alternative(s.node)) { const auto& cs = std::get(s.node); if (cs.call && std::holds_alternative(cs.call->node)) { const auto& call = std::get(cs.call->node); // Handle parse_here - merge UI fields from referenced type if (call.fn == "parse_here" && !call.args.isEmpty() && mod) { if (std::holds_alternative(call.args[0]->node)) { const QString typeName = std::get(call.args[0]->node).v; if (mod->types.contains(typeName)) { const TypeDef& childTd = mod->types[typeName]; collectFieldsFromBlock(childTd.body, out, mod); } } } } return; } } inline void collectFieldsFromBlock(const QVector& blk, QMap& out, const Module* mod) { for (const auto& sp : blk) { if (!sp) continue; collectFieldsFromStmt(*sp, out, mod); } } inline QMap buildUiSchemaForType(const TypeDef& td, const Module* mod = nullptr) { QMap fields; collectFieldsFromBlock(td.criteria, fields, mod); collectFieldsFromBlock(td.body, fields, mod); return fields; } #endif // DSLUISCHEMA_H