cashc 0.12.1 → 0.12.2

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.
@@ -0,0 +1,22 @@
1
+ import { ErrorListener, Recognizer } from 'antlr4';
2
+ export interface CashScriptErrorListener {
3
+ syntaxError(recognizer: unknown, offendingSymbol: unknown, line: number, charPositionInLine: number, message: string, e?: unknown): void;
4
+ }
5
+ /**
6
+ * Error listener that forwards syntax errors to another listener and stores the first error.
7
+ */
8
+ export declare class ForwardingErrorListener extends ErrorListener<unknown> implements CashScriptErrorListener {
9
+ private readonly errorListener;
10
+ private firstError?;
11
+ constructor(errorListener: CashScriptErrorListener);
12
+ syntaxError(recognizer: unknown, offendingSymbol: unknown, line: number, charPositionInLine: number, message: string, e?: unknown): void;
13
+ throwFirstError(): void;
14
+ }
15
+ /**
16
+ * ANTLR Error Listener that immediately throws on error. This is used so that
17
+ * ANTLR doesn't attempt any error recovery during lexing/parsing and fails early.
18
+ */
19
+ export declare class ThrowingErrorListener<TSymbol> extends ErrorListener<TSymbol> {
20
+ static readonly INSTANCE: ThrowingErrorListener<unknown>;
21
+ syntaxError(_recognizer: Recognizer<TSymbol>, _offendingSymbol: TSymbol, line: number, charPositionInLine: number, message: string): void;
22
+ }
@@ -0,0 +1,35 @@
1
+ import { ErrorListener } from 'antlr4';
2
+ import { ParseError } from '../Errors.js';
3
+ import { Point } from './Location.js';
4
+ /**
5
+ * Error listener that forwards syntax errors to another listener and stores the first error.
6
+ */
7
+ export class ForwardingErrorListener extends ErrorListener {
8
+ constructor(errorListener) {
9
+ super();
10
+ this.errorListener = errorListener;
11
+ }
12
+ syntaxError(recognizer, offendingSymbol, line, charPositionInLine, message, e) {
13
+ this.firstError ??= createParseError(line, charPositionInLine, message);
14
+ this.errorListener.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, message, e);
15
+ }
16
+ throwFirstError() {
17
+ if (this.firstError)
18
+ throw this.firstError;
19
+ }
20
+ }
21
+ /**
22
+ * ANTLR Error Listener that immediately throws on error. This is used so that
23
+ * ANTLR doesn't attempt any error recovery during lexing/parsing and fails early.
24
+ */
25
+ export class ThrowingErrorListener extends ErrorListener {
26
+ syntaxError(_recognizer, _offendingSymbol, line, charPositionInLine, message) {
27
+ throw createParseError(line, charPositionInLine, message);
28
+ }
29
+ }
30
+ ThrowingErrorListener.INSTANCE = new ThrowingErrorListener();
31
+ function createParseError(line, charPositionInLine, message) {
32
+ const capitalisedMessage = message.charAt(0).toUpperCase() + message.slice(1);
33
+ return new ParseError(capitalisedMessage, new Point(line, charPositionInLine));
34
+ }
35
+ //# sourceMappingURL=error-listeners.js.map
@@ -1,6 +1,10 @@
1
1
  import { Artifact } from '@cashscript/utils';
2
2
  import { PathLike } from 'fs';
3
3
  import { Ast } from './ast/AST.js';
4
- export declare function compileString(code: string): Artifact;
5
- export declare function compileFile(codeFile: PathLike): Artifact;
6
- export declare function parseCode(code: string): Ast;
4
+ import { CashScriptErrorListener } from './ast/error-listeners.js';
5
+ export interface CompileOptions {
6
+ errorListener?: CashScriptErrorListener;
7
+ }
8
+ export declare function compileString(code: string, compilerOptions?: CompileOptions): Artifact;
9
+ export declare function compileFile(codeFile: PathLike, compilerOptions?: CompileOptions): Artifact;
10
+ export declare function parseCode(code: string, errorListener?: CashScriptErrorListener): Ast;
package/dist/compiler.js CHANGED
@@ -1,19 +1,19 @@
1
1
  import { CharStream, CommonTokenStream } from 'antlr4';
2
2
  import { binToHex } from '@bitauth/libauth';
3
- import { generateSourceMap, optimiseBytecode, optimiseBytecodeOld, scriptToAsm, scriptToBytecode, sourceMapToLocationData } from '@cashscript/utils';
3
+ import { generateSourceMap, optimiseBytecode, optimiseBytecodeOld, scriptToAsm, scriptToBytecode, sourceMapToLocationData, } from '@cashscript/utils';
4
4
  import fs from 'fs';
5
5
  import { generateArtifact } from './artifact/Artifact.js';
6
6
  import AstBuilder from './ast/AstBuilder.js';
7
- import ThrowingErrorListener from './ast/ThrowingErrorListener.js';
7
+ import { ForwardingErrorListener, ThrowingErrorListener } from './ast/error-listeners.js';
8
8
  import GenerateTargetTraversal from './generation/GenerateTargetTraversal.js';
9
9
  import CashScriptLexer from './grammar/CashScriptLexer.js';
10
10
  import CashScriptParser from './grammar/CashScriptParser.js';
11
11
  import SymbolTableTraversal from './semantic/SymbolTableTraversal.js';
12
12
  import TypeCheckTraversal from './semantic/TypeCheckTraversal.js';
13
13
  import EnsureFinalRequireTraversal from './semantic/EnsureFinalRequireTraversal.js';
14
- export function compileString(code) {
14
+ export function compileString(code, compilerOptions = {}) {
15
15
  // Lexing + parsing
16
- let ast = parseCode(code);
16
+ let ast = parseCode(code, compilerOptions.errorListener);
17
17
  // Semantic analysis
18
18
  ast = ast.accept(new SymbolTableTraversal());
19
19
  ast = ast.accept(new TypeCheckTraversal());
@@ -39,22 +39,24 @@ export function compileString(code) {
39
39
  };
40
40
  return generateArtifact(ast, optimisationResult.script, code, debug);
41
41
  }
42
- export function compileFile(codeFile) {
42
+ export function compileFile(codeFile, compilerOptions = {}) {
43
43
  const code = fs.readFileSync(codeFile, { encoding: 'utf-8' });
44
- return compileString(code);
44
+ return compileString(code, compilerOptions);
45
45
  }
46
- export function parseCode(code) {
46
+ export function parseCode(code, errorListener = ThrowingErrorListener.INSTANCE) {
47
+ const syntaxErrorListener = new ForwardingErrorListener(errorListener);
47
48
  // Lexing (throwing on errors)
48
49
  const inputStream = new CharStream(code);
49
50
  const lexer = new CashScriptLexer(inputStream);
50
51
  lexer.removeErrorListeners();
51
- lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
52
+ lexer.addErrorListener(syntaxErrorListener);
52
53
  const tokenStream = new CommonTokenStream(lexer);
53
54
  // Parsing (throwing on errors)
54
55
  const parser = new CashScriptParser(tokenStream);
55
56
  parser.removeErrorListeners();
56
- parser.addErrorListener(ThrowingErrorListener.INSTANCE);
57
+ parser.addErrorListener(syntaxErrorListener);
57
58
  const parseTree = parser.sourceFile();
59
+ syntaxErrorListener.throwFirstError();
58
60
  // AST building
59
61
  const ast = new AstBuilder(parseTree).build();
60
62
  return ast;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './Errors.js';
2
2
  export * as utils from '@cashscript/utils';
3
- export { compileFile, compileString } from './compiler.js';
4
- export declare const version = "0.12.1";
3
+ export { compileFile, compileString, type CompileOptions } from './compiler.js';
4
+ export * from './ast/error-listeners.js';
5
+ export declare const version = "0.12.2";
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './Errors.js';
2
2
  export * as utils from '@cashscript/utils';
3
3
  export { compileFile, compileString } from './compiler.js';
4
- export const version = '0.12.1';
4
+ export * from './ast/error-listeners.js';
5
+ export const version = '0.12.2';
5
6
  //# sourceMappingURL=index.js.map
@@ -80,11 +80,13 @@ export default class SymbolTableTraversal extends AstTraversal {
80
80
  return node;
81
81
  }
82
82
  visitTupleAssignment(node) {
83
- [node.left, node.right].forEach(({ name, type }) => {
83
+ [node.left, node.right].forEach((variable) => {
84
+ const definition = createTupleVariableDefinition(node, variable);
85
+ const { name } = variable;
84
86
  if (this.symbolTables[0].get(name)) {
85
- throw new VariableRedefinitionError(new VariableDefinitionNode(type, [], name, node.tuple));
87
+ throw new VariableRedefinitionError(definition);
86
88
  }
87
- this.symbolTables[0].set(Symbol.variable(new VariableDefinitionNode(type, [], name, node.tuple)));
89
+ this.symbolTables[0].set(Symbol.variable(definition));
88
90
  });
89
91
  node.tuple = this.visit(node.tuple);
90
92
  return node;
@@ -127,4 +129,9 @@ export default class SymbolTableTraversal extends AstTraversal {
127
129
  return node;
128
130
  }
129
131
  }
132
+ function createTupleVariableDefinition(node, variable) {
133
+ const definition = new VariableDefinitionNode(variable.type, [], variable.name, node.tuple);
134
+ definition.location = node.location;
135
+ return definition;
136
+ }
130
137
  //# sourceMappingURL=SymbolTableTraversal.js.map
@@ -17,7 +17,9 @@ export default class TypeCheckTraversal extends AstTraversal {
17
17
  }
18
18
  const assignmentType = new TupleType(node.left.type, node.right.type);
19
19
  if (!implicitlyCastable(node.tuple.type, assignmentType)) {
20
- throw new AssignTypeError(new VariableDefinitionNode(assignmentType, [], node.left.name, node.tuple));
20
+ const syntheticAssignment = new VariableDefinitionNode(assignmentType, [], node.left.name, node.tuple);
21
+ syntheticAssignment.location = node.location;
22
+ throw new AssignTypeError(syntheticAssignment);
21
23
  }
22
24
  return node;
23
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cashc",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "description": "Compile Bitcoin Cash contracts to Bitcoin Cash Script or artifacts",
5
5
  "keywords": [
6
6
  "bitcoin",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@bitauth/libauth": "^3.1.0-next.8",
51
- "@cashscript/utils": "^0.12.1",
51
+ "@cashscript/utils": "^0.12.2",
52
52
  "antlr4": "^4.13.2",
53
53
  "commander": "^14.0.0",
54
54
  "semver": "^7.7.2"
@@ -65,5 +65,5 @@
65
65
  "url-join": "^5.0.0",
66
66
  "vitest": "^4.0.15"
67
67
  },
68
- "gitHead": "e2e12ba611bc0499891fb817e611eddd891c2313"
68
+ "gitHead": "5cde1601fe522646e5b85766b17a4b6387c7c4b5"
69
69
  }
@@ -1,9 +0,0 @@
1
- import { ErrorListener, RecognitionException, Recognizer } from 'antlr4';
2
- /**
3
- * ANTLR Error Listener that immediately throws on error. This is used so that
4
- * ANTLR doesn't attempt any error recovery during lexing/parsing and fails early.
5
- */
6
- export default class ThrowingErrorListener<TSymbol> extends ErrorListener<TSymbol> {
7
- static readonly INSTANCE: ThrowingErrorListener<unknown>;
8
- syntaxError(recognizer: Recognizer<TSymbol>, offendingSymbol: TSymbol, line: number, charPositionInLine: number, message: string, e?: RecognitionException): void;
9
- }
@@ -1,17 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import { ErrorListener } from 'antlr4';
3
- import { ParseError } from '../Errors.js';
4
- import { Point } from './Location.js';
5
- /**
6
- * ANTLR Error Listener that immediately throws on error. This is used so that
7
- * ANTLR doesn't attempt any error recovery during lexing/parsing and fails early.
8
- */
9
- class ThrowingErrorListener extends ErrorListener {
10
- syntaxError(recognizer, offendingSymbol, line, charPositionInLine, message, e) {
11
- const capitalisedMessage = message.charAt(0).toUpperCase() + message.slice(1);
12
- throw new ParseError(capitalisedMessage, new Point(line, charPositionInLine));
13
- }
14
- }
15
- ThrowingErrorListener.INSTANCE = new ThrowingErrorListener();
16
- export default ThrowingErrorListener;
17
- //# sourceMappingURL=ThrowingErrorListener.js.map