@creationix/rex 0.4.1 → 0.6.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/README.md +24 -0
- package/package.json +9 -6
- package/rex-cli.js +785 -987
- package/rex-cli.ts +236 -16
- package/rex-repl.js +592 -1005
- package/rex-repl.ts +389 -101
- package/rex.js +51 -845
- package/rex.ohm +7 -8
- package/rex.ohm-bundle.cjs +1 -1
- package/rex.ohm-bundle.d.ts +4 -3
- package/rex.ohm-bundle.js +1 -1
- package/rex.ts +52 -23
- package/rexc-interpreter.ts +136 -15
- package/rx-cli.js +2836 -0
- package/rx-cli.ts +298 -0
package/rexc-interpreter.ts
CHANGED
|
@@ -27,7 +27,6 @@ const OPCODES = {
|
|
|
27
27
|
mod: "md",
|
|
28
28
|
neg: "ng",
|
|
29
29
|
range: "rn",
|
|
30
|
-
size: "sz",
|
|
31
30
|
} as const;
|
|
32
31
|
|
|
33
32
|
export type RexcContext = {
|
|
@@ -47,7 +46,7 @@ export type RexcRuntimeState = {
|
|
|
47
46
|
|
|
48
47
|
type LoopControl = { kind: "break" | "continue"; depth: number };
|
|
49
48
|
|
|
50
|
-
type OpcodeMarker = { __opcode: string };
|
|
49
|
+
type OpcodeMarker = { __opcode: string; __receiver?: unknown };
|
|
51
50
|
|
|
52
51
|
function decodePrefix(text: string, start: number, end: number): number {
|
|
53
52
|
let value = 0;
|
|
@@ -328,7 +327,9 @@ class CursorInterpreter {
|
|
|
328
327
|
this.ensure(")");
|
|
329
328
|
|
|
330
329
|
if (typeof callee === "object" && callee && "__opcode" in callee) {
|
|
331
|
-
|
|
330
|
+
const marker = callee as OpcodeMarker;
|
|
331
|
+
const opArgs = marker.__receiver !== undefined ? [marker.__receiver, ...args] : args;
|
|
332
|
+
return this.applyOpcode(marker.__opcode as string, opArgs);
|
|
332
333
|
}
|
|
333
334
|
return this.navigate(callee, args);
|
|
334
335
|
}
|
|
@@ -737,10 +738,26 @@ class CursorInterpreter {
|
|
|
737
738
|
return args.length ? args[args.length - 1] : undefined;
|
|
738
739
|
case OPCODES.add:
|
|
739
740
|
if (args[0] === undefined || args[1] === undefined) return undefined;
|
|
740
|
-
if (
|
|
741
|
-
return
|
|
741
|
+
if (Array.isArray(args[0]) && Array.isArray(args[1])) {
|
|
742
|
+
return [...args[0], ...args[1]];
|
|
742
743
|
}
|
|
743
|
-
|
|
744
|
+
if (
|
|
745
|
+
args[0]
|
|
746
|
+
&& args[1]
|
|
747
|
+
&& typeof args[0] === "object"
|
|
748
|
+
&& typeof args[1] === "object"
|
|
749
|
+
&& !Array.isArray(args[0])
|
|
750
|
+
&& !Array.isArray(args[1])
|
|
751
|
+
) {
|
|
752
|
+
return { ...(args[0] as Record<string, unknown>), ...(args[1] as Record<string, unknown>) };
|
|
753
|
+
}
|
|
754
|
+
if (typeof args[0] === "string" && typeof args[1] === "string") {
|
|
755
|
+
return args[0] + args[1];
|
|
756
|
+
}
|
|
757
|
+
if (typeof args[0] === "number" && typeof args[1] === "number") {
|
|
758
|
+
return args[0] + args[1];
|
|
759
|
+
}
|
|
760
|
+
return undefined;
|
|
744
761
|
case OPCODES.sub:
|
|
745
762
|
if (args[0] === undefined || args[1] === undefined) return undefined;
|
|
746
763
|
return Number(args[0]) - Number(args[1]);
|
|
@@ -808,12 +825,74 @@ class CursorInterpreter {
|
|
|
808
825
|
out.push(v);
|
|
809
826
|
return out;
|
|
810
827
|
}
|
|
811
|
-
case
|
|
828
|
+
case "array:push": {
|
|
812
829
|
const target = args[0];
|
|
813
|
-
if (Array.isArray(target)) return
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
return
|
|
830
|
+
if (!Array.isArray(target)) return undefined;
|
|
831
|
+
const next = target.slice();
|
|
832
|
+
for (let i = 1; i < args.length; i += 1) next.push(args[i]);
|
|
833
|
+
return next;
|
|
834
|
+
}
|
|
835
|
+
case "array:pop": {
|
|
836
|
+
const target = args[0];
|
|
837
|
+
if (!Array.isArray(target) || target.length === 0) return undefined;
|
|
838
|
+
return target[target.length - 1];
|
|
839
|
+
}
|
|
840
|
+
case "array:unshift": {
|
|
841
|
+
const target = args[0];
|
|
842
|
+
if (!Array.isArray(target)) return undefined;
|
|
843
|
+
const next = target.slice();
|
|
844
|
+
for (let i = args.length - 1; i >= 1; i -= 1) next.unshift(args[i]);
|
|
845
|
+
return next;
|
|
846
|
+
}
|
|
847
|
+
case "array:shift": {
|
|
848
|
+
const target = args[0];
|
|
849
|
+
if (!Array.isArray(target) || target.length === 0) return undefined;
|
|
850
|
+
return target[0];
|
|
851
|
+
}
|
|
852
|
+
case "array:slice": {
|
|
853
|
+
const target = args[0];
|
|
854
|
+
if (!Array.isArray(target)) return undefined;
|
|
855
|
+
const start = args.length > 1 && args[1] !== undefined ? Number(args[1]) : undefined;
|
|
856
|
+
const end = args.length > 2 && args[2] !== undefined ? Number(args[2]) : undefined;
|
|
857
|
+
return target.slice(start, end);
|
|
858
|
+
}
|
|
859
|
+
case "array:join": {
|
|
860
|
+
const target = args[0];
|
|
861
|
+
if (!Array.isArray(target)) return undefined;
|
|
862
|
+
const sep = args.length > 1 && args[1] !== undefined ? String(args[1]) : ",";
|
|
863
|
+
return target.map((item) => String(item)).join(sep);
|
|
864
|
+
}
|
|
865
|
+
case "string:split": {
|
|
866
|
+
const target = args[0];
|
|
867
|
+
if (typeof target !== "string") return undefined;
|
|
868
|
+
if (args.length < 2 || args[1] === undefined) return [target];
|
|
869
|
+
return target.split(String(args[1]));
|
|
870
|
+
}
|
|
871
|
+
case "string:join": {
|
|
872
|
+
const target = args[0];
|
|
873
|
+
if (typeof target !== "string") return undefined;
|
|
874
|
+
const parts = Array.from(target);
|
|
875
|
+
const sep = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
|
|
876
|
+
return parts.join(sep);
|
|
877
|
+
}
|
|
878
|
+
case "string:slice": {
|
|
879
|
+
const target = args[0];
|
|
880
|
+
if (typeof target !== "string") return undefined;
|
|
881
|
+
const start = args.length > 1 && args[1] !== undefined ? Number(args[1]) : undefined;
|
|
882
|
+
const end = args.length > 2 && args[2] !== undefined ? Number(args[2]) : undefined;
|
|
883
|
+
return Array.from(target).slice(start, end).join("");
|
|
884
|
+
}
|
|
885
|
+
case "string:starts-with": {
|
|
886
|
+
const target = args[0];
|
|
887
|
+
if (typeof target !== "string") return undefined;
|
|
888
|
+
const prefix = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
|
|
889
|
+
return target.startsWith(prefix);
|
|
890
|
+
}
|
|
891
|
+
case "string:ends-with": {
|
|
892
|
+
const target = args[0];
|
|
893
|
+
if (typeof target !== "string") return undefined;
|
|
894
|
+
const suffix = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
|
|
895
|
+
return target.endsWith(suffix);
|
|
817
896
|
}
|
|
818
897
|
default:
|
|
819
898
|
throw new Error(`Unknown opcode ${id}`);
|
|
@@ -831,14 +910,20 @@ class CursorInterpreter {
|
|
|
831
910
|
}
|
|
832
911
|
|
|
833
912
|
private readProperty(target: unknown, key: unknown): unknown {
|
|
913
|
+
if (typeof key === "string" && key === "size") {
|
|
914
|
+
if (Array.isArray(target)) return target.length;
|
|
915
|
+
if (typeof target === "string") return Array.from(target).length;
|
|
916
|
+
}
|
|
834
917
|
const index = this.parseIndexKey(key);
|
|
835
918
|
if (Array.isArray(target)) {
|
|
836
|
-
if (index
|
|
837
|
-
return target
|
|
919
|
+
if (index !== undefined) return target[index];
|
|
920
|
+
if (typeof key === "string") return this.resolveArrayMethod(target, key);
|
|
921
|
+
return undefined;
|
|
838
922
|
}
|
|
839
923
|
if (typeof target === "string") {
|
|
840
|
-
if (index
|
|
841
|
-
return
|
|
924
|
+
if (index !== undefined) return Array.from(target)[index];
|
|
925
|
+
if (typeof key === "string") return this.resolveStringMethod(target, key);
|
|
926
|
+
return undefined;
|
|
842
927
|
}
|
|
843
928
|
if (this.isPlainObject(target)) {
|
|
844
929
|
const prop = String(key);
|
|
@@ -848,6 +933,42 @@ class CursorInterpreter {
|
|
|
848
933
|
return undefined;
|
|
849
934
|
}
|
|
850
935
|
|
|
936
|
+
private resolveArrayMethod(target: unknown[], key: string): OpcodeMarker | undefined {
|
|
937
|
+
switch (key) {
|
|
938
|
+
case "push":
|
|
939
|
+
return { __opcode: "array:push", __receiver: target };
|
|
940
|
+
case "pop":
|
|
941
|
+
return { __opcode: "array:pop", __receiver: target };
|
|
942
|
+
case "unshift":
|
|
943
|
+
return { __opcode: "array:unshift", __receiver: target };
|
|
944
|
+
case "shift":
|
|
945
|
+
return { __opcode: "array:shift", __receiver: target };
|
|
946
|
+
case "slice":
|
|
947
|
+
return { __opcode: "array:slice", __receiver: target };
|
|
948
|
+
case "join":
|
|
949
|
+
return { __opcode: "array:join", __receiver: target };
|
|
950
|
+
default:
|
|
951
|
+
return undefined;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
private resolveStringMethod(target: string, key: string): OpcodeMarker | undefined {
|
|
956
|
+
switch (key) {
|
|
957
|
+
case "split":
|
|
958
|
+
return { __opcode: "string:split", __receiver: target };
|
|
959
|
+
case "join":
|
|
960
|
+
return { __opcode: "string:join", __receiver: target };
|
|
961
|
+
case "slice":
|
|
962
|
+
return { __opcode: "string:slice", __receiver: target };
|
|
963
|
+
case "starts-with":
|
|
964
|
+
return { __opcode: "string:starts-with", __receiver: target };
|
|
965
|
+
case "ends-with":
|
|
966
|
+
return { __opcode: "string:ends-with", __receiver: target };
|
|
967
|
+
default:
|
|
968
|
+
return undefined;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
851
972
|
private canWriteProperty(target: unknown, key: unknown): { kind: "array"; index: number } | { kind: "object" } | undefined {
|
|
852
973
|
const index = this.parseIndexKey(key);
|
|
853
974
|
if (Array.isArray(target)) {
|