imxc 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components.js +1 -1
- package/dist/emitter.js +75 -26
- package/dist/ir.d.ts +5 -0
- package/dist/lowering.js +66 -11
- package/package.json +1 -1
package/dist/components.js
CHANGED
|
@@ -184,7 +184,7 @@ export const HOST_COMPONENTS = {
|
|
|
184
184
|
props: {
|
|
185
185
|
label: { type: 'string', required: true },
|
|
186
186
|
value: { type: 'string', required: true },
|
|
187
|
-
onChange: { type: 'callback', required:
|
|
187
|
+
onChange: { type: 'callback', required: false },
|
|
188
188
|
style: { type: 'style', required: false },
|
|
189
189
|
},
|
|
190
190
|
hasChildren: false, isContainer: false,
|
package/dist/emitter.js
CHANGED
|
@@ -1096,9 +1096,10 @@ function emitListMap(node, lines, indent, depth) {
|
|
|
1096
1096
|
if (node.loc) {
|
|
1097
1097
|
lines.push(`${indent}// ${node.loc.file}:${node.loc.line} .map()`);
|
|
1098
1098
|
}
|
|
1099
|
-
|
|
1100
|
-
lines.push(`${indent}${
|
|
1101
|
-
lines.push(`${indent}${INDENT}
|
|
1099
|
+
const idx = node.indexVar;
|
|
1100
|
+
lines.push(`${indent}for (size_t ${idx} = 0; ${idx} < ${node.array}.size(); ${idx}++) {`);
|
|
1101
|
+
lines.push(`${indent}${INDENT}auto& ${node.itemVar} = ${node.array}[${idx}];`);
|
|
1102
|
+
lines.push(`${indent}${INDENT}ctx.begin_instance("${node.componentName}", (int)${idx}, ${node.stateCount}, ${node.bufferCount});`);
|
|
1102
1103
|
emitNodes(node.body, lines, depth + 2);
|
|
1103
1104
|
lines.push(`${indent}${INDENT}ctx.end_instance();`);
|
|
1104
1105
|
lines.push(`${indent}}`);
|
|
@@ -1346,6 +1347,19 @@ function emitColorEdit(node, lines, indent) {
|
|
|
1346
1347
|
lines.push(`${indent}${INDENT}}`);
|
|
1347
1348
|
lines.push(`${indent}}`);
|
|
1348
1349
|
}
|
|
1350
|
+
else if (node.directBind && node.valueExpr) {
|
|
1351
|
+
lines.push(`${indent}imx::renderer::color_edit(${label}, ${node.valueExpr}.data());`);
|
|
1352
|
+
}
|
|
1353
|
+
else if (node.valueExpr !== undefined) {
|
|
1354
|
+
lines.push(`${indent}{`);
|
|
1355
|
+
lines.push(`${indent}${INDENT}auto val = ${node.valueExpr};`);
|
|
1356
|
+
lines.push(`${indent}${INDENT}if (imx::renderer::color_edit(${label}, val.data())) {`);
|
|
1357
|
+
if (node.onChangeExpr) {
|
|
1358
|
+
lines.push(`${indent}${INDENT}${INDENT}${node.onChangeExpr};`);
|
|
1359
|
+
}
|
|
1360
|
+
lines.push(`${indent}${INDENT}}`);
|
|
1361
|
+
lines.push(`${indent}}`);
|
|
1362
|
+
}
|
|
1349
1363
|
}
|
|
1350
1364
|
function emitListBox(node, lines, indent) {
|
|
1351
1365
|
emitLocComment(node.loc, 'ListBox', lines, indent);
|
|
@@ -1469,44 +1483,79 @@ function emitInputTextMultiline(node, lines, indent) {
|
|
|
1469
1483
|
}
|
|
1470
1484
|
function emitColorPicker(node, lines, indent) {
|
|
1471
1485
|
emitLocComment(node.loc, 'ColorPicker', lines, indent);
|
|
1486
|
+
const label = asCharPtr(node.label);
|
|
1472
1487
|
if (node.stateVar) {
|
|
1473
1488
|
lines.push(`${indent}{`);
|
|
1474
1489
|
lines.push(`${indent}${INDENT}auto val = ${node.stateVar}.get();`);
|
|
1475
|
-
lines.push(`${indent}${INDENT}if (imx::renderer::color_picker(${
|
|
1490
|
+
lines.push(`${indent}${INDENT}if (imx::renderer::color_picker(${label}, val.data())) {`);
|
|
1476
1491
|
lines.push(`${indent}${INDENT}${INDENT}${node.stateVar}.set(val);`);
|
|
1477
1492
|
lines.push(`${indent}${INDENT}}`);
|
|
1478
1493
|
lines.push(`${indent}}`);
|
|
1479
1494
|
}
|
|
1495
|
+
else if (node.directBind && node.valueExpr) {
|
|
1496
|
+
lines.push(`${indent}imx::renderer::color_picker(${label}, ${node.valueExpr}.data());`);
|
|
1497
|
+
}
|
|
1498
|
+
else if (node.valueExpr !== undefined) {
|
|
1499
|
+
lines.push(`${indent}{`);
|
|
1500
|
+
lines.push(`${indent}${INDENT}auto val = ${node.valueExpr};`);
|
|
1501
|
+
lines.push(`${indent}${INDENT}if (imx::renderer::color_picker(${label}, val.data())) {`);
|
|
1502
|
+
if (node.onChangeExpr) {
|
|
1503
|
+
lines.push(`${indent}${INDENT}${INDENT}${node.onChangeExpr};`);
|
|
1504
|
+
}
|
|
1505
|
+
lines.push(`${indent}${INDENT}}`);
|
|
1506
|
+
lines.push(`${indent}}`);
|
|
1507
|
+
}
|
|
1480
1508
|
}
|
|
1481
1509
|
function emitPlotLines(node, lines, indent) {
|
|
1482
1510
|
emitLocComment(node.loc, 'PlotLines', lines, indent);
|
|
1483
|
-
const idx = plotCounter++;
|
|
1484
|
-
const varName = `_plot_${idx}`;
|
|
1485
|
-
const values = node.values.split(',').map(v => ensureFloatLiteral(v.trim()));
|
|
1486
|
-
const count = values.length;
|
|
1487
|
-
lines.push(`${indent}{`);
|
|
1488
|
-
const innerIndent = indent + INDENT;
|
|
1489
|
-
const styleVar = buildStyleVar(node.style, innerIndent, lines);
|
|
1490
|
-
lines.push(`${innerIndent}float ${varName}[] = {${values.join(', ')}};`);
|
|
1491
1511
|
const overlay = node.overlay ? `, ${node.overlay}` : ', nullptr';
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1512
|
+
// Check if values is a variable/property access (struct binding) vs literal array
|
|
1513
|
+
if (node.values.includes('.') || /^[a-zA-Z_]\w*$/.test(node.values)) {
|
|
1514
|
+
lines.push(`${indent}{`);
|
|
1515
|
+
const innerIndent = indent + INDENT;
|
|
1516
|
+
const styleVar = buildStyleVar(node.style, innerIndent, lines);
|
|
1517
|
+
const styleArg = styleVar ? `, ${styleVar}` : '';
|
|
1518
|
+
lines.push(`${innerIndent}imx::renderer::plot_lines(${node.label}, ${node.values}.data(), static_cast<int>(${node.values}.size())${overlay}${styleArg});`);
|
|
1519
|
+
lines.push(`${indent}}`);
|
|
1520
|
+
}
|
|
1521
|
+
else {
|
|
1522
|
+
const idx = plotCounter++;
|
|
1523
|
+
const varName = `_plot_${idx}`;
|
|
1524
|
+
const values = node.values.split(',').map(v => ensureFloatLiteral(v.trim()));
|
|
1525
|
+
const count = values.length;
|
|
1526
|
+
lines.push(`${indent}{`);
|
|
1527
|
+
const innerIndent = indent + INDENT;
|
|
1528
|
+
const styleVar = buildStyleVar(node.style, innerIndent, lines);
|
|
1529
|
+
const styleArg = styleVar ? `, ${styleVar}` : '';
|
|
1530
|
+
lines.push(`${innerIndent}float ${varName}[] = {${values.join(', ')}};`);
|
|
1531
|
+
lines.push(`${innerIndent}imx::renderer::plot_lines(${node.label}, ${varName}, ${count}${overlay}${styleArg});`);
|
|
1532
|
+
lines.push(`${indent}}`);
|
|
1533
|
+
}
|
|
1495
1534
|
}
|
|
1496
1535
|
function emitPlotHistogram(node, lines, indent) {
|
|
1497
1536
|
emitLocComment(node.loc, 'PlotHistogram', lines, indent);
|
|
1498
|
-
const idx = plotCounter++;
|
|
1499
|
-
const varName = `_plot_${idx}`;
|
|
1500
|
-
const values = node.values.split(',').map(v => ensureFloatLiteral(v.trim()));
|
|
1501
|
-
const count = values.length;
|
|
1502
|
-
lines.push(`${indent}{`);
|
|
1503
|
-
const innerIndent = indent + INDENT;
|
|
1504
|
-
const styleVar = buildStyleVar(node.style, innerIndent, lines);
|
|
1505
|
-
lines.push(`${innerIndent}float ${varName}[] = {${values.join(', ')}};`);
|
|
1506
1537
|
const overlay = node.overlay ? `, ${node.overlay}` : ', nullptr';
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1538
|
+
if (node.values.includes('.') || /^[a-zA-Z_]\w*$/.test(node.values)) {
|
|
1539
|
+
lines.push(`${indent}{`);
|
|
1540
|
+
const innerIndent = indent + INDENT;
|
|
1541
|
+
const styleVar = buildStyleVar(node.style, innerIndent, lines);
|
|
1542
|
+
const styleArg = styleVar ? `, ${styleVar}` : '';
|
|
1543
|
+
lines.push(`${innerIndent}imx::renderer::plot_histogram(${node.label}, ${node.values}.data(), static_cast<int>(${node.values}.size())${overlay}${styleArg});`);
|
|
1544
|
+
lines.push(`${indent}}`);
|
|
1545
|
+
}
|
|
1546
|
+
else {
|
|
1547
|
+
const idx = plotCounter++;
|
|
1548
|
+
const varName = `_plot_${idx}`;
|
|
1549
|
+
const values = node.values.split(',').map(v => ensureFloatLiteral(v.trim()));
|
|
1550
|
+
const count = values.length;
|
|
1551
|
+
lines.push(`${indent}{`);
|
|
1552
|
+
const innerIndent = indent + INDENT;
|
|
1553
|
+
const styleVar = buildStyleVar(node.style, innerIndent, lines);
|
|
1554
|
+
const styleArg = styleVar ? `, ${styleVar}` : '';
|
|
1555
|
+
lines.push(`${innerIndent}float ${varName}[] = {${values.join(', ')}};`);
|
|
1556
|
+
lines.push(`${innerIndent}imx::renderer::plot_histogram(${node.label}, ${varName}, ${count}${overlay}${styleArg});`);
|
|
1557
|
+
lines.push(`${indent}}`);
|
|
1558
|
+
}
|
|
1510
1559
|
}
|
|
1511
1560
|
function emitImage(node, lines, indent) {
|
|
1512
1561
|
emitLocComment(node.loc, 'Image', lines, indent);
|
package/dist/ir.d.ts
CHANGED
|
@@ -99,6 +99,7 @@ export interface IRListMap {
|
|
|
99
99
|
kind: 'list_map';
|
|
100
100
|
array: string;
|
|
101
101
|
itemVar: string;
|
|
102
|
+
indexVar: string;
|
|
102
103
|
key: string;
|
|
103
104
|
componentName: string;
|
|
104
105
|
stateCount: number;
|
|
@@ -203,6 +204,8 @@ export interface IRColorEdit {
|
|
|
203
204
|
kind: 'color_edit';
|
|
204
205
|
label: string;
|
|
205
206
|
stateVar: string;
|
|
207
|
+
valueExpr?: string;
|
|
208
|
+
onChangeExpr?: string;
|
|
206
209
|
directBind?: boolean;
|
|
207
210
|
style?: string;
|
|
208
211
|
loc?: SourceLoc;
|
|
@@ -281,6 +284,8 @@ export interface IRColorPicker {
|
|
|
281
284
|
kind: 'color_picker';
|
|
282
285
|
label: string;
|
|
283
286
|
stateVar: string;
|
|
287
|
+
valueExpr?: string;
|
|
288
|
+
onChangeExpr?: string;
|
|
284
289
|
directBind?: boolean;
|
|
285
290
|
style?: string;
|
|
286
291
|
loc?: SourceLoc;
|
package/dist/lowering.js
CHANGED
|
@@ -230,10 +230,14 @@ export function exprToCpp(node, ctx) {
|
|
|
230
230
|
else if (op === '!==')
|
|
231
231
|
op = '!=';
|
|
232
232
|
// String + non-string: JS string concatenation -> C++ std::string + std::to_string
|
|
233
|
-
if (op === '+'
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
if (op === '+') {
|
|
234
|
+
const leftIsString = ts.isStringLiteral(node.left) || ts.isNoSubstitutionTemplateLiteral(node.left) || inferExprType(node.left, ctx) === 'string';
|
|
235
|
+
const rightIsString = ts.isStringLiteral(node.right) || ts.isNoSubstitutionTemplateLiteral(node.right) || inferExprType(node.right, ctx) === 'string';
|
|
236
|
+
if (leftIsString && !rightIsString) {
|
|
237
|
+
return `(std::string(${left}) + std::to_string(${right})).c_str()`;
|
|
238
|
+
}
|
|
239
|
+
if (!leftIsString && rightIsString) {
|
|
240
|
+
return `(std::to_string(${left}) + std::string(${right})).c_str()`;
|
|
237
241
|
}
|
|
238
242
|
}
|
|
239
243
|
return `${left} ${op} ${right}`;
|
|
@@ -677,8 +681,12 @@ function lowerCheckbox(attrs, rawAttrs, body, ctx, loc) {
|
|
|
677
681
|
const onChangeRaw = rawAttrs.get('onChange');
|
|
678
682
|
if (onChangeRaw) {
|
|
679
683
|
onChangeExprStr = exprToCpp(onChangeRaw, ctx);
|
|
680
|
-
|
|
681
|
-
|
|
684
|
+
if (onChangeExprStr.startsWith('[')) {
|
|
685
|
+
// Lambda from arrow function — invoke it (IIFE)
|
|
686
|
+
onChangeExprStr = `(${onChangeExprStr})()`;
|
|
687
|
+
}
|
|
688
|
+
else if (!onChangeExprStr.endsWith(')')) {
|
|
689
|
+
// Plain identifier — make it a call
|
|
682
690
|
onChangeExprStr = `${onChangeExprStr}()`;
|
|
683
691
|
}
|
|
684
692
|
}
|
|
@@ -835,11 +843,15 @@ function lowerListMap(node, body, ctx, loc) {
|
|
|
835
843
|
const array = exprToCpp(propAccess.expression, ctx);
|
|
836
844
|
const callback = node.arguments[0];
|
|
837
845
|
let itemVar = 'item';
|
|
846
|
+
let indexVar = 'i';
|
|
838
847
|
let mapBody = [];
|
|
839
848
|
if (callback && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))) {
|
|
840
849
|
if (callback.parameters.length > 0 && ts.isIdentifier(callback.parameters[0].name)) {
|
|
841
850
|
itemVar = callback.parameters[0].name.text;
|
|
842
851
|
}
|
|
852
|
+
if (callback.parameters.length > 1 && ts.isIdentifier(callback.parameters[1].name)) {
|
|
853
|
+
indexVar = callback.parameters[1].name.text;
|
|
854
|
+
}
|
|
843
855
|
if (ts.isBlock(callback.body)) {
|
|
844
856
|
const ret = callback.body.statements.find(ts.isReturnStatement);
|
|
845
857
|
if (ret?.expression) {
|
|
@@ -854,7 +866,8 @@ function lowerListMap(node, body, ctx, loc) {
|
|
|
854
866
|
kind: 'list_map',
|
|
855
867
|
array,
|
|
856
868
|
itemVar,
|
|
857
|
-
|
|
869
|
+
indexVar,
|
|
870
|
+
key: indexVar,
|
|
858
871
|
componentName: 'ListItem',
|
|
859
872
|
stateCount: 0,
|
|
860
873
|
bufferCount: 0,
|
|
@@ -1051,11 +1064,30 @@ function lowerColorPicker(attrs, rawAttrs, body, ctx, loc) {
|
|
|
1051
1064
|
const label = attrs['label'] ?? '""';
|
|
1052
1065
|
const style = attrs['style'];
|
|
1053
1066
|
let stateVar = '';
|
|
1067
|
+
let valueExpr;
|
|
1068
|
+
let onChangeExpr;
|
|
1069
|
+
let directBind;
|
|
1054
1070
|
const valueRaw = rawAttrs.get('value');
|
|
1055
1071
|
if (valueRaw && ts.isIdentifier(valueRaw) && ctx.stateVars.has(valueRaw.text)) {
|
|
1056
1072
|
stateVar = valueRaw.text;
|
|
1057
1073
|
}
|
|
1058
|
-
|
|
1074
|
+
else if (valueRaw) {
|
|
1075
|
+
valueExpr = exprToCpp(valueRaw, ctx);
|
|
1076
|
+
const onChangeRaw = rawAttrs.get('onChange');
|
|
1077
|
+
if (onChangeRaw) {
|
|
1078
|
+
onChangeExpr = exprToCpp(onChangeRaw, ctx);
|
|
1079
|
+
if (onChangeExpr.startsWith('[')) {
|
|
1080
|
+
onChangeExpr = `(${onChangeExpr})()`;
|
|
1081
|
+
}
|
|
1082
|
+
else if (!onChangeExpr.endsWith(')')) {
|
|
1083
|
+
onChangeExpr = `${onChangeExpr}()`;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
else if (valueRaw && ts.isPropertyAccessExpression(valueRaw)) {
|
|
1087
|
+
directBind = true;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
body.push({ kind: 'color_picker', label, stateVar, valueExpr, onChangeExpr, directBind, style, loc });
|
|
1059
1091
|
}
|
|
1060
1092
|
function lowerPlotLines(attrs, body, ctx, loc) {
|
|
1061
1093
|
const label = attrs['label'] ?? '""';
|
|
@@ -1137,7 +1169,12 @@ function lowerValueOnChange(rawAttrs, ctx) {
|
|
|
1137
1169
|
const onChangeRaw = rawAttrs.get('onChange');
|
|
1138
1170
|
if (onChangeRaw) {
|
|
1139
1171
|
onChangeExpr = exprToCpp(onChangeRaw, ctx);
|
|
1140
|
-
if (
|
|
1172
|
+
if (onChangeExpr.startsWith('[')) {
|
|
1173
|
+
// Lambda from arrow function — invoke it (IIFE)
|
|
1174
|
+
onChangeExpr = `(${onChangeExpr})()`;
|
|
1175
|
+
}
|
|
1176
|
+
else if (!onChangeExpr.endsWith(')')) {
|
|
1177
|
+
// Plain identifier — make it a call
|
|
1141
1178
|
onChangeExpr = `${onChangeExpr}()`;
|
|
1142
1179
|
}
|
|
1143
1180
|
}
|
|
@@ -1201,13 +1238,31 @@ function lowerInputFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
|
1201
1238
|
function lowerColorEdit(attrs, rawAttrs, body, ctx, loc) {
|
|
1202
1239
|
const label = attrs['label'] ?? '""';
|
|
1203
1240
|
const style = attrs['style'];
|
|
1204
|
-
// ColorEdit only supports state-bound values
|
|
1205
1241
|
let stateVar = '';
|
|
1242
|
+
let valueExpr;
|
|
1243
|
+
let onChangeExpr;
|
|
1244
|
+
let directBind;
|
|
1206
1245
|
const valueRaw = rawAttrs.get('value');
|
|
1207
1246
|
if (valueRaw && ts.isIdentifier(valueRaw) && ctx.stateVars.has(valueRaw.text)) {
|
|
1208
1247
|
stateVar = valueRaw.text;
|
|
1209
1248
|
}
|
|
1210
|
-
|
|
1249
|
+
else if (valueRaw) {
|
|
1250
|
+
valueExpr = exprToCpp(valueRaw, ctx);
|
|
1251
|
+
const onChangeRaw = rawAttrs.get('onChange');
|
|
1252
|
+
if (onChangeRaw) {
|
|
1253
|
+
onChangeExpr = exprToCpp(onChangeRaw, ctx);
|
|
1254
|
+
if (onChangeExpr.startsWith('[')) {
|
|
1255
|
+
onChangeExpr = `(${onChangeExpr})()`;
|
|
1256
|
+
}
|
|
1257
|
+
else if (!onChangeExpr.endsWith(')')) {
|
|
1258
|
+
onChangeExpr = `${onChangeExpr}()`;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
else if (valueRaw && ts.isPropertyAccessExpression(valueRaw)) {
|
|
1262
|
+
directBind = true;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
body.push({ kind: 'color_edit', label, stateVar, valueExpr, onChangeExpr, directBind, style, loc });
|
|
1211
1266
|
}
|
|
1212
1267
|
function lowerListBox(attrs, rawAttrs, body, ctx, loc) {
|
|
1213
1268
|
const label = attrs['label'] ?? '""';
|