greybel-interpreter 5.6.2 → 6.0.1

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 CHANGED
@@ -1,3 +1,73 @@
1
1
  # greybel-interpreter
2
2
 
3
- [![greybel-interpreter](https://circleci.com/gh/ayecue/greybel-interpreter.svg?style=svg)](https://circleci.com/gh/ayecue/greybel-interpreter)
3
+ [![greybel-interpreter](https://circleci.com/gh/ayecue/greybel-interpreter.svg?style=svg)](https://circleci.com/gh/ayecue/greybel-interpreter)
4
+
5
+ A bytecode interpreter for [MiniScript](https://miniscript.org) written in TypeScript. It compiles MiniScript source code to bytecode and executes it in a stack-based VM built on top of [greybel-core](../greybel-core). For GreyScript-specific interpretation, see [greyscript-interpreter](../greyscript-interpreter).
6
+
7
+ ## Features
8
+
9
+ * Bytecode compiler that converts AST to efficient instructions
10
+ * Stack-based virtual machine with non-blocking scheduling
11
+ * Built-in type system: string, number, boolean, list, map, function, and nil
12
+ * Pluggable handler system for resource loading, output, and error handling
13
+ * Debugger support with breakpoints and step-through execution
14
+ * Code injection at runtime via `interpreter.inject()`
15
+ * Environment variable injection
16
+ * Extensible API surface - supply custom intrinsics via an `ObjectValue` map
17
+ * Runs in both Node.js and the browser (includes Rollup bundle config)
18
+ * Written in TypeScript with type definitions included
19
+
20
+ ## Install
21
+
22
+ ```
23
+ npm install greybel-interpreter
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```ts
29
+ import { Interpreter, HandlerContainer } from 'greybel-interpreter';
30
+
31
+ const interpreter = new Interpreter({
32
+ target: '/path/to/main.src',
33
+ handler: new HandlerContainer(),
34
+ environmentVariables: new Map([['MY_VAR', '123']])
35
+ });
36
+
37
+ await interpreter.run();
38
+ ```
39
+
40
+ ### Custom intrinsics
41
+
42
+ ```ts
43
+ import {
44
+ Interpreter,
45
+ CustomFunction,
46
+ CustomString,
47
+ DefaultType,
48
+ ObjectValue
49
+ } from 'greybel-interpreter';
50
+
51
+ const api = new ObjectValue();
52
+
53
+ api.set(
54
+ new CustomString('exit'),
55
+ CustomFunction.createExternal('exit', (fnCtx, self, args) => {
56
+ interpreter.exit();
57
+ return Promise.resolve(DefaultType.Void);
58
+ })
59
+ );
60
+
61
+ const interpreter = new Interpreter({
62
+ target: '/path/to/main.src',
63
+ api
64
+ });
65
+
66
+ await interpreter.run();
67
+ ```
68
+
69
+ ## Testing
70
+
71
+ ```
72
+ npm test
73
+ ```
@@ -40,8 +40,8 @@ class Context {
40
40
  return {
41
41
  name: name !== null && name !== void 0 ? name : node.type,
42
42
  path: target,
43
- start: node.start,
44
- end: node.end
43
+ start: { line: node.startLine, character: node.startChar },
44
+ end: { line: node.endLine, character: node.endChar }
45
45
  };
46
46
  }
47
47
  getInternalLocation() {
@@ -91,7 +91,7 @@ class BytecodeExpressionGenerator {
91
91
  case greybel_core_1.ASTType.FeatureLineExpression:
92
92
  this.context.pushCode({
93
93
  op: instruction_1.OpCode.PUSH,
94
- value: new number_1.CustomNumber(node.start.line)
94
+ value: new number_1.CustomNumber(node.startLine)
95
95
  }, node);
96
96
  return;
97
97
  case greybel_core_1.ASTType.FeatureFileExpression:
@@ -100,13 +100,11 @@ class BytecodeExpressionGenerator {
100
100
  value: new string_1.CustomString((0, path_1.basename)(this.context.target.peek()))
101
101
  }, node);
102
102
  return;
103
- case miniscript_core_1.ASTType.Comment:
104
- return;
105
103
  case miniscript_core_1.ASTType.ComparisonGroupExpression:
106
104
  yield this.processComparisonGroupExpression(node);
107
105
  return;
108
106
  default: {
109
- const range = new miniscript_core_1.ASTRange(node.start, node.end);
107
+ const range = new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar]);
110
108
  throw new error_1.PrepareError(`Unexpected AST type ${node.type}`, {
111
109
  target: this.context.target.peek(),
112
110
  range
@@ -486,7 +484,7 @@ class BytecodeExpressionGenerator {
486
484
  const importTarget = yield this.context.handler.resourceHandler.getTargetRelativeTo(currentTarget, node.path);
487
485
  const content = yield this.context.handler.resourceHandler.get(importTarget);
488
486
  if (content == null) {
489
- const range = new miniscript_core_1.ASTRange(node.start, node.end);
487
+ const range = new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar]);
490
488
  throw new error_1.PrepareError(`Cannot find injection "${currentTarget}"`, {
491
489
  target: currentTarget,
492
490
  range
@@ -531,7 +529,7 @@ BytecodeExpressionGenerator.binaryExpressionToOp = {
531
529
  [miniscript_core_1.Operator.GreaterThanOrEqual]: instruction_1.OpCode.GREATER_THAN_OR_EQUAL,
532
530
  [miniscript_core_1.Operator.Plus]: instruction_1.OpCode.ADD,
533
531
  [miniscript_core_1.Operator.Minus]: instruction_1.OpCode.SUB,
534
- [miniscript_core_1.Operator.Asterik]: instruction_1.OpCode.MUL,
532
+ [miniscript_core_1.Operator.Asterisk]: instruction_1.OpCode.MUL,
535
533
  [miniscript_core_1.Operator.Slash]: instruction_1.OpCode.DIV,
536
534
  [miniscript_core_1.Operator.Modulo]: instruction_1.OpCode.MOD,
537
535
  [miniscript_core_1.Operator.Power]: instruction_1.OpCode.POW,
@@ -1,4 +1,3 @@
1
- import { ASTPosition } from 'miniscript-core';
2
1
  import { CustomValue } from '../types/base';
3
2
  import { CustomFunctionCallback } from '../types/function';
4
3
  import { CustomString } from '../types/string';
@@ -70,8 +69,14 @@ export interface FunctionDefinitionInstructionArgument {
70
69
  export type SourceLocation = {
71
70
  name: string;
72
71
  path: string;
73
- start: ASTPosition;
74
- end: ASTPosition;
72
+ start: {
73
+ line: number;
74
+ character: number;
75
+ };
76
+ end: {
77
+ line: number;
78
+ character: number;
79
+ };
75
80
  };
76
81
  export interface BaseInstruction {
77
82
  op: OpCode;
@@ -109,7 +109,6 @@ class BytecodeStatementGenerator {
109
109
  yield this.processForGenericStatement(node);
110
110
  return;
111
111
  case miniscript_core_1.ASTType.EmptyExpression:
112
- case miniscript_core_1.ASTType.Comment:
113
112
  return;
114
113
  case greybel_core_1.ASTType.FeatureInjectExpression:
115
114
  return;
@@ -125,7 +124,7 @@ class BytecodeStatementGenerator {
125
124
  yield this.processDebuggerExpression(node);
126
125
  return;
127
126
  default: {
128
- const range = new miniscript_core_1.ASTRange(node.start, node.end);
127
+ const range = new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar]);
129
128
  throw new error_1.PrepareError(`Unexpected AST type ${node.type}`, {
130
129
  target: this.context.target.peek(),
131
130
  range
@@ -633,7 +632,7 @@ class BytecodeStatementGenerator {
633
632
  }
634
633
  throw new error_1.PrepareError(err.message, {
635
634
  target: path,
636
- range: new miniscript_core_1.ASTRange(node.start, node.end)
635
+ range: new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar])
637
636
  }, err);
638
637
  }
639
638
  });
@@ -643,13 +642,13 @@ class BytecodeStatementGenerator {
643
642
  const currentTarget = this.context.target.peek();
644
643
  const importTarget = yield this.context.handler.resourceHandler.getTargetRelativeTo(currentTarget, node.path);
645
644
  if (this.context.target.includes(importTarget)) {
646
- console.warn(`Found circular dependency between "${currentTarget}" and "${importTarget}" at line ${node.start.line}. Using noop instead to prevent overflow.`);
645
+ console.warn(`Found circular dependency between "${currentTarget}" and "${importTarget}" at line ${node.startLine}. Using noop instead to prevent overflow.`);
647
646
  return;
648
647
  }
649
648
  if (!this.context.imports.has(importTarget)) {
650
649
  const code = yield this.context.handler.resourceHandler.get(importTarget);
651
650
  if (code == null) {
652
- const range = new miniscript_core_1.ASTRange(node.start, node.end);
651
+ const range = new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar]);
653
652
  throw new error_1.PrepareError(`Cannot find import "${currentTarget}"`, {
654
653
  target: currentTarget,
655
654
  range
@@ -679,15 +678,18 @@ class BytecodeStatementGenerator {
679
678
  }
680
679
  processIncludeExpression(node) {
681
680
  return __awaiter(this, void 0, void 0, function* () {
681
+ if (node.typeOnly) {
682
+ return;
683
+ }
682
684
  const currentTarget = this.context.target.peek();
683
685
  const importTarget = yield this.context.handler.resourceHandler.getTargetRelativeTo(currentTarget, node.path);
684
686
  if (this.context.target.includes(importTarget)) {
685
- console.warn(`Found circular dependency between "${currentTarget}" and "${importTarget}" at line ${node.start.line}. Using noop instead to prevent overflow.`);
687
+ console.warn(`Found circular dependency between "${currentTarget}" and "${importTarget}" at line ${node.startLine}. Using noop instead to prevent overflow.`);
686
688
  return;
687
689
  }
688
690
  const code = yield this.context.handler.resourceHandler.get(importTarget);
689
691
  if (code == null) {
690
- const range = new miniscript_core_1.ASTRange(node.start, node.end);
692
+ const range = new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar]);
691
693
  throw new error_1.PrepareError(`Cannot find import "${currentTarget}"`, {
692
694
  target: currentTarget,
693
695
  range
@@ -705,7 +707,7 @@ class BytecodeStatementGenerator {
705
707
  }
706
708
  throw new error_1.PrepareError(err.message, {
707
709
  target: importTarget,
708
- range: new miniscript_core_1.ASTRange(node.start, node.end)
710
+ range: new miniscript_core_1.ASTRange([node.startLine, node.startChar], [node.endLine, node.endChar])
709
711
  }, err);
710
712
  }
711
713
  });
@@ -10,9 +10,13 @@ export interface BytecodeConverterOptions {
10
10
  handler: HandlerContainer;
11
11
  debugMode?: boolean;
12
12
  context?: Context;
13
+ environmentVariables?: Map<string, string>;
14
+ strictMode?: boolean;
13
15
  }
14
16
  export declare class BytecodeGenerator {
15
17
  protected context: Context;
18
+ protected environmentVariables: Map<string, string>;
19
+ protected strictMode: boolean;
16
20
  constructor(options: BytecodeConverterOptions);
17
21
  compile(code: string): Promise<BytecodeCompileResult>;
18
22
  }
@@ -17,7 +17,10 @@ const greybel_core_1 = require("greybel-core");
17
17
  const error_1 = require("./utils/error");
18
18
  const parse = function (code) {
19
19
  try {
20
- const parser = new greybel_core_1.Parser(code);
20
+ const parser = new greybel_core_1.Parser(code, {
21
+ environmentVariables: this.environmentVariables,
22
+ strictMode: this.strictMode
23
+ });
21
24
  return parser.parseChunk();
22
25
  }
23
26
  catch (err) {
@@ -34,12 +37,14 @@ const parse = function (code) {
34
37
  };
35
38
  class BytecodeGenerator {
36
39
  constructor(options) {
37
- var _a;
40
+ var _a, _b, _c;
38
41
  this.context = (_a = options.context) !== null && _a !== void 0 ? _a : new context_1.Context({
39
42
  target: options.target,
40
43
  handler: options.handler,
41
44
  debugMode: options.debugMode
42
45
  });
46
+ this.environmentVariables = (_b = options.environmentVariables) !== null && _b !== void 0 ? _b : new Map();
47
+ this.strictMode = (_c = options.strictMode) !== null && _c !== void 0 ? _c : false;
43
48
  }
44
49
  compile(code) {
45
50
  return __awaiter(this, void 0, void 0, function* () {
@@ -17,6 +17,7 @@ export interface InterpreterOptions {
17
17
  debugger?: Debugger;
18
18
  debugMode?: boolean;
19
19
  environmentVariables?: Map<string, string>;
20
+ strictMode?: boolean;
20
21
  }
21
22
  export interface InterpreterRunOptions {
22
23
  customCode?: string;
@@ -27,6 +28,7 @@ export declare class Interpreter extends EventEmitter {
27
28
  api: ObjectValue;
28
29
  params: Array<string>;
29
30
  environmentVariables: Map<string, string>;
31
+ strictMode: boolean;
30
32
  handler: HandlerContainer;
31
33
  debugger: Debugger;
32
34
  debugMode: boolean;
@@ -28,7 +28,7 @@ exports.PARAMS_PROPERTY = new string_1.CustomString('params');
28
28
  exports.IS_GREYBEL_PROPERTY = new string_1.CustomString('IS_GREYBEL');
29
29
  class Interpreter extends events_1.EventEmitter {
30
30
  constructor(options = {}) {
31
- var _a, _b, _c, _d, _e, _f, _g;
31
+ var _a, _b, _c, _d, _e, _f, _g, _h;
32
32
  super();
33
33
  this.handler = (_a = options.handler) !== null && _a !== void 0 ? _a : new handler_container_1.HandlerContainer();
34
34
  this.debugger = (_b = options.debugger) !== null && _b !== void 0 ? _b : new vm_1.Debugger();
@@ -36,10 +36,11 @@ class Interpreter extends events_1.EventEmitter {
36
36
  this.api = (_c = options.api) !== null && _c !== void 0 ? _c : new object_value_1.ObjectValue();
37
37
  this.params = (_d = options.params) !== null && _d !== void 0 ? _d : [];
38
38
  this.environmentVariables = (_e = options.environmentVariables) !== null && _e !== void 0 ? _e : new Map();
39
- this.debugMode = (_f = options.debugMode) !== null && _f !== void 0 ? _f : false;
39
+ this.strictMode = (_f = options.strictMode) !== null && _f !== void 0 ? _f : false;
40
+ this.debugMode = (_g = options.debugMode) !== null && _g !== void 0 ? _g : false;
40
41
  this.apiContext = null;
41
42
  this.globalContext = null;
42
- this.setTarget((_g = options.target) !== null && _g !== void 0 ? _g : 'unknown');
43
+ this.setTarget((_h = options.target) !== null && _h !== void 0 ? _h : 'unknown');
43
44
  }
44
45
  setTarget(target) {
45
46
  if (this.vm !== null && this.vm.isPending()) {
@@ -73,7 +74,9 @@ class Interpreter extends events_1.EventEmitter {
73
74
  return __awaiter(this, void 0, void 0, function* () {
74
75
  const bytecodeGenerator = new bytecode_generator_1.BytecodeGenerator({
75
76
  target: 'injected',
76
- handler: this.handler
77
+ handler: this.handler,
78
+ environmentVariables: this.environmentVariables,
79
+ strictMode: this.strictMode
77
80
  });
78
81
  const result = yield bytecodeGenerator.compile(code);
79
82
  const vm = new vm_1.VM({
@@ -171,7 +174,9 @@ class Interpreter extends events_1.EventEmitter {
171
174
  const bytecodeConverter = new bytecode_generator_1.BytecodeGenerator({
172
175
  target: this.target,
173
176
  handler: this.handler,
174
- debugMode: this.debugMode
177
+ debugMode: this.debugMode,
178
+ environmentVariables: this.environmentVariables,
179
+ strictMode: this.strictMode
175
180
  });
176
181
  const bytecode = yield bytecodeConverter.compile(code);
177
182
  this.initVM(bytecode, vmOptions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "greybel-interpreter",
3
- "version": "5.6.2",
3
+ "version": "6.0.1",
4
4
  "description": "Interpreter",
5
5
  "main": "dist/index",
6
6
  "typings": "dist/index",
@@ -50,7 +50,7 @@
50
50
  "typescript": "^5.0.4"
51
51
  },
52
52
  "dependencies": {
53
- "greybel-core": "~2.6.0",
53
+ "greybel-core": "~3.0.1",
54
54
  "hyperid": "^3.2.0",
55
55
  "imurmurhash": "^0.1.4",
56
56
  "non-blocking-schedule": "^0.2.0"