cashc 0.13.0 → 0.13.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.
- package/dist/Errors.d.ts +3 -2
- package/dist/Errors.js +3 -5
- package/dist/ast/error-listeners.d.ts +22 -0
- package/dist/ast/error-listeners.js +91 -0
- package/dist/compiler.d.ts +7 -3
- package/dist/compiler.js +10 -7
- package/dist/generation/GenerateTargetTraversal.d.ts +2 -0
- package/dist/generation/GenerateTargetTraversal.js +30 -9
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/semantic/SymbolTableTraversal.js +10 -3
- package/dist/semantic/TypeCheckTraversal.js +3 -1
- package/package.json +3 -3
- package/dist/ast/ThrowingErrorListener.d.ts +0 -9
- package/dist/ast/ThrowingErrorListener.js +0 -17
package/dist/Errors.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Type } from '@cashscript/utils';
|
|
2
2
|
import { IdentifierNode, FunctionDefinitionNode, VariableDefinitionNode, ParameterNode, Node, FunctionCallNode, BinaryOpNode, UnaryOpNode, TimeOpNode, CastNode, AssignNode, BranchNode, ArrayNode, TupleIndexOpNode, RequireNode, InstantiationNode, StatementNode, ContractNode, ExpressionNode, SliceNode } from './ast/AST.js';
|
|
3
3
|
import { Symbol, SymbolType } from './ast/SymbolTable.js';
|
|
4
|
-
import { Location
|
|
4
|
+
import { Location } from './ast/Location.js';
|
|
5
5
|
export declare class CashScriptError extends Error {
|
|
6
6
|
node: Node;
|
|
7
7
|
constructor(node: Node, message: string);
|
|
8
8
|
}
|
|
9
9
|
export declare class ParseError extends Error {
|
|
10
|
-
|
|
10
|
+
location: Location;
|
|
11
|
+
constructor(message: string, location: Location);
|
|
11
12
|
}
|
|
12
13
|
export declare class UndefinedReferenceError extends CashScriptError {
|
|
13
14
|
node: IdentifierNode;
|
package/dist/Errors.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { PrimitiveType } from '@cashscript/utils';
|
|
2
2
|
import { BinaryOpNode, UnaryOpNode, TimeOpNode, AssignNode, TupleIndexOpNode, RequireNode, SliceNode, IntLiteralNode, } from './ast/AST.js';
|
|
3
|
-
import { Point } from './ast/Location.js';
|
|
4
3
|
import { BinaryOperator } from './ast/Operator.js';
|
|
5
4
|
export class CashScriptError extends Error {
|
|
6
5
|
constructor(node, message) {
|
|
@@ -14,12 +13,11 @@ export class CashScriptError extends Error {
|
|
|
14
13
|
}
|
|
15
14
|
export class ParseError extends Error {
|
|
16
15
|
constructor(message, location) {
|
|
17
|
-
|
|
18
|
-
if (start) {
|
|
19
|
-
message += ` at ${start}`;
|
|
20
|
-
}
|
|
16
|
+
message += ` at ${location.start}`;
|
|
21
17
|
super(message);
|
|
18
|
+
this.location = location;
|
|
22
19
|
this.name = this.constructor.name;
|
|
20
|
+
this.location = location;
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
export class UndefinedReferenceError extends CashScriptError {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ErrorListener, RecognitionException, 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, _e?: RecognitionException): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ErrorListener, Token } from 'antlr4';
|
|
2
|
+
import { ParseError } from '../Errors.js';
|
|
3
|
+
import { Location, 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
|
+
const normalisedMessage = normaliseSyntaxErrorMessage(message, offendingSymbol);
|
|
14
|
+
this.firstError ??= createParseError(line, charPositionInLine, normalisedMessage, offendingSymbol);
|
|
15
|
+
this.errorListener.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, normalisedMessage, e);
|
|
16
|
+
}
|
|
17
|
+
throwFirstError() {
|
|
18
|
+
if (this.firstError)
|
|
19
|
+
throw this.firstError;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* ANTLR Error Listener that immediately throws on error. This is used so that
|
|
24
|
+
* ANTLR doesn't attempt any error recovery during lexing/parsing and fails early.
|
|
25
|
+
*/
|
|
26
|
+
export class ThrowingErrorListener extends ErrorListener {
|
|
27
|
+
syntaxError(_recognizer, offendingSymbol, line, charPositionInLine, message, _e) {
|
|
28
|
+
const normalisedMessage = normaliseSyntaxErrorMessage(message, offendingSymbol);
|
|
29
|
+
throw createParseError(line, charPositionInLine, normalisedMessage, offendingSymbol);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
ThrowingErrorListener.INSTANCE = new ThrowingErrorListener();
|
|
33
|
+
function createParseError(line, charPositionInLine, message, offendingSymbol) {
|
|
34
|
+
const capitalisedMessage = message.charAt(0).toUpperCase() + message.slice(1);
|
|
35
|
+
const token = getToken(offendingSymbol);
|
|
36
|
+
const location = getTokenLocation(token) ?? createEmptyLocation(line, charPositionInLine);
|
|
37
|
+
return new ParseError(capitalisedMessage, location);
|
|
38
|
+
}
|
|
39
|
+
function normaliseSyntaxErrorMessage(message, offendingSymbol) {
|
|
40
|
+
const token = getToken(offendingSymbol);
|
|
41
|
+
const tokenText = getTokenText(token);
|
|
42
|
+
if (!tokenText)
|
|
43
|
+
return message;
|
|
44
|
+
// There are 2 common error messages that we need to normalise:
|
|
45
|
+
const noViableAlternativeInput = getNoViableAlternativeInput(message);
|
|
46
|
+
const extraneousInput = isExtraneousInput(message, tokenText);
|
|
47
|
+
if (isBoundedBytesExpressionError(message, tokenText, noViableAlternativeInput)) {
|
|
48
|
+
return boundedBytesCastMessage(tokenText);
|
|
49
|
+
}
|
|
50
|
+
if (noViableAlternativeInput !== undefined || extraneousInput) {
|
|
51
|
+
return `Unexpected token '${tokenText}'`;
|
|
52
|
+
}
|
|
53
|
+
return message;
|
|
54
|
+
}
|
|
55
|
+
function isBoundedBytesExpressionError(message, tokenText, noViableAlternativeInput) {
|
|
56
|
+
if (!isBoundedBytesToken(tokenText))
|
|
57
|
+
return false;
|
|
58
|
+
return noViableAlternativeInput?.includes(`(${tokenText}`) || isExtraneousInput(message, tokenText);
|
|
59
|
+
}
|
|
60
|
+
function isBoundedBytesToken(tokenText) {
|
|
61
|
+
return tokenText === 'byte' || /^bytes[1-9][0-9]*$/.test(tokenText);
|
|
62
|
+
}
|
|
63
|
+
function boundedBytesCastMessage(typeName) {
|
|
64
|
+
const bound = typeName === 'byte' ? 1 : Number(typeName.slice('bytes'.length));
|
|
65
|
+
const unsafeCast = typeName === 'byte' ? 'unsafe_byte' : `unsafe_${typeName}`;
|
|
66
|
+
return `Invalid bounded bytes cast '${typeName}(...)'. Use 'toPaddedBytes(value, ${bound})' to convert an int or '${unsafeCast}(value)' for semantic bytes casts`;
|
|
67
|
+
}
|
|
68
|
+
function getNoViableAlternativeInput(message) {
|
|
69
|
+
return message.match(/^no viable alternative at input '([\s\S]*)'$/)?.[1];
|
|
70
|
+
}
|
|
71
|
+
function isExtraneousInput(message, tokenText) {
|
|
72
|
+
return message.startsWith(`extraneous input '${tokenText}'`);
|
|
73
|
+
}
|
|
74
|
+
function getToken(offendingSymbol) {
|
|
75
|
+
return offendingSymbol instanceof Token ? offendingSymbol : undefined;
|
|
76
|
+
}
|
|
77
|
+
function getTokenText(token) {
|
|
78
|
+
if (!token || token.type === Token.EOF || typeof token.text !== 'string' || token.text === '<EOF>') {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
return token.text;
|
|
82
|
+
}
|
|
83
|
+
function getTokenLocation(token) {
|
|
84
|
+
if (!token || !getTokenText(token))
|
|
85
|
+
return undefined;
|
|
86
|
+
return Location.fromToken(token);
|
|
87
|
+
}
|
|
88
|
+
function createEmptyLocation(line, column) {
|
|
89
|
+
return new Location(new Point(line, column), new Point(line, column));
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=error-listeners.js.map
|
package/dist/compiler.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { Artifact, CompilerOptions } from '@cashscript/utils';
|
|
2
2
|
import { PathLike } from 'fs';
|
|
3
3
|
import { Ast } from './ast/AST.js';
|
|
4
|
+
import { CashScriptErrorListener } from './ast/error-listeners.js';
|
|
4
5
|
export declare const DEFAULT_COMPILER_OPTIONS: CompilerOptions;
|
|
6
|
+
export interface CompileOptions extends CompilerOptions {
|
|
7
|
+
errorListener?: CashScriptErrorListener;
|
|
8
|
+
}
|
|
5
9
|
/**
|
|
6
10
|
* Compile a CashScript source string to an {@link Artifact}.
|
|
7
11
|
*
|
|
@@ -10,7 +14,7 @@ export declare const DEFAULT_COMPILER_OPTIONS: CompilerOptions;
|
|
|
10
14
|
* @returns The compiled CashScript artifact, including ABI, bytecode and debug information.
|
|
11
15
|
* @throws If the source code contains a syntax, semantic, or type error.
|
|
12
16
|
*/
|
|
13
|
-
export declare function compileString(code: string, compilerOptions?:
|
|
17
|
+
export declare function compileString(code: string, compilerOptions?: CompileOptions): Artifact;
|
|
14
18
|
/**
|
|
15
19
|
* Read a `.cash` source file from disk and compile it to an `Artifact`.
|
|
16
20
|
*
|
|
@@ -19,5 +23,5 @@ export declare function compileString(code: string, compilerOptions?: CompilerOp
|
|
|
19
23
|
* @returns The compiled CashScript artifact.
|
|
20
24
|
* @throws If the file cannot be read, or if the source contains a compilation error.
|
|
21
25
|
*/
|
|
22
|
-
export declare function compileFile(codeFile: PathLike, compilerOptions?:
|
|
23
|
-
export declare function parseCode(code: string): Ast;
|
|
26
|
+
export declare function compileFile(codeFile: PathLike, compilerOptions?: CompileOptions): Artifact;
|
|
27
|
+
export declare function parseCode(code: string, errorListener?: CashScriptErrorListener): Ast;
|
package/dist/compiler.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { CharStream, CommonTokenStream } from 'antlr4';
|
|
2
2
|
import { binToHex } from '@bitauth/libauth';
|
|
3
|
-
import { computeBytecodeFingerprintWithConstructorArgs, generateSourceMap, generateSourceTags, optimiseBytecode, optimiseBytecodeOld, scriptToAsm, scriptToBytecode, sourceMapToLocationData } from '@cashscript/utils';
|
|
3
|
+
import { computeBytecodeFingerprintWithConstructorArgs, generateSourceMap, generateSourceTags, 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/
|
|
7
|
+
import { ThrowingErrorListener, ForwardingErrorListener } 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';
|
|
@@ -25,9 +25,10 @@ export const DEFAULT_COMPILER_OPTIONS = {
|
|
|
25
25
|
* @throws If the source code contains a syntax, semantic, or type error.
|
|
26
26
|
*/
|
|
27
27
|
export function compileString(code, compilerOptions = {}) {
|
|
28
|
-
const
|
|
28
|
+
const { errorListener, ...artifactCompilerOptions } = compilerOptions;
|
|
29
|
+
const mergedCompilerOptions = { ...DEFAULT_COMPILER_OPTIONS, ...artifactCompilerOptions };
|
|
29
30
|
// Lexing + parsing
|
|
30
|
-
let ast = parseCode(code);
|
|
31
|
+
let ast = parseCode(code, errorListener);
|
|
31
32
|
// Semantic analysis
|
|
32
33
|
ast = ast.accept(new SymbolTableTraversal());
|
|
33
34
|
ast = ast.accept(new TypeCheckTraversal());
|
|
@@ -71,18 +72,20 @@ export function compileFile(codeFile, compilerOptions = {}) {
|
|
|
71
72
|
const code = fs.readFileSync(codeFile, { encoding: 'utf-8' });
|
|
72
73
|
return compileString(code, compilerOptions);
|
|
73
74
|
}
|
|
74
|
-
export function parseCode(code) {
|
|
75
|
+
export function parseCode(code, errorListener = ThrowingErrorListener.INSTANCE) {
|
|
76
|
+
const syntaxErrorListener = new ForwardingErrorListener(errorListener);
|
|
75
77
|
// Lexing (throwing on errors)
|
|
76
78
|
const inputStream = new CharStream(code);
|
|
77
79
|
const lexer = new CashScriptLexer(inputStream);
|
|
78
80
|
lexer.removeErrorListeners();
|
|
79
|
-
lexer.addErrorListener(
|
|
81
|
+
lexer.addErrorListener(syntaxErrorListener);
|
|
80
82
|
const tokenStream = new CommonTokenStream(lexer);
|
|
81
83
|
// Parsing (throwing on errors)
|
|
82
84
|
const parser = new CashScriptParser(tokenStream);
|
|
83
85
|
parser.removeErrorListeners();
|
|
84
|
-
parser.addErrorListener(
|
|
86
|
+
parser.addErrorListener(syntaxErrorListener);
|
|
85
87
|
const parseTree = parser.sourceFile();
|
|
88
|
+
syntaxErrorListener.throwFirstError();
|
|
86
89
|
// AST building
|
|
87
90
|
const ast = new AstBuilder(parseTree).build();
|
|
88
91
|
return ast;
|
|
@@ -42,7 +42,9 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
42
42
|
visitDoWhile(node: DoWhileNode): Node;
|
|
43
43
|
visitWhile(node: WhileNode): Node;
|
|
44
44
|
visitFor(node: ForNode): Node;
|
|
45
|
+
private emitLoopCondition;
|
|
45
46
|
removeScopedVariables(depthBeforeScope: number, node: Node): void;
|
|
47
|
+
private tagScopeCleanup;
|
|
46
48
|
visitCast(node: CastNode): Node;
|
|
47
49
|
visitFunctionCall(node: FunctionCallNode): Node;
|
|
48
50
|
visitMultiSig(node: FunctionCallNode): Node;
|
|
@@ -151,11 +151,13 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
151
151
|
}
|
|
152
152
|
cleanStack(functionBodyNode) {
|
|
153
153
|
// Keep final verification value, OP_NIP the other stack values
|
|
154
|
+
const tagStartIndex = this.output.length;
|
|
154
155
|
const stackSize = this.stack.length;
|
|
155
156
|
for (let i = 0; i < stackSize - 1; i += 1) {
|
|
156
157
|
this.emit(Op.OP_NIP, { location: functionBodyNode.location, positionHint: PositionHint.END });
|
|
157
158
|
this.nipFromStack();
|
|
158
159
|
}
|
|
160
|
+
this.tagScopeCleanup(tagStartIndex);
|
|
159
161
|
}
|
|
160
162
|
enforceFunctionParameterTypes(node) {
|
|
161
163
|
node.parameters.forEach((parameter) => this.enforceFunctionParameterType(parameter));
|
|
@@ -349,12 +351,7 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
349
351
|
const bodyStackDepth = this.stack.length;
|
|
350
352
|
node.block = this.visit(node.block);
|
|
351
353
|
this.removeScopedVariables(bodyStackDepth, node.block);
|
|
352
|
-
this.
|
|
353
|
-
this.emit(Op.OP_FROMALTSTACK, { location: node.block.location, positionHint: PositionHint.END });
|
|
354
|
-
this.pushToStack('(value)');
|
|
355
|
-
this.emit(Op.OP_NOT, { location: node.location, positionHint: PositionHint.END });
|
|
356
|
-
this.emit(Op.OP_UNTIL, { location: node.location, positionHint: PositionHint.END });
|
|
357
|
-
this.popFromStack();
|
|
354
|
+
this.emitLoopCondition(node);
|
|
358
355
|
this.scopeDepth -= 1;
|
|
359
356
|
return node;
|
|
360
357
|
}
|
|
@@ -377,22 +374,46 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
|
|
|
377
374
|
const updateEndIndex = this.output.length - 1;
|
|
378
375
|
this.sourceTags.push({ startIndex: updateStartIndex, endIndex: updateEndIndex, kind: SourceTagKind.FOR_UPDATE });
|
|
379
376
|
this.removeScopedVariables(bodyStackDepth, node.block);
|
|
377
|
+
this.emitLoopCondition(node);
|
|
378
|
+
this.scopeDepth -= 1;
|
|
379
|
+
this.removeScopedVariables(forScopeStackDepth, node);
|
|
380
|
+
return node;
|
|
381
|
+
}
|
|
382
|
+
// Emits the loop-back epilogue shared by while- and for-loops: OP_ENDIF closes the body branch,
|
|
383
|
+
// then OP_FROMALTSTACK OP_NOT OP_UNTIL re-checks the saved condition and jumps back. These are
|
|
384
|
+
// compiler-injected and map to the closing brace; tag them so the debug reconstruction renders a
|
|
385
|
+
// ">>> loop condition check" annotation line (and the following loop-variable cleanup) before the brace.
|
|
386
|
+
emitLoopCondition(node) {
|
|
387
|
+
const tagStartIndex = this.output.length;
|
|
380
388
|
this.emit(Op.OP_ENDIF, { location: node.block.location, positionHint: PositionHint.END });
|
|
381
389
|
this.emit(Op.OP_FROMALTSTACK, { location: node.block.location, positionHint: PositionHint.END });
|
|
382
390
|
this.pushToStack('(value)');
|
|
383
391
|
this.emit(Op.OP_NOT, { location: node.location, positionHint: PositionHint.END });
|
|
384
392
|
this.emit(Op.OP_UNTIL, { location: node.location, positionHint: PositionHint.END });
|
|
385
393
|
this.popFromStack();
|
|
386
|
-
this.
|
|
387
|
-
|
|
388
|
-
|
|
394
|
+
this.sourceTags.push({
|
|
395
|
+
startIndex: tagStartIndex,
|
|
396
|
+
endIndex: this.output.length - 1,
|
|
397
|
+
kind: SourceTagKind.LOOP_CONDITION,
|
|
398
|
+
});
|
|
389
399
|
}
|
|
390
400
|
removeScopedVariables(depthBeforeScope, node) {
|
|
401
|
+
const tagStartIndex = this.output.length;
|
|
391
402
|
const dropCount = this.stack.length - depthBeforeScope;
|
|
392
403
|
for (let i = 0; i < dropCount; i += 1) {
|
|
393
404
|
this.emit(Op.OP_DROP, { location: node.location, positionHint: PositionHint.END });
|
|
394
405
|
this.popFromStack();
|
|
395
406
|
}
|
|
407
|
+
this.tagScopeCleanup(tagStartIndex);
|
|
408
|
+
}
|
|
409
|
+
tagScopeCleanup(tagStartIndex) {
|
|
410
|
+
if (this.output.length <= tagStartIndex)
|
|
411
|
+
return;
|
|
412
|
+
this.sourceTags.push({
|
|
413
|
+
startIndex: tagStartIndex,
|
|
414
|
+
endIndex: this.output.length - 1,
|
|
415
|
+
kind: SourceTagKind.SCOPE_CLEANUP,
|
|
416
|
+
});
|
|
396
417
|
}
|
|
397
418
|
visitCast(node) {
|
|
398
419
|
node.expression = this.visit(node.expression);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from './Errors.js';
|
|
2
2
|
export * as utils from '@cashscript/utils';
|
|
3
|
-
export { compileFile, compileString } from './compiler.js';
|
|
4
|
-
export
|
|
3
|
+
export { compileFile, compileString, type CompileOptions } from './compiler.js';
|
|
4
|
+
export * from './ast/Location.js';
|
|
5
|
+
export * from './ast/error-listeners.js';
|
|
6
|
+
export declare const version = "0.13.2";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from './Errors.js';
|
|
2
2
|
export * as utils from '@cashscript/utils';
|
|
3
3
|
export { compileFile, compileString } from './compiler.js';
|
|
4
|
-
export
|
|
4
|
+
export * from './ast/Location.js';
|
|
5
|
+
export * from './ast/error-listeners.js';
|
|
6
|
+
export const version = '0.13.2';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -94,11 +94,13 @@ export default class SymbolTableTraversal extends AstTraversal {
|
|
|
94
94
|
return node;
|
|
95
95
|
}
|
|
96
96
|
visitTupleAssignment(node) {
|
|
97
|
-
[node.left, node.right].forEach((
|
|
97
|
+
[node.left, node.right].forEach((variable) => {
|
|
98
|
+
const definition = createTupleVariableDefinition(node, variable);
|
|
99
|
+
const { name } = variable;
|
|
98
100
|
if (this.symbolTables[0].get(name)) {
|
|
99
|
-
throw new VariableRedefinitionError(
|
|
101
|
+
throw new VariableRedefinitionError(definition);
|
|
100
102
|
}
|
|
101
|
-
this.symbolTables[0].set(Symbol.variable(
|
|
103
|
+
this.symbolTables[0].set(Symbol.variable(definition));
|
|
102
104
|
});
|
|
103
105
|
node.tuple = this.visit(node.tuple);
|
|
104
106
|
return node;
|
|
@@ -141,4 +143,9 @@ export default class SymbolTableTraversal extends AstTraversal {
|
|
|
141
143
|
return node;
|
|
142
144
|
}
|
|
143
145
|
}
|
|
146
|
+
function createTupleVariableDefinition(node, variable) {
|
|
147
|
+
const definition = new VariableDefinitionNode(variable.type, [], variable.name, node.tuple);
|
|
148
|
+
definition.location = node.location;
|
|
149
|
+
return definition;
|
|
150
|
+
}
|
|
144
151
|
//# sourceMappingURL=SymbolTableTraversal.js.map
|
|
@@ -18,7 +18,9 @@ export default class TypeCheckTraversal extends AstTraversal {
|
|
|
18
18
|
}
|
|
19
19
|
const assignmentType = new TupleType(node.left.type, node.right.type);
|
|
20
20
|
if (!implicitlyCastable(node.tuple.type, assignmentType)) {
|
|
21
|
-
|
|
21
|
+
const syntheticAssignment = new VariableDefinitionNode(assignmentType, [], node.left.name, node.tuple);
|
|
22
|
+
syntheticAssignment.location = node.location;
|
|
23
|
+
throw new AssignTypeError(syntheticAssignment);
|
|
22
24
|
}
|
|
23
25
|
return node;
|
|
24
26
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cashc",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.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.13.
|
|
51
|
+
"@cashscript/utils": "^0.13.2",
|
|
52
52
|
"antlr4": "^4.13.2",
|
|
53
53
|
"commander": "^14.0.0",
|
|
54
54
|
"semver": "^7.7.2"
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"typescript": "^5.9.2",
|
|
65
65
|
"vitest": "^4.0.15"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "a4f112abb0d035ecf018ebc694e2b081f25b3409"
|
|
68
68
|
}
|
|
@@ -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
|