imxc 0.4.0 → 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 +75 -13
- 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
|
}
|
|
@@ -727,8 +735,15 @@ function lowerTextElement(node, body, ctx, loc) {
|
|
|
727
735
|
args.push(cppExpr);
|
|
728
736
|
break;
|
|
729
737
|
case 'float':
|
|
730
|
-
|
|
731
|
-
|
|
738
|
+
if (cppExpr.startsWith('props.')) {
|
|
739
|
+
// Props fields: number could be int or float in C++, cast to double for safe printf
|
|
740
|
+
format += '%g';
|
|
741
|
+
args.push(`(double)${cppExpr}`);
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
format += '%.2f';
|
|
745
|
+
args.push(cppExpr);
|
|
746
|
+
}
|
|
732
747
|
break;
|
|
733
748
|
case 'bool':
|
|
734
749
|
format += '%s';
|
|
@@ -828,11 +843,15 @@ function lowerListMap(node, body, ctx, loc) {
|
|
|
828
843
|
const array = exprToCpp(propAccess.expression, ctx);
|
|
829
844
|
const callback = node.arguments[0];
|
|
830
845
|
let itemVar = 'item';
|
|
846
|
+
let indexVar = 'i';
|
|
831
847
|
let mapBody = [];
|
|
832
848
|
if (callback && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))) {
|
|
833
849
|
if (callback.parameters.length > 0 && ts.isIdentifier(callback.parameters[0].name)) {
|
|
834
850
|
itemVar = callback.parameters[0].name.text;
|
|
835
851
|
}
|
|
852
|
+
if (callback.parameters.length > 1 && ts.isIdentifier(callback.parameters[1].name)) {
|
|
853
|
+
indexVar = callback.parameters[1].name.text;
|
|
854
|
+
}
|
|
836
855
|
if (ts.isBlock(callback.body)) {
|
|
837
856
|
const ret = callback.body.statements.find(ts.isReturnStatement);
|
|
838
857
|
if (ret?.expression) {
|
|
@@ -847,7 +866,8 @@ function lowerListMap(node, body, ctx, loc) {
|
|
|
847
866
|
kind: 'list_map',
|
|
848
867
|
array,
|
|
849
868
|
itemVar,
|
|
850
|
-
|
|
869
|
+
indexVar,
|
|
870
|
+
key: indexVar,
|
|
851
871
|
componentName: 'ListItem',
|
|
852
872
|
stateCount: 0,
|
|
853
873
|
bufferCount: 0,
|
|
@@ -1044,11 +1064,30 @@ function lowerColorPicker(attrs, rawAttrs, body, ctx, loc) {
|
|
|
1044
1064
|
const label = attrs['label'] ?? '""';
|
|
1045
1065
|
const style = attrs['style'];
|
|
1046
1066
|
let stateVar = '';
|
|
1067
|
+
let valueExpr;
|
|
1068
|
+
let onChangeExpr;
|
|
1069
|
+
let directBind;
|
|
1047
1070
|
const valueRaw = rawAttrs.get('value');
|
|
1048
1071
|
if (valueRaw && ts.isIdentifier(valueRaw) && ctx.stateVars.has(valueRaw.text)) {
|
|
1049
1072
|
stateVar = valueRaw.text;
|
|
1050
1073
|
}
|
|
1051
|
-
|
|
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 });
|
|
1052
1091
|
}
|
|
1053
1092
|
function lowerPlotLines(attrs, body, ctx, loc) {
|
|
1054
1093
|
const label = attrs['label'] ?? '""';
|
|
@@ -1130,7 +1169,12 @@ function lowerValueOnChange(rawAttrs, ctx) {
|
|
|
1130
1169
|
const onChangeRaw = rawAttrs.get('onChange');
|
|
1131
1170
|
if (onChangeRaw) {
|
|
1132
1171
|
onChangeExpr = exprToCpp(onChangeRaw, ctx);
|
|
1133
|
-
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
|
|
1134
1178
|
onChangeExpr = `${onChangeExpr}()`;
|
|
1135
1179
|
}
|
|
1136
1180
|
}
|
|
@@ -1194,13 +1238,31 @@ function lowerInputFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
|
1194
1238
|
function lowerColorEdit(attrs, rawAttrs, body, ctx, loc) {
|
|
1195
1239
|
const label = attrs['label'] ?? '""';
|
|
1196
1240
|
const style = attrs['style'];
|
|
1197
|
-
// ColorEdit only supports state-bound values
|
|
1198
1241
|
let stateVar = '';
|
|
1242
|
+
let valueExpr;
|
|
1243
|
+
let onChangeExpr;
|
|
1244
|
+
let directBind;
|
|
1199
1245
|
const valueRaw = rawAttrs.get('value');
|
|
1200
1246
|
if (valueRaw && ts.isIdentifier(valueRaw) && ctx.stateVars.has(valueRaw.text)) {
|
|
1201
1247
|
stateVar = valueRaw.text;
|
|
1202
1248
|
}
|
|
1203
|
-
|
|
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 });
|
|
1204
1266
|
}
|
|
1205
1267
|
function lowerListBox(attrs, rawAttrs, body, ctx, loc) {
|
|
1206
1268
|
const label = attrs['label'] ?? '""';
|