├── src ├── ast │ └── nodes │ │ └── _base.ts ├── cli │ ├── index.ts │ ├── ui │ │ └── completions.ts │ ├── commands │ │ └── parse.ts │ └── BaseCommand.ts ├── util │ ├── logger.ts │ ├── strings.ts │ ├── paths.ts │ ├── symbol-table.ts │ ├── diagnostics.ts │ ├── result.ts │ └── position.ts ├── index.ts ├── grammar │ ├── CWScriptLexer.tokens │ └── CWScriptParser.tokens └── parser │ ├── index.ts │ └── validation.ts ├── dist ├── ast │ └── nodes │ │ ├── _base.d.ts │ │ ├── _base.js │ │ └── _base.js.map ├── parser │ ├── validation.d.ts │ ├── index.d.ts │ ├── validation.js.map │ ├── index.js.map │ ├── index.js │ ├── visitor.d.ts │ └── validation.js ├── util │ ├── logger.d.ts │ ├── logger.js │ ├── logger.js.map │ ├── strings.d.ts │ ├── diagnostics.d.ts │ ├── paths.d.ts │ ├── paths.js.map │ ├── strings.js.map │ ├── strings.js │ ├── symbol-table.d.ts │ ├── result.d.ts │ ├── symbol-table.js.map │ ├── paths.js │ ├── symbol-table.js │ ├── diagnostics.js.map │ ├── diagnostics.js │ ├── result.js.map │ ├── result.js │ ├── position.d.ts │ ├── position.js.map │ └── position.js ├── cli │ ├── index.d.ts │ ├── ui │ │ ├── completions.d.ts │ │ ├── completions.js.map │ │ └── completions.js │ ├── index.js.map │ ├── index.js │ ├── commands │ │ ├── parse.d.ts │ │ ├── parse.js.map │ │ └── parse.js │ ├── BaseCommand.d.ts │ ├── BaseCommand.js.map │ └── BaseCommand.js ├── index.d.ts ├── grammar │ ├── CWScriptParserVisitor.js.map │ ├── CWScriptParserListener.js.map │ ├── CWScriptParserListener.js │ ├── CWScriptParserVisitor.js │ └── CWScriptLexer.d.ts ├── bundle.node.js.LICENSE.txt ├── index.js.map ├── bundle.js.LICENSE.txt ├── index.js └── interpreter.d.ts ├── .gitignore ├── bin ├── dev.cmd ├── run.cmd ├── run └── dev ├── bun.lockb ├── jest.config.js ├── .vscode ├── settings.json └── launch.json ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── misc.xml ├── .gitignore ├── prettier.xml ├── modules.xml └── inspectionProfiles │ └── Project_Default.xml ├── .swcrc ├── .github └── workflows │ ├── size.yml │ └── main.yml ├── .editorconfig ├── examples ├── test-suite │ ├── unit │ │ └── 1_errors.cws │ └── 999_kitchen_sink.cws ├── stdlib │ └── stdlib.cws ├── cw-template │ └── CWTemplate.cws ├── kitchen-sink │ └── kitchen-sink.cws ├── test-contract │ └── test-contract.cws ├── atomic-order-example │ └── AtomicOrderExample.cws └── terraswap │ └── TerraswapFactory.cws ├── cwsc-x.iml ├── util └── print-ast.ts ├── tsconfig.json ├── LICENSE.md ├── webpack.config.js ├── grammar ├── CWScriptLexer.g4 ├── .antlr │ ├── CWScriptLexer.tokens │ └── CWScriptParser.tokens ├── CWScriptLexer.tokens └── gen │ └── CWScriptLexer.tokens ├── gen └── CWScriptLexer.tokens ├── __tests__ └── interpreter │ └── TerraswapToken.test.ts ├── oclif.manifest.json ├── package.json ├── scripts └── generate-textmate.ts └── README.md /src/ast/nodes/_base.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/ast/nodes/_base.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/parser/validation.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/util/logger.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /bin/dev.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\dev" %* -------------------------------------------------------------------------------- /src/cli/index.ts: -------------------------------------------------------------------------------- 1 | export {run} from '@oclif/core' 2 | -------------------------------------------------------------------------------- /src/util/logger.ts: -------------------------------------------------------------------------------- 1 | import winston from 'winston'; 2 | -------------------------------------------------------------------------------- /bin/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\run" %* 4 | -------------------------------------------------------------------------------- /dist/cli/index.d.ts: -------------------------------------------------------------------------------- 1 | export { run } from '@oclif/core'; 2 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperweb-io/cwsc/HEAD/bun.lockb -------------------------------------------------------------------------------- /dist/ast/nodes/_base.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | //# sourceMappingURL=_base.js.map -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '^.+\\.(t|j)sx?$': '@swc/jest', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /dist/cli/ui/completions.d.ts: -------------------------------------------------------------------------------- 1 | import omelette from 'omelette'; 2 | export declare const completions: omelette.Instance; 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.ttml": "xml", 4 | "*.ttss": "css" 5 | } 6 | } -------------------------------------------------------------------------------- /dist/util/logger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=logger.js.map -------------------------------------------------------------------------------- /dist/util/logger.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/util/logger.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | export { CWSParser } from './parser'; 2 | export { CWSInterpreter } from './interpreter'; 3 | export * as AST from './ast'; 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { CWSParser } from './parser'; 2 | export { CWSInterpreter } from './interpreter'; 3 | export * as AST from './ast'; 4 | -------------------------------------------------------------------------------- /dist/ast/nodes/_base.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"_base.js","sourceRoot":"","sources":["../../../src/ast/nodes/_base.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/util/strings.d.ts: -------------------------------------------------------------------------------- 1 | export declare function snakeToPascal(s: string): string; 2 | export declare function pascalToSnake(s: string): string; 3 | -------------------------------------------------------------------------------- /dist/cli/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AAAA,oCAA+B;AAAvB,2FAAA,GAAG,OAAA"} -------------------------------------------------------------------------------- /bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const oclif = require('@oclif/core') 4 | 5 | oclif.run().then(require('@oclif/core/flush')).catch(require('@oclif/core/handle')) 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /dist/grammar/CWScriptParserVisitor.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"CWScriptParserVisitor.js","sourceRoot":"","sources":["../../src/grammar/CWScriptParserVisitor.ts"],"names":[],"mappings":";AAAA,qEAAqE"} -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/grammar/CWScriptParserListener.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"CWScriptParserListener.js","sourceRoot":"","sources":["../../src/grammar/CWScriptParserListener.ts"],"names":[],"mappings":";AAAA,qEAAqE"} -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.swcrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsc": { 3 | "parser": { 4 | "syntax": "typescript" 5 | }, 6 | "target": "es2017", 7 | }, 8 | "module": { 9 | "type": "commonjs" 10 | }, 11 | "sourceMaps": true 12 | } -------------------------------------------------------------------------------- /dist/bundle.node.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright 2016 The ANTLR Project. All rights reserved. 3 | * Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information. 4 | */ 5 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAAqC;AAA5B,mGAAA,SAAS,OAAA;AAClB,6CAA+C;AAAtC,6GAAA,cAAc,OAAA;AACvB,6CAA6B"} -------------------------------------------------------------------------------- /dist/grammar/CWScriptParserListener.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Generated from ./grammar/CWScriptParser.g4 by ANTLR 4.9.0-SNAPSHOT 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | //# sourceMappingURL=CWScriptParserListener.js.map -------------------------------------------------------------------------------- /dist/grammar/CWScriptParserVisitor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Generated from ./grammar/CWScriptParser.g4 by ANTLR 4.9.0-SNAPSHOT 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | //# sourceMappingURL=CWScriptParserVisitor.js.map -------------------------------------------------------------------------------- /dist/util/diagnostics.d.ts: -------------------------------------------------------------------------------- 1 | import { TextView } from './position'; 2 | import { Diagnostic } from 'vscode-languageserver'; 3 | export declare function errorReportWithCodeSnippet(filename: string, sourceText: TextView, diagnostic: Diagnostic): string; 4 | -------------------------------------------------------------------------------- /.idea/prettier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dist/cli/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.run = void 0; 4 | var core_1 = require("@oclif/core"); 5 | Object.defineProperty(exports, "run", { enumerable: true, get: function () { return core_1.run; } }); 6 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/util/strings.ts: -------------------------------------------------------------------------------- 1 | export function snakeToPascal(s: string): string { 2 | return s 3 | .split('_') 4 | .map((x) => x[0].toUpperCase() + x.slice(1)) 5 | .join(''); 6 | } 7 | 8 | export function pascalToSnake(s: string): string { 9 | return s.replace(/([A-Z])/g, '_$1').toLowerCase(); 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/size.yml: -------------------------------------------------------------------------------- 1 | name: size 2 | on: [pull_request] 3 | jobs: 4 | size: 5 | runs-on: ubuntu-latest 6 | env: 7 | CI_JOB_NUMBER: 1 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: andresz1/size-limit-action@v1 11 | with: 12 | github_token: ${{ secrets.GITHUB_TOKEN }} 13 | -------------------------------------------------------------------------------- /dist/util/paths.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Resolves a file path to an absolute path. 3 | * @param fromFile file from which to calculate 4 | * @param importedPath relative path imported from `fromFile` 5 | * @returns absolute path to the imported file 6 | */ 7 | export declare function resolveFileImport(fromFile: string, importedPath: string): string; 8 | -------------------------------------------------------------------------------- /dist/util/paths.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA6B;AAE7B;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,QAAgB,EAAE,YAAoB;IACtE,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACzD,OAAO,YAAY,CAAC;AACtB,CAAC;AAJD,8CAIC"} -------------------------------------------------------------------------------- /dist/bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright 2016 The ANTLR Project. All rights reserved. 3 | * Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information. 4 | */ 5 | 6 | /*! 7 | * The buffer module from node.js, for the browser. 8 | * 9 | * @author Feross Aboukhadijeh 10 | * @license MIT 11 | */ 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = false 9 | max_line_length = 120 10 | tab_width = 4 11 | 12 | [{*.ats,*.cts,*.mts,*.ts}] 13 | tab_width = 2 14 | 15 | [{*.cjs,*.js}] 16 | tab_width = 2 17 | 18 | [{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /examples/test-suite/unit/1_errors.cws: -------------------------------------------------------------------------------- 1 | contract TestContractErrors extends BaseContract implements Base_Contract, Hello { 2 | 3 | error SingleErrorUnit 4 | error SingleErrorTuple(String, Uint128) 5 | error SingleErrorStruct(item: Uint128, user: Addr) 6 | 7 | error { 8 | GroupedErrorUnit 9 | GroupedErrorTuple(String, Uint128) 10 | GroupedErrorStruct(item: Uint128, user: Addr) 11 | } 12 | } -------------------------------------------------------------------------------- /dist/util/strings.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"strings.js","sourceRoot":"","sources":["../../src/util/strings.ts"],"names":[],"mappings":";;;AAAA,SAAgB,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC;SACL,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AALD,sCAKC;AAED,SAAgB,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AACpD,CAAC;AAFD,sCAEC"} -------------------------------------------------------------------------------- /cwsc-x.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /util/print-ast.ts: -------------------------------------------------------------------------------- 1 | function prettyPrint(node: any, depth = 0, field?: string) { 2 | let { $type, $children, ...keys } = node; 3 | let indent = ' '.repeat(depth); 4 | let res = `${indent}${$type}${field !== undefined ? ` (.${field})` : ''}`; 5 | for (let key in keys) { 6 | res += ' ' + key + ': ' + keys[key]; 7 | } 8 | console.log(res); 9 | for (let child of $children) { 10 | let { key, value } = child; 11 | prettyPrint(value, depth + 1, key); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const oclif = require('@oclif/core') 4 | 5 | const path = require('path') 6 | const project = path.join(__dirname, '..', 'tsconfig.json') 7 | 8 | // In dev mode -> use ts-node and dev plugins 9 | process.env.NODE_ENV = 'development' 10 | 11 | require('ts-node').register({project}) 12 | 13 | // In dev mode, always show stack traces 14 | oclif.settings.debug = true; 15 | 16 | // Start the CLI 17 | oclif.run().then(oclif.flush).catch(oclif.Errors.handle) 18 | -------------------------------------------------------------------------------- /src/util/paths.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | /** 4 | * Resolves a file path to an absolute path. 5 | * @param fromFile file from which to calculate 6 | * @param importedPath relative path imported from `fromFile` 7 | * @returns absolute path to the imported file 8 | */ 9 | export function resolveFileImport(fromFile: string, importedPath: string) { 10 | let baseDir = path.parse(fromFile).dir; 11 | const resolvedPath = path.resolve(baseDir, importedPath); 12 | return resolvedPath; 13 | } 14 | -------------------------------------------------------------------------------- /dist/util/strings.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.pascalToSnake = exports.snakeToPascal = void 0; 4 | function snakeToPascal(s) { 5 | return s 6 | .split('_') 7 | .map((x) => x[0].toUpperCase() + x.slice(1)) 8 | .join(''); 9 | } 10 | exports.snakeToPascal = snakeToPascal; 11 | function pascalToSnake(s) { 12 | return s.replace(/([A-Z])/g, '_$1').toLowerCase(); 13 | } 14 | exports.pascalToSnake = pascalToSnake; 15 | //# sourceMappingURL=strings.js.map -------------------------------------------------------------------------------- /dist/util/symbol-table.d.ts: -------------------------------------------------------------------------------- 1 | type SymbolEnv = { 2 | [key: string]: any; 3 | }; 4 | export declare class SymbolTable { 5 | parent?: SymbolTable | undefined; 6 | symbols: SymbolEnv; 7 | constructor(symbols?: SymbolEnv, parent?: SymbolTable | undefined); 8 | getTrail(): SymbolTable[]; 9 | getSymbol(name: string): T; 10 | hasSymbol(name: string): boolean; 11 | getOwnSymbol(name: string): T; 12 | setSymbol(name: string, value: any): void; 13 | subscope(x?: T): T; 14 | } 15 | export {}; 16 | -------------------------------------------------------------------------------- /examples/stdlib/stdlib.cws: -------------------------------------------------------------------------------- 1 | impl for T[] { 2 | fn map(self, f: (item: T) -> U) -> U[] { 3 | let result: U[] = []; 4 | for item in self { 5 | result.push(f(item)); 6 | } 7 | result 8 | } 9 | 10 | fn map!(self, f: !(item: T) -> U) -> U[] { 11 | let result: U[] = []; 12 | for item in self { 13 | result.push(f!(item)); 14 | } 15 | result 16 | } 17 | 18 | fn push(self, item: T) { 19 | self[self.len()] = item; 20 | } 21 | 22 | fn pop() -> T { 23 | let len = self.len(); 24 | let item = self[len - 1]; 25 | self[len]; 26 | item 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/cw-template/CWTemplate.cws: -------------------------------------------------------------------------------- 1 | contract CWTemplate { 2 | 3 | state { 4 | count: U64 5 | owner: Address 6 | } 7 | 8 | #instantiate(count: U64) { 9 | state.count = count 10 | state.owner = msg.sender 11 | } 12 | 13 | exec #increment() { 14 | $state.count -= 1 15 | } 16 | 17 | exec #reset(count: U64) { 18 | $state.count = count 19 | } 20 | 21 | query #get_count() -> struct { count: U64 } { 22 | return { 23 | count: $state.count 24 | } 25 | } 26 | 27 | query #get_owner() -> struct { owner: Address } { 28 | return { 29 | owner: $state.owner 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/cli/ui/completions.ts: -------------------------------------------------------------------------------- 1 | import omelette from 'omelette'; 2 | import fs from 'fs'; 3 | 4 | export const completions = omelette(`githubber|gh `); 5 | 6 | // Bind events for every template part. 7 | completions.on('action', ({ reply }) => { 8 | reply(['clone', 'update', 'push']); 9 | }); 10 | 11 | completions.on('user', ({ reply }) => { 12 | reply(fs.readdirSync('/Users/')); 13 | }); 14 | 15 | completions.on('repo', ({ before, reply }) => { 16 | reply([ 17 | `http://github.com/${before}/helloworld`, 18 | `http://github.com/${before}/blabla`, 19 | ]); 20 | }); 21 | 22 | // Initialize the omelette. 23 | completions.init(); 24 | -------------------------------------------------------------------------------- /dist/cli/ui/completions.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"completions.js","sourceRoot":"","sources":["../../../src/cli/ui/completions.ts"],"names":[],"mappings":";;;;;;AAAA,wDAAgC;AAChC,4CAAoB;AAEP,QAAA,WAAW,GAAG,IAAA,kBAAQ,EAAC,qCAAqC,CAAC,CAAC;AAE3E,uCAAuC;AACvC,mBAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACrC,KAAK,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,mBAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACnC,KAAK,CAAC,YAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,mBAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;IAC3C,KAAK,CAAC;QACJ,qBAAqB,MAAM,aAAa;QACxC,qBAAqB,MAAM,SAAS;KACrC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,2BAA2B;AAC3B,mBAAW,CAAC,IAAI,EAAE,CAAC"} -------------------------------------------------------------------------------- /dist/cli/commands/parse.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseCommand } from '../BaseCommand'; 2 | export default class ParseCommand extends BaseCommand { 3 | static description: string; 4 | static examples: string[]; 5 | static flags: { 6 | format: import("@oclif/core/lib/interfaces").OptionFlag; 7 | out: import("@oclif/core/lib/interfaces").OptionFlag; 8 | }; 9 | static args: { 10 | file: import("@oclif/core/lib/interfaces/parser").Arg; 13 | }; 14 | run(): Promise; 15 | } 16 | -------------------------------------------------------------------------------- /examples/kitchen-sink/kitchen-sink.cws: -------------------------------------------------------------------------------- 1 | interface HasSomething { 2 | 3 | state { 4 | something: struct Something { 5 | the_thing: U123 6 | } 7 | } 8 | } 9 | 10 | interface HasOwner { 11 | state { 12 | owner: String 13 | } 14 | 15 | query #get_owner() -> struct { 16 | owner: String 17 | } 18 | } 19 | 20 | 21 | contract EmptyContract {} 22 | 23 | contract ImplHasSomething implements HasSomething { 24 | query #get_something() { 25 | return { 26 | something: state.something 27 | } 28 | } 29 | } 30 | 31 | contract ImplHasOwner implements HasOwner { 32 | query #get_owner() { 33 | return { 34 | owner: state.owner 35 | } 36 | } 37 | } 38 | 39 | contract ImplHasSomethingAndOwner extends ImplHasSomething { 40 | } 41 | -------------------------------------------------------------------------------- /examples/test-suite/999_kitchen_sink.cws: -------------------------------------------------------------------------------- 1 | import "standard" 2 | import item, ute from "utica.cws" 3 | 4 | interface IContract { 5 | 6 | } 7 | 8 | interface IHasErrors { 9 | 10 | } 11 | 12 | contract KitchenSink extends ExampleContract 13 | implements IContract, IHasErrors 14 | { 15 | 16 | error SingleUnit 17 | error SingleTuple(String, Uint128) 18 | error SingleStruct(name: String, balance: Uint128) 19 | error SingleStructCurly{ 20 | name: String, 21 | balance: Uint128, 22 | } 23 | 24 | event SingleUnit 25 | event SingleTuple(String, String, Uint128) 26 | event SingleStruct(name: String, balance: Uint128) 27 | event SingleStructCurly { 28 | name: String, 29 | balance: Uint128, 30 | } 31 | 32 | instantiate(msg: Uint128, name: String) { 33 | } 34 | } -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | build: 5 | name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} 6 | 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | node: ['10.x', '12.x', '14.x'] 11 | os: [ubuntu-latest, windows-latest, macOS-latest] 12 | 13 | steps: 14 | - name: Checkout repo 15 | uses: actions/checkout@v2 16 | 17 | - name: Use Node ${{ matrix.node }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node }} 21 | 22 | - name: Install deps and build (with cache) 23 | uses: bahmutov/npm-install@v1 24 | 25 | - name: Lint 26 | run: yarn lint 27 | 28 | - name: Test 29 | run: yarn test --ci --coverage --maxWorkers=2 30 | 31 | - name: Build 32 | run: yarn build 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src", 4 | "types" 5 | ], 6 | "exclude": [ 7 | "/node_modules/", 8 | "./src/**/*.test.ts" 9 | ], 10 | "compilerOptions": { 11 | "allowSyntheticDefaultImports": true, 12 | "alwaysStrict": true, 13 | "baseUrl": "./", 14 | "declaration": true, 15 | "esModuleInterop": true, 16 | "lib": [ 17 | "es2016", 18 | "es2017", 19 | "dom" 20 | ], 21 | "module": "commonjs", 22 | "moduleResolution": "node", 23 | "noFallthroughCasesInSwitch": true, 24 | "noImplicitAny": true, 25 | "noImplicitReturns": true, 26 | "noImplicitThis": true, 27 | "noUnusedLocals": false, 28 | "noUnusedParameters": false, 29 | "downlevelIteration": true, 30 | "outDir": "dist", 31 | "rootDir": "src", 32 | "sourceMap": true, 33 | "strict": true, 34 | "strictFunctionTypes": true, 35 | "strictNullChecks": true, 36 | "strictPropertyInitialization": true, 37 | "target": "es2017" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /dist/cli/ui/completions.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.completions = void 0; 7 | const omelette_1 = __importDefault(require("omelette")); 8 | const fs_1 = __importDefault(require("fs")); 9 | exports.completions = (0, omelette_1.default)(`githubber|gh `); 10 | // Bind events for every template part. 11 | exports.completions.on('action', ({ reply }) => { 12 | reply(['clone', 'update', 'push']); 13 | }); 14 | exports.completions.on('user', ({ reply }) => { 15 | reply(fs_1.default.readdirSync('/Users/')); 16 | }); 17 | exports.completions.on('repo', ({ before, reply }) => { 18 | reply([ 19 | `http://github.com/${before}/helloworld`, 20 | `http://github.com/${before}/blabla`, 21 | ]); 22 | }); 23 | // Initialize the omelette. 24 | exports.completions.init(); 25 | //# sourceMappingURL=completions.js.map -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Web, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/test-contract/test-contract.cws: -------------------------------------------------------------------------------- 1 | contract MyTestContract { 2 | 3 | event Instantiate(owner: Addr, count: u32) 4 | event Call(method: String) 5 | 6 | error Unauthorized{} 7 | 8 | state { 9 | count: u32 10 | owner: Addr 11 | } 12 | 13 | instantiate(count: u32) { 14 | state.count = count 15 | state.owner = msg.sender 16 | 17 | emit Instantiate(msg.sender, count) 18 | } 19 | 20 | exec increment() { 21 | if count == None { 22 | state.count += 1 23 | } else { 24 | state.count += count 25 | } 26 | 27 | emit Call("increment") 28 | } 29 | 30 | exec reset(count: u32) { 31 | if msg.sender != state.owner { 32 | fail Unauthorized{} 33 | } 34 | 35 | state.count = count 36 | emit Call("reset") 37 | } 38 | 39 | query get_count() -> struct _ { count: u32 } { 40 | return _ { 41 | count: state.count 42 | } 43 | } 44 | 45 | query get_owner() -> struct _ { owner: Addr } { 46 | return _ { 47 | owner: state.owner 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /dist/cli/commands/parse.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/cli/commands/parse.ts"],"names":[],"mappings":";;;;;AAAA,sCAAmD;AACnD,gDAA4D;AAC5D,yCAAyC;AACzC,4CAAoB;AAMpB,MAAqB,YAAa,SAAQ,yBAAgC;IA+BjE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;SAC1C;QAED,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,IAAI,SAAS,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;QAC3D,IAAI,WAAW,GAAG,YAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrD,IAAI,GAAG,GAAG,IAAI,kBAAS,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACxD,IAAI,KAAK,CAAC,GAAG,EAAE;YACb,YAAE,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;SAC3D;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;SAC3B;IACH,CAAC;;AA7CH,+BA8CC;AA7CQ,wBAAW,GAAG,wCAAwC,CAAC;AAEvD,qBAAQ,GAAG;IAChB,0CAA0C;IAC1C,wDAAwD;CACzD,CAAC;AAEK,kBAAK,GAAG;IACb,MAAM,EAAE,YAAK,CAAC,MAAM,CAAC;QACnB,WAAW,EAAE,yCAAyC;QACtD,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;QACzB,OAAO,EAAE,MAAM;KAChB,CAAC;IACF,GAAG,EAAE,YAAK,CAAC,MAAM,CAAC;QAChB,IAAI,EAAE,GAAG;QACT,WAAW,EAAE,wCAAwC;QACrD,QAAQ,EAAE,KAAK;KAChB,CAAC;CACH,CAAC;AAEK,iBAAI,GAAG;IACZ,IAAI,EAAE,WAAI,CAAC,IAAI,CAAC;QACd,WAAW,EAAE,yBAAyB;QACtC,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,IAAI;QACjB,MAAM,EAAE,IAAI;KACb,CAAC;CACH,CAAC"} -------------------------------------------------------------------------------- /dist/util/result.d.ts: -------------------------------------------------------------------------------- 1 | import { Diagnostic } from 'vscode-languageserver'; 2 | import { Result, Ok, Err } from 'ts-results'; 3 | export type DgnsOk = DgnsResult>; 4 | export type DgnsErr = DgnsResult>; 5 | export declare class CWSValidationError extends Error { 6 | diagnostics: Diagnostic[]; 7 | constructor(diagnostics: Diagnostic[]); 8 | } 9 | export declare class DgnsResult = Result> { 10 | res: R; 11 | diagnostics: Diagnostic[]; 12 | constructor(res: R, diagnostics: Diagnostic[]); 13 | static Ok(res: T, diagnostics: Diagnostic[]): DgnsOk; 14 | static Err(err: E, diagnostics: Diagnostic[]): DgnsErr; 15 | isOk(): this is DgnsOk; 16 | isErr(): this is DgnsErr; 17 | map(f: (t: T, d: Diagnostic[]) => U): DgnsResult; 18 | mapErr(f: (e: E, d: Diagnostic[]) => U): DgnsResult; 19 | flatMap: (f: (r: T, d: Diagnostic[]) => DgnsResult>) => DgnsResult>; 20 | andThen(f: (r: T, d: Diagnostic[]) => DgnsResult): DgnsResult; 21 | unwrap(): T; 22 | static all(results: DgnsResult[]): DgnsResult; 23 | static allOk(results: DgnsOk[]): DgnsOk; 24 | static allErr(results: DgnsErr[]): DgnsErr; 25 | catchErr(errC: new (...args: any[]) => F, f: (e: F, d: Diagnostic[]) => DgnsResult): DgnsResult; 26 | } 27 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug CWScript Grammar", 9 | "type": "antlr-debug", 10 | "request": "launch", 11 | "input": "examples/cws-cw20/src/cw20-base.cws", 12 | "grammar": "grammar/CWScriptParser.g4", 13 | "startRule": "sourceFile", 14 | "printParseTree": true, 15 | "visualParseTree": true 16 | }, 17 | // { 18 | // "name": "Debug CWSpec Grammar", 19 | // "type": "antlr-debug", 20 | // "request": "launch", 21 | // "input": "examples/cws-cw20/src/cw20-base.cwspec", 22 | // "grammar": "grammar/CWSpecParser.g4", 23 | // "startRule": "cwspec", 24 | // "printParseTree": true, 25 | // "visualParseTree": true 26 | // } 27 | { 28 | "name": "Debug CWScript Compiler", 29 | "type": "node", 30 | "request": "launch", 31 | "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], 32 | "args": ["src/cli.ts", "examples/cws-cw20/src/cw20-base.cws"], 33 | "cwd": "${workspaceFolder}", 34 | "internalConsoleOptions": "openOnSessionStart", 35 | "skipFiles": ["/**", "node_modules/**"], 36 | "env": { 37 | "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json" 38 | } 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /dist/cli/BaseCommand.d.ts: -------------------------------------------------------------------------------- 1 | import { Command, Interfaces } from '@oclif/core'; 2 | export type FlagsT = Interfaces.InferredFlags; 3 | export type ArgsT = Interfaces.InferredArgs; 4 | export declare class ConfigKV { 5 | key: string; 6 | value: string; 7 | constructor(key: string, value: string); 8 | } 9 | export declare abstract class BaseCommand extends Command { 10 | loadConfig(): Promise; 11 | protected flags: FlagsT; 12 | protected args: ArgsT; 13 | init(): Promise; 14 | static baseFlags: { 15 | verbose: Interfaces.BooleanFlag; 16 | silent: Interfaces.BooleanFlag; 17 | 'show-hints': Interfaces.BooleanFlag; 18 | 'show-warnings': Interfaces.BooleanFlag; 19 | logs: Interfaces.OptionFlag; 20 | 'log-file': Interfaces.OptionFlag; 21 | 'project-dir': Interfaces.OptionFlag; 22 | cwsconfig: Interfaces.OptionFlag; 23 | }; 24 | protected catch(err: Error & { 25 | exitCode?: number; 26 | }): Promise; 27 | protected finally(_: Error | undefined): Promise; 28 | abstract run(): Promise; 29 | } 30 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | Object.defineProperty(exports, "__esModule", { value: true }); 26 | exports.AST = exports.CWSInterpreter = exports.CWSParser = void 0; 27 | var parser_1 = require("./parser"); 28 | Object.defineProperty(exports, "CWSParser", { enumerable: true, get: function () { return parser_1.CWSParser; } }); 29 | var interpreter_1 = require("./interpreter"); 30 | Object.defineProperty(exports, "CWSInterpreter", { enumerable: true, get: function () { return interpreter_1.CWSInterpreter; } }); 31 | exports.AST = __importStar(require("./ast")); 32 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/util/symbol-table.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"symbol-table.js","sourceRoot":"","sources":["../../src/util/symbol-table.ts"],"names":[],"mappings":";;;AAIA,MAAa,WAAW;IAGtB,YAAY,OAAmB,EAAS,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;QAC1D,IAAI,CAAC,OAAO,GAAG,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC;IAC/B,CAAC;IAED,QAAQ;QACN,IAAI,GAAG,GAAkB,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,OAAO,GAAG,EAAE;YACV,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACd,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;SAClB;QACD,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IAED,SAAS,CAAU,IAAY;QAC7B,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;YACxB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;SAC3B;QAED,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;YAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;SAClC;QAED,IAAI,IAAI,CAAC,MAAM,EAAE;YACf,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;SACpC;QAED,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,YAAY,CAAC,CAAC;IAC9C,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,IAAI,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC;QAC9D,IAAI,GAAG,EAAE;YACP,OAAO,IAAI,CAAC;SACb;aAAM;YACL,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;SAC1D;IACH,CAAC;IAED,YAAY,CAAU,IAAY;QAChC,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;YACxB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;SAC3B;QAED,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;YAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;SAClC;QAED,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,YAAY,CAAC,CAAC;IAC9C,CAAC;IAED,SAAS,CAAC,IAAY,EAAE,KAAU;QAChC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAsC,CAAK;QACjD,IAAI,CAAC,KAAK,SAAS,EAAE;YACnB,IAAI,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;YAC5B,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC;YAClB,OAAO,GAAQ,CAAC;SACjB;aAAM;YACL,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,CAAC;SACV;IACH,CAAC;CACF;AApED,kCAoEC"} -------------------------------------------------------------------------------- /dist/util/paths.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | Object.defineProperty(exports, "__esModule", { value: true }); 26 | exports.resolveFileImport = void 0; 27 | const path = __importStar(require("path")); 28 | /** 29 | * Resolves a file path to an absolute path. 30 | * @param fromFile file from which to calculate 31 | * @param importedPath relative path imported from `fromFile` 32 | * @returns absolute path to the imported file 33 | */ 34 | function resolveFileImport(fromFile, importedPath) { 35 | let baseDir = path.parse(fromFile).dir; 36 | const resolvedPath = path.resolve(baseDir, importedPath); 37 | return resolvedPath; 38 | } 39 | exports.resolveFileImport = resolveFileImport; 40 | //# sourceMappingURL=paths.js.map -------------------------------------------------------------------------------- /src/util/symbol-table.ts: -------------------------------------------------------------------------------- 1 | type SymbolEnv = { 2 | [key: string]: any; 3 | }; 4 | 5 | export class SymbolTable { 6 | public symbols: SymbolEnv; 7 | 8 | constructor(symbols?: SymbolEnv, public parent?: SymbolTable) { 9 | this.symbols = symbols ?? {}; 10 | } 11 | 12 | getTrail(): SymbolTable[] { 13 | let res: SymbolTable[] = [this]; 14 | let cur = this.parent; 15 | while (cur) { 16 | res.push(cur); 17 | cur = cur.parent; 18 | } 19 | return res.reverse(); 20 | } 21 | 22 | getSymbol(name: string): T { 23 | if (name in this.symbols) { 24 | return this.symbols[name]; 25 | } 26 | 27 | if (name + '#!' in this.symbols) { 28 | return this.symbols[name + '#!']; 29 | } 30 | 31 | if (this.parent) { 32 | return this.parent.getSymbol(name); 33 | } 34 | 35 | throw new Error(`symbol ${name} not found`); 36 | } 37 | 38 | hasSymbol(name: string): boolean { 39 | let res = name in this.symbols || name + '#!' in this.symbols; 40 | if (res) { 41 | return true; 42 | } else { 43 | return this.parent ? this.parent.hasSymbol(name) : false; 44 | } 45 | } 46 | 47 | getOwnSymbol(name: string): T { 48 | if (name in this.symbols) { 49 | return this.symbols[name]; 50 | } 51 | 52 | if (name + '#!' in this.symbols) { 53 | return this.symbols[name + '#!']; 54 | } 55 | 56 | throw new Error(`symbol ${name} not found`); 57 | } 58 | 59 | setSymbol(name: string, value: any) { 60 | this.symbols[name] = value; 61 | } 62 | 63 | subscope(x?: T): T { 64 | if (x === undefined) { 65 | let res = new SymbolTable(); 66 | res.parent = this; 67 | return res as T; 68 | } else { 69 | x.parent = this; 70 | return x; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/cli/commands/parse.ts: -------------------------------------------------------------------------------- 1 | import { Command, Args, Flags } from '@oclif/core'; 2 | import { BaseCommand, FlagsT, ArgsT } from '../BaseCommand'; 3 | import { CWSParser } from '../../parser'; 4 | import fs from 'fs'; 5 | import path from 'path'; 6 | import { DiagnosticSeverity } from 'vscode-languageserver'; 7 | import { TextView } from '../../util/position'; 8 | import { errorReportWithCodeSnippet } from '../../util/diagnostics'; 9 | 10 | export default class ParseCommand extends BaseCommand { 11 | static description = 'Parse a CWScript source file into AST.'; 12 | 13 | static examples = [ 14 | `<%= config.bin %> <%= command.id %> FILE`, 15 | `<%= config.bin %> <%= command.id %> FILE --format sexp`, 16 | ]; 17 | 18 | static flags = { 19 | format: Flags.string({ 20 | description: 'Desired format of the parsed AST output', 21 | required: true, 22 | options: ['json', 'sexp'], 23 | default: 'json', 24 | }), 25 | out: Flags.string({ 26 | char: 'o', 27 | description: 'Output file to write the parsed AST to', 28 | required: false, 29 | }), 30 | }; 31 | 32 | static args = { 33 | file: Args.file({ 34 | description: 'File to parse into AST.', 35 | required: true, 36 | ignoreStdin: true, 37 | exists: true, 38 | }), 39 | }; 40 | 41 | public async run() { 42 | const { args, flags } = await this.parse(ParseCommand); 43 | if (!args.file) { 44 | this.error('No file provided to parse.'); 45 | } 46 | 47 | this.debug(`Parsing ${args.file} into ${flags.format}...`); 48 | let sourceInput = fs.readFileSync(args.file, 'utf8'); 49 | let ast = new CWSParser(sourceInput, args.file).parse(); 50 | if (flags.out) { 51 | fs.writeFileSync(flags.out, JSON.stringify(ast.toJSON())); 52 | } else { 53 | console.log(ast.toJSON()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /dist/parser/index.d.ts: -------------------------------------------------------------------------------- 1 | import { ANTLRErrorListener } from 'antlr4ts'; 2 | import { SourceFileContext } from '../grammar/CWScriptParser'; 3 | import * as AST from '../ast'; 4 | import { Diagnostic } from 'vscode-languageserver'; 5 | import * as P from '../grammar/CWScriptParser'; 6 | import { CWScriptParserListener } from '../grammar/CWScriptParserListener'; 7 | import { RecognitionException } from 'antlr4ts/RecognitionException'; 8 | export declare abstract class CWSDiagnosticsCollector { 9 | diagnostics: Diagnostic[]; 10 | get errors(): Diagnostic[]; 11 | get warnings(): Diagnostic[]; 12 | get infos(): Diagnostic[]; 13 | get hints(): Diagnostic[]; 14 | } 15 | export declare class CWSSyntaxErrorListener implements ANTLRErrorListener { 16 | parser: CWSParser; 17 | constructor(parser: CWSParser); 18 | syntaxError(recognizer: any, offendingSymbol: any, line: number, charPositionInLine: number, msg: string, e: RecognitionException | undefined): void; 19 | } 20 | export declare class CheckSymbolsDeclaredBeforeUse implements CWScriptParserListener { 21 | parser: CWSParser; 22 | scopes: any; 23 | get scope(): any; 24 | constructor(parser: CWSParser); 25 | enterIdentExpr(ctx: P.IdentExprContext): void; 26 | enterIdentBinding_(ctx: P.IdentBinding_Context): void; 27 | enterImportItemsStmt(ctx: P.ImportItemsStmtContext): void; 28 | enterParam(ctx: P.ParamContext): void; 29 | enterInstantiateDefn(ctx: P.InstantiateDefnContext): void; 30 | enterFnDefn(ctx: P.FnDefnContext): void; 31 | enterStructDefn(ctx: P.StructDefnContext): void; 32 | enterEnumDefn(ctx: P.EnumDefnContext): void; 33 | } 34 | export declare class CWSParser extends CWSDiagnosticsCollector { 35 | sourceInput: string; 36 | constructor(sourceInput: string, sourceFile?: string | null); 37 | /** 38 | * This is the public-facing interface for parsing a source file. 39 | */ 40 | parse(): AST.SourceFile; 41 | protected antlrParse(): SourceFileContext; 42 | } 43 | -------------------------------------------------------------------------------- /dist/util/symbol-table.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.SymbolTable = void 0; 4 | class SymbolTable { 5 | constructor(symbols, parent) { 6 | this.parent = parent; 7 | this.symbols = symbols !== null && symbols !== void 0 ? symbols : {}; 8 | } 9 | getTrail() { 10 | let res = [this]; 11 | let cur = this.parent; 12 | while (cur) { 13 | res.push(cur); 14 | cur = cur.parent; 15 | } 16 | return res.reverse(); 17 | } 18 | getSymbol(name) { 19 | if (name in this.symbols) { 20 | return this.symbols[name]; 21 | } 22 | if (name + '#!' in this.symbols) { 23 | return this.symbols[name + '#!']; 24 | } 25 | if (this.parent) { 26 | return this.parent.getSymbol(name); 27 | } 28 | throw new Error(`symbol ${name} not found`); 29 | } 30 | hasSymbol(name) { 31 | let res = name in this.symbols || name + '#!' in this.symbols; 32 | if (res) { 33 | return true; 34 | } 35 | else { 36 | return this.parent ? this.parent.hasSymbol(name) : false; 37 | } 38 | } 39 | getOwnSymbol(name) { 40 | if (name in this.symbols) { 41 | return this.symbols[name]; 42 | } 43 | if (name + '#!' in this.symbols) { 44 | return this.symbols[name + '#!']; 45 | } 46 | throw new Error(`symbol ${name} not found`); 47 | } 48 | setSymbol(name, value) { 49 | this.symbols[name] = value; 50 | } 51 | subscope(x) { 52 | if (x === undefined) { 53 | let res = new SymbolTable(); 54 | res.parent = this; 55 | return res; 56 | } 57 | else { 58 | x.parent = this; 59 | return x; 60 | } 61 | } 62 | } 63 | exports.SymbolTable = SymbolTable; 64 | //# sourceMappingURL=symbol-table.js.map -------------------------------------------------------------------------------- /dist/cli/commands/parse.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const core_1 = require("@oclif/core"); 7 | const BaseCommand_1 = require("../BaseCommand"); 8 | const parser_1 = require("../../parser"); 9 | const fs_1 = __importDefault(require("fs")); 10 | class ParseCommand extends BaseCommand_1.BaseCommand { 11 | async run() { 12 | const { args, flags } = await this.parse(ParseCommand); 13 | if (!args.file) { 14 | this.error('No file provided to parse.'); 15 | } 16 | this.debug(`Parsing ${args.file} into ${flags.format}...`); 17 | let sourceInput = fs_1.default.readFileSync(args.file, 'utf8'); 18 | let ast = new parser_1.CWSParser(sourceInput, args.file).parse(); 19 | if (flags.out) { 20 | fs_1.default.writeFileSync(flags.out, JSON.stringify(ast.toJSON())); 21 | } 22 | else { 23 | console.log(ast.toJSON()); 24 | } 25 | } 26 | } 27 | exports.default = ParseCommand; 28 | ParseCommand.description = 'Parse a CWScript source file into AST.'; 29 | ParseCommand.examples = [ 30 | `<%= config.bin %> <%= command.id %> FILE`, 31 | `<%= config.bin %> <%= command.id %> FILE --format sexp`, 32 | ]; 33 | ParseCommand.flags = { 34 | format: core_1.Flags.string({ 35 | description: 'Desired format of the parsed AST output', 36 | required: true, 37 | options: ['json', 'sexp'], 38 | default: 'json', 39 | }), 40 | out: core_1.Flags.string({ 41 | char: 'o', 42 | description: 'Output file to write the parsed AST to', 43 | required: false, 44 | }), 45 | }; 46 | ParseCommand.args = { 47 | file: core_1.Args.file({ 48 | description: 'File to parse into AST.', 49 | required: true, 50 | ignoreStdin: true, 51 | exists: true, 52 | }), 53 | }; 54 | //# sourceMappingURL=parse.js.map -------------------------------------------------------------------------------- /src/util/diagnostics.ts: -------------------------------------------------------------------------------- 1 | import { TextView } from './position'; 2 | import { Diagnostic } from 'vscode-languageserver'; 3 | 4 | import chalk from 'chalk'; 5 | 6 | export function errorReportWithCodeSnippet( 7 | filename: string, 8 | sourceText: TextView, 9 | diagnostic: Diagnostic 10 | ) { 11 | let res = ''; 12 | let { range, message } = diagnostic; 13 | let filenameWithRange = `${filename}:${range.start.line + 1}:${ 14 | range.start.character + 1 15 | }-${range.end.line + 1}:${range.end.character + 1}`; 16 | res += `[ERROR] ${filenameWithRange}\n`; 17 | res += `${message}\n\n...\n`; 18 | 19 | let lineNoWidth = 5; 20 | let gutterWidth = lineNoWidth + 2; 21 | let makeLine = (line: number, text: string) => { 22 | return chalk.dim( 23 | `${line.toString().padStart(lineNoWidth, ' ')}| ${text}\n` 24 | ); 25 | }; 26 | let makeErrorLine = (line: number, text: string) => { 27 | return `${chalk.redBright( 28 | chalk.bold(line.toString().padStart(lineNoWidth, ' ')) + '|' 29 | )} ${text}\n`; 30 | }; 31 | 32 | sourceText.surroundingLinesOfRange(range, 5).forEach((x) => { 33 | // if this is the starting line, make a pointer 34 | // if range.start.line <= x.line <= range.end.line, highlight the line 35 | if (x.line >= range.start.line && x.line <= range.end.line) { 36 | // only highlight the part of the line that is in the range 37 | let start = x.line === range.start.line ? range.start.character : 0; 38 | let end = x.line === range.end.line ? range.end.character : x.text.length; 39 | res += makeErrorLine( 40 | x.line, 41 | chalk.dim(x.text.slice(0, start)) + 42 | chalk.bold(chalk.redBright(x.text.slice(start, end))) + 43 | chalk.dim(x.text.slice(end)) 44 | ); 45 | if (x.line === range.end.line) { 46 | res += chalk.bold( 47 | chalk.yellow( 48 | ' '.repeat(gutterWidth + range.end.character) + 49 | '^ ' + 50 | message + 51 | '\n' 52 | ) 53 | ); 54 | } 55 | } else { 56 | res += makeLine(x.line, x.text); 57 | } 58 | }); 59 | res += `...\n\n`; 60 | return res; 61 | } 62 | -------------------------------------------------------------------------------- /dist/util/diagnostics.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/util/diagnostics.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); 3 | const TerserPlugin = require('terser-webpack-plugin'); 4 | const { resolve } = require('path'); 5 | 6 | // const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 7 | 8 | const commonConfig = { 9 | mode: 'production', 10 | entry: ['./src/index.ts'], 11 | devtool: 'source-map', 12 | output: { 13 | globalObject: 'this', 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.tsx?/, 19 | use: { loader: 'ts-loader' }, 20 | exclude: /node_modules/, 21 | }, 22 | ], 23 | }, 24 | resolve: { 25 | extensions: ['.tsx', '.ts', '.js'], 26 | plugins: [new TsconfigPathsPlugin()], 27 | }, 28 | plugins: [ 29 | new webpack.IgnorePlugin({ 30 | resourceRegExp: 31 | /wordlists\/(french|spanish|italian|korean|chinese_simplified|chinese_traditional|japanese)\.json$/, 32 | }), 33 | ], 34 | }; 35 | 36 | const webConfig = { 37 | ...commonConfig, 38 | target: 'web', 39 | output: { 40 | filename: 'bundle.js', 41 | libraryTarget: 'umd', 42 | library: 'cwsc', 43 | }, 44 | resolve: { 45 | ...commonConfig.resolve, 46 | fallback: { 47 | stream: require.resolve('stream-browserify'), 48 | path: require.resolve('path-browserify'), 49 | buffer: require.resolve('buffer'), 50 | assert: require.resolve('assert'), 51 | 'process/browser': require.resolve('process'), 52 | }, 53 | }, 54 | plugins: [ 55 | ...commonConfig.plugins, 56 | new webpack.ProvidePlugin({ 57 | Buffer: ['buffer', 'Buffer'], 58 | }), 59 | new webpack.ProvidePlugin({ 60 | process: 'process/browser', 61 | }), 62 | // new BundleAnalyzerPlugin(), 63 | ], 64 | optimization: { 65 | minimize: true, 66 | minimizer: [ 67 | new TerserPlugin({ 68 | terserOptions: { 69 | keep_classnames: true, 70 | }, 71 | }), 72 | ], 73 | }, 74 | }; 75 | 76 | const nodeConfig = { 77 | ...commonConfig, 78 | target: 'node', 79 | output: { 80 | libraryTarget: 'commonjs', 81 | filename: 'bundle.node.js', 82 | }, 83 | }; 84 | 85 | module.exports = [webConfig, nodeConfig]; 86 | -------------------------------------------------------------------------------- /dist/cli/BaseCommand.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"BaseCommand.js","sourceRoot":"","sources":["../../src/cli/BaseCommand.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/util/diagnostics.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.errorReportWithCodeSnippet = void 0; 7 | const chalk_1 = __importDefault(require("chalk")); 8 | function errorReportWithCodeSnippet(filename, sourceText, diagnostic) { 9 | let res = ''; 10 | let { range, message } = diagnostic; 11 | let filenameWithRange = `${filename}:${range.start.line + 1}:${range.start.character + 1}-${range.end.line + 1}:${range.end.character + 1}`; 12 | res += `[ERROR] ${filenameWithRange}\n`; 13 | res += `${message}\n\n...\n`; 14 | let lineNoWidth = 5; 15 | let gutterWidth = lineNoWidth + 2; 16 | let makeLine = (line, text) => { 17 | return chalk_1.default.dim(`${line.toString().padStart(lineNoWidth, ' ')}| ${text}\n`); 18 | }; 19 | let makeErrorLine = (line, text) => { 20 | return `${chalk_1.default.redBright(chalk_1.default.bold(line.toString().padStart(lineNoWidth, ' ')) + '|')} ${text}\n`; 21 | }; 22 | sourceText.surroundingLinesOfRange(range, 5).forEach((x) => { 23 | // if this is the starting line, make a pointer 24 | // if range.start.line <= x.line <= range.end.line, highlight the line 25 | if (x.line >= range.start.line && x.line <= range.end.line) { 26 | // only highlight the part of the line that is in the range 27 | let start = x.line === range.start.line ? range.start.character : 0; 28 | let end = x.line === range.end.line ? range.end.character : x.text.length; 29 | res += makeErrorLine(x.line, chalk_1.default.dim(x.text.slice(0, start)) + 30 | chalk_1.default.bold(chalk_1.default.redBright(x.text.slice(start, end))) + 31 | chalk_1.default.dim(x.text.slice(end))); 32 | if (x.line === range.end.line) { 33 | res += chalk_1.default.bold(chalk_1.default.yellow(' '.repeat(gutterWidth + range.end.character) + 34 | '^ ' + 35 | message + 36 | '\n')); 37 | } 38 | } 39 | else { 40 | res += makeLine(x.line, x.text); 41 | } 42 | }); 43 | res += `...\n\n`; 44 | return res; 45 | } 46 | exports.errorReportWithCodeSnippet = errorReportWithCodeSnippet; 47 | //# sourceMappingURL=diagnostics.js.map -------------------------------------------------------------------------------- /grammar/CWScriptLexer.g4: -------------------------------------------------------------------------------- 1 | lexer grammar CWScriptLexer; 2 | 3 | // KEYWORDS 4 | DEBUG: 'debug!'; 5 | CONTRACT: 'contract'; 6 | INTERFACE: 'interface'; 7 | IMPORT: 'import'; 8 | IMPLEMENTS: 'implements'; 9 | EXTENDS: 'extends'; 10 | ERROR: 'error'; 11 | EVENT: 'event'; 12 | DEFER: 'defer'; 13 | INSTANTIATE_NOW: 'instantiate!'; 14 | EXEC_NOW: 'exec!'; 15 | QUERY_NOW: 'query!'; 16 | DELEGATE_EXEC: 'delegate_exec!'; 17 | INSTANTIATE: 'instantiate'; 18 | EXEC: 'exec'; 19 | QUERY: 'query'; 20 | REPLY: 'reply'; 21 | FOR: 'for'; 22 | IN: 'in'; 23 | FROM: 'from'; 24 | STATE: 'state'; 25 | IF: 'if'; 26 | IS: 'is'; 27 | TRY: 'try'; 28 | CATCH: 'catch'; 29 | ELSE: 'else'; 30 | NOT: 'not'; 31 | NONE: 'None'; 32 | MUT: 'mut'; 33 | AND: 'and'; 34 | OR: 'or'; 35 | TRUE: 'true'; 36 | FALSE: 'false'; 37 | FN: 'fn'; 38 | LET: 'let'; 39 | CONST: 'const'; 40 | FAIL: 'fail!'; 41 | RETURN: 'return'; 42 | STRUCT: 'struct'; 43 | ENUM: 'enum'; 44 | TYPE: 'type'; 45 | EMIT: 'emit'; 46 | AS: 'as'; 47 | 48 | 49 | // PUNCTUATION 50 | TILDE: '~'; 51 | LPAREN: '('; 52 | RPAREN: ')'; 53 | LBRACK: '['; 54 | RBRACK: ']'; 55 | LBRACE: '{'; 56 | RBRACE: '}'; 57 | DOT: '.'; 58 | COMMA: ','; 59 | D_QUEST: '??'; 60 | QUEST: '?'; 61 | BANG: '!'; 62 | SEMI: ';'; 63 | COLON: ':'; 64 | D_COLON: '::'; 65 | HASH: '#'; 66 | AT: '@'; 67 | AMP: '&'; 68 | ARROW: '->'; 69 | FAT_ARROW: '=>'; 70 | BAR: '|'; 71 | S_QUOTE: '\''; 72 | D_QUOTE: '"'; 73 | EQ: '='; // OPS 74 | EQ_EQ: '=='; 75 | NEQ: '!='; 76 | PLUS: '+'; 77 | PLUS_EQ: '+='; 78 | MINUS: '-'; 79 | MINUS_EQ: '-='; 80 | MUL: '*'; 81 | MUL_EQ: '*='; 82 | DIV: '/'; 83 | DIV_EQ: '/='; 84 | MOD: '%'; 85 | MOD_EQ: '%='; 86 | LT: '<'; 87 | LT_EQ: '<='; 88 | GT: '>'; 89 | GT_EQ: '>='; 90 | POW: '**'; 91 | 92 | // Identifiers 93 | Ident: [_a-zA-Z$][_a-zA-Z0-9]*; 94 | 95 | // Strings 96 | StringLiteral: D_QUOTE DoubleQuotedStringCharacter* D_QUOTE; 97 | fragment DoubleQuotedStringCharacter: ~["\r\n\\] | ('\\' .); 98 | 99 | // Numbers 100 | IntLiteral: DecimalDigits; 101 | DecLiteral: (DecimalDigits? DOT DecimalDigits); 102 | fragment DecimalDigits: [0-9] ( '_'? [0-9])*; 103 | 104 | // Bool 105 | BoolLiteral: TRUE | FALSE; 106 | 107 | // Comments 108 | CWSPEC_LINE_COMMENT: ('///' .*? [\r\n])+; 109 | CWSPEC_BLOCK_COMMENT: '/**' .*? '*/'; 110 | 111 | LINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN); 112 | BLOCK_COMMENT: '/*' .*? '*/' -> channel(HIDDEN); 113 | 114 | // Whitespace 115 | WS: [\r\n\t ] -> channel(HIDDEN); 116 | -------------------------------------------------------------------------------- /grammar/.antlr/CWScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | CONTRACT=1 2 | INTERFACE=2 3 | IMPORT=3 4 | IMPLEMENTS=4 5 | EXTENDS=5 6 | ERROR=6 7 | EVENT=7 8 | INSTANTIATE_NOW=8 9 | EXEC_NOW=9 10 | QUERY_NOW=10 11 | DELEGATE_EXEC=11 12 | INSTANTIATE=12 13 | EXEC=13 14 | QUERY=14 15 | REPLY=15 16 | FOR=16 17 | IN=17 18 | FROM=18 19 | STATE=19 20 | IF=20 21 | IS=21 22 | TRY=22 23 | CATCH=23 24 | ELSE=24 25 | NOT=25 26 | NONE=26 27 | MUT=27 28 | AND=28 29 | OR=29 30 | TRUE=30 31 | FALSE=31 32 | FN=32 33 | LET=33 34 | CONST=34 35 | FAIL=35 36 | RETURN=36 37 | STRUCT=37 38 | ENUM=38 39 | TYPE=39 40 | EMIT=40 41 | AS=41 42 | TILDE=42 43 | LPAREN=43 44 | RPAREN=44 45 | LBRACK=45 46 | RBRACK=46 47 | LBRACE=47 48 | RBRACE=48 49 | DOT=49 50 | COMMA=50 51 | D_QUEST=51 52 | QUEST=52 53 | BANG=53 54 | COLON=54 55 | D_COLON=55 56 | HASH=56 57 | AT=57 58 | AMP=58 59 | ARROW=59 60 | FAT_ARROW=60 61 | BAR=61 62 | S_QUOTE=62 63 | D_QUOTE=63 64 | EQ=64 65 | EQ_EQ=65 66 | NEQ=66 67 | PLUS=67 68 | PLUS_EQ=68 69 | MINUS=69 70 | MINUS_EQ=70 71 | MUL=71 72 | MUL_EQ=72 73 | DIV=73 74 | DIV_EQ=74 75 | MOD=75 76 | MOD_EQ=76 77 | LT=77 78 | LT_EQ=78 79 | GT=79 80 | GT_EQ=80 81 | POW=81 82 | Ident=82 83 | StringLiteral=83 84 | IntLiteral=84 85 | DecLiteral=85 86 | BoolLiteral=86 87 | CWSPEC_LINE_COMMENT=87 88 | CWSPEC_BLOCK_COMMENT=88 89 | LINE_COMMENT=89 90 | BLOCK_COMMENT=90 91 | WS=91 92 | 'contract'=1 93 | 'interface'=2 94 | 'import'=3 95 | 'implements'=4 96 | 'extends'=5 97 | 'error'=6 98 | 'event'=7 99 | 'instantiate!'=8 100 | 'exec!'=9 101 | 'query!'=10 102 | 'delegate_exec!'=11 103 | 'instantiate'=12 104 | 'exec'=13 105 | 'query'=14 106 | 'reply'=15 107 | 'for'=16 108 | 'in'=17 109 | 'from'=18 110 | 'state'=19 111 | 'if'=20 112 | 'is'=21 113 | 'try'=22 114 | 'catch'=23 115 | 'else'=24 116 | 'not'=25 117 | 'None'=26 118 | 'mut'=27 119 | 'and'=28 120 | 'or'=29 121 | 'true'=30 122 | 'false'=31 123 | 'fn'=32 124 | 'let'=33 125 | 'const'=34 126 | 'fail!'=35 127 | 'return'=36 128 | 'struct'=37 129 | 'enum'=38 130 | 'type'=39 131 | 'emit'=40 132 | 'as'=41 133 | '~'=42 134 | '('=43 135 | ')'=44 136 | '['=45 137 | ']'=46 138 | '{'=47 139 | '}'=48 140 | '.'=49 141 | ','=50 142 | '??'=51 143 | '?'=52 144 | '!'=53 145 | ':'=54 146 | '::'=55 147 | '#'=56 148 | '@'=57 149 | '&'=58 150 | '->'=59 151 | '=>'=60 152 | '|'=61 153 | '\''=62 154 | '"'=63 155 | '='=64 156 | '=='=65 157 | '!='=66 158 | '+'=67 159 | '+='=68 160 | '-'=69 161 | '-='=70 162 | '*'=71 163 | '*='=72 164 | '/'=73 165 | '/='=74 166 | '%'=75 167 | '%='=76 168 | '<'=77 169 | '<='=78 170 | '>'=79 171 | '>='=80 172 | '**'=81 173 | -------------------------------------------------------------------------------- /grammar/.antlr/CWScriptParser.tokens: -------------------------------------------------------------------------------- 1 | CONTRACT=1 2 | INTERFACE=2 3 | IMPORT=3 4 | IMPLEMENTS=4 5 | EXTENDS=5 6 | ERROR=6 7 | EVENT=7 8 | INSTANTIATE_NOW=8 9 | EXEC_NOW=9 10 | QUERY_NOW=10 11 | DELEGATE_EXEC=11 12 | INSTANTIATE=12 13 | EXEC=13 14 | QUERY=14 15 | REPLY=15 16 | FOR=16 17 | IN=17 18 | FROM=18 19 | STATE=19 20 | IF=20 21 | IS=21 22 | TRY=22 23 | CATCH=23 24 | ELSE=24 25 | NOT=25 26 | NONE=26 27 | MUT=27 28 | AND=28 29 | OR=29 30 | TRUE=30 31 | FALSE=31 32 | FN=32 33 | LET=33 34 | CONST=34 35 | FAIL=35 36 | RETURN=36 37 | STRUCT=37 38 | ENUM=38 39 | TYPE=39 40 | EMIT=40 41 | AS=41 42 | TILDE=42 43 | LPAREN=43 44 | RPAREN=44 45 | LBRACK=45 46 | RBRACK=46 47 | LBRACE=47 48 | RBRACE=48 49 | DOT=49 50 | COMMA=50 51 | D_QUEST=51 52 | QUEST=52 53 | BANG=53 54 | COLON=54 55 | D_COLON=55 56 | HASH=56 57 | AT=57 58 | AMP=58 59 | ARROW=59 60 | FAT_ARROW=60 61 | BAR=61 62 | S_QUOTE=62 63 | D_QUOTE=63 64 | EQ=64 65 | EQ_EQ=65 66 | NEQ=66 67 | PLUS=67 68 | PLUS_EQ=68 69 | MINUS=69 70 | MINUS_EQ=70 71 | MUL=71 72 | MUL_EQ=72 73 | DIV=73 74 | DIV_EQ=74 75 | MOD=75 76 | MOD_EQ=76 77 | LT=77 78 | LT_EQ=78 79 | GT=79 80 | GT_EQ=80 81 | POW=81 82 | Ident=82 83 | StringLiteral=83 84 | IntLiteral=84 85 | DecLiteral=85 86 | BoolLiteral=86 87 | CWSPEC_LINE_COMMENT=87 88 | CWSPEC_BLOCK_COMMENT=88 89 | LINE_COMMENT=89 90 | BLOCK_COMMENT=90 91 | WS=91 92 | 'contract'=1 93 | 'interface'=2 94 | 'import'=3 95 | 'implements'=4 96 | 'extends'=5 97 | 'error'=6 98 | 'event'=7 99 | 'instantiate!'=8 100 | 'exec!'=9 101 | 'query!'=10 102 | 'delegate_exec!'=11 103 | 'instantiate'=12 104 | 'exec'=13 105 | 'query'=14 106 | 'reply'=15 107 | 'for'=16 108 | 'in'=17 109 | 'from'=18 110 | 'state'=19 111 | 'if'=20 112 | 'is'=21 113 | 'try'=22 114 | 'catch'=23 115 | 'else'=24 116 | 'not'=25 117 | 'None'=26 118 | 'mut'=27 119 | 'and'=28 120 | 'or'=29 121 | 'true'=30 122 | 'false'=31 123 | 'fn'=32 124 | 'let'=33 125 | 'const'=34 126 | 'fail!'=35 127 | 'return'=36 128 | 'struct'=37 129 | 'enum'=38 130 | 'type'=39 131 | 'emit'=40 132 | 'as'=41 133 | '~'=42 134 | '('=43 135 | ')'=44 136 | '['=45 137 | ']'=46 138 | '{'=47 139 | '}'=48 140 | '.'=49 141 | ','=50 142 | '??'=51 143 | '?'=52 144 | '!'=53 145 | ':'=54 146 | '::'=55 147 | '#'=56 148 | '@'=57 149 | '&'=58 150 | '->'=59 151 | '=>'=60 152 | '|'=61 153 | '\''=62 154 | '"'=63 155 | '='=64 156 | '=='=65 157 | '!='=66 158 | '+'=67 159 | '+='=68 160 | '-'=69 161 | '-='=70 162 | '*'=71 163 | '*='=72 164 | '/'=73 165 | '/='=74 166 | '%'=75 167 | '%='=76 168 | '<'=77 169 | '<='=78 170 | '>'=79 171 | '>='=80 172 | '**'=81 173 | -------------------------------------------------------------------------------- /grammar/CWScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | DEBUG=1 2 | CONTRACT=2 3 | INTERFACE=3 4 | IMPORT=4 5 | IMPLEMENTS=5 6 | EXTENDS=6 7 | ERROR=7 8 | EVENT=8 9 | INSTANTIATE_NOW=9 10 | EXEC_NOW=10 11 | QUERY_NOW=11 12 | DELEGATE_EXEC=12 13 | INSTANTIATE=13 14 | EXEC=14 15 | QUERY=15 16 | REPLY=16 17 | FOR=17 18 | IN=18 19 | FROM=19 20 | STATE=20 21 | IF=21 22 | IS=22 23 | TRY=23 24 | CATCH=24 25 | ELSE=25 26 | NOT=26 27 | NONE=27 28 | MUT=28 29 | AND=29 30 | OR=30 31 | TRUE=31 32 | FALSE=32 33 | FN=33 34 | LET=34 35 | CONST=35 36 | FAIL=36 37 | RETURN=37 38 | STRUCT=38 39 | ENUM=39 40 | TYPE=40 41 | EMIT=41 42 | AS=42 43 | TILDE=43 44 | LPAREN=44 45 | RPAREN=45 46 | LBRACK=46 47 | RBRACK=47 48 | LBRACE=48 49 | RBRACE=49 50 | DOT=50 51 | COMMA=51 52 | D_QUEST=52 53 | QUEST=53 54 | BANG=54 55 | SEMI=55 56 | COLON=56 57 | D_COLON=57 58 | HASH=58 59 | AT=59 60 | AMP=60 61 | ARROW=61 62 | FAT_ARROW=62 63 | BAR=63 64 | S_QUOTE=64 65 | D_QUOTE=65 66 | EQ=66 67 | EQ_EQ=67 68 | NEQ=68 69 | PLUS=69 70 | PLUS_EQ=70 71 | MINUS=71 72 | MINUS_EQ=72 73 | MUL=73 74 | MUL_EQ=74 75 | DIV=75 76 | DIV_EQ=76 77 | MOD=77 78 | MOD_EQ=78 79 | LT=79 80 | LT_EQ=80 81 | GT=81 82 | GT_EQ=82 83 | POW=83 84 | Ident=84 85 | StringLiteral=85 86 | IntLiteral=86 87 | DecLiteral=87 88 | BoolLiteral=88 89 | CWSPEC_LINE_COMMENT=89 90 | CWSPEC_BLOCK_COMMENT=90 91 | LINE_COMMENT=91 92 | BLOCK_COMMENT=92 93 | WS=93 94 | 'debug!'=1 95 | 'contract'=2 96 | 'interface'=3 97 | 'import'=4 98 | 'implements'=5 99 | 'extends'=6 100 | 'error'=7 101 | 'event'=8 102 | 'instantiate!'=9 103 | 'exec!'=10 104 | 'query!'=11 105 | 'delegate_exec!'=12 106 | 'instantiate'=13 107 | 'exec'=14 108 | 'query'=15 109 | 'reply'=16 110 | 'for'=17 111 | 'in'=18 112 | 'from'=19 113 | 'state'=20 114 | 'if'=21 115 | 'is'=22 116 | 'try'=23 117 | 'catch'=24 118 | 'else'=25 119 | 'not'=26 120 | 'None'=27 121 | 'mut'=28 122 | 'and'=29 123 | 'or'=30 124 | 'true'=31 125 | 'false'=32 126 | 'fn'=33 127 | 'let'=34 128 | 'const'=35 129 | 'fail!'=36 130 | 'return'=37 131 | 'struct'=38 132 | 'enum'=39 133 | 'type'=40 134 | 'emit'=41 135 | 'as'=42 136 | '~'=43 137 | '('=44 138 | ')'=45 139 | '['=46 140 | ']'=47 141 | '{'=48 142 | '}'=49 143 | '.'=50 144 | ','=51 145 | '??'=52 146 | '?'=53 147 | '!'=54 148 | ';'=55 149 | ':'=56 150 | '::'=57 151 | '#'=58 152 | '@'=59 153 | '&'=60 154 | '->'=61 155 | '=>'=62 156 | '|'=63 157 | '\''=64 158 | '"'=65 159 | '='=66 160 | '=='=67 161 | '!='=68 162 | '+'=69 163 | '+='=70 164 | '-'=71 165 | '-='=72 166 | '*'=73 167 | '*='=74 168 | '/'=75 169 | '/='=76 170 | '%'=77 171 | '%='=78 172 | '<'=79 173 | '<='=80 174 | '>'=81 175 | '>='=82 176 | '**'=83 177 | -------------------------------------------------------------------------------- /grammar/gen/CWScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | DEBUG=1 2 | CONTRACT=2 3 | INTERFACE=3 4 | IMPORT=4 5 | IMPLEMENTS=5 6 | EXTENDS=6 7 | ERROR=7 8 | EVENT=8 9 | INSTANTIATE_NOW=9 10 | EXEC_NOW=10 11 | QUERY_NOW=11 12 | DELEGATE_EXEC=12 13 | INSTANTIATE=13 14 | EXEC=14 15 | QUERY=15 16 | REPLY=16 17 | FOR=17 18 | IN=18 19 | FROM=19 20 | STATE=20 21 | IF=21 22 | IS=22 23 | TRY=23 24 | CATCH=24 25 | ELSE=25 26 | NOT=26 27 | NONE=27 28 | MUT=28 29 | AND=29 30 | OR=30 31 | TRUE=31 32 | FALSE=32 33 | FN=33 34 | LET=34 35 | CONST=35 36 | FAIL=36 37 | RETURN=37 38 | STRUCT=38 39 | ENUM=39 40 | TYPE=40 41 | EMIT=41 42 | AS=42 43 | TILDE=43 44 | LPAREN=44 45 | RPAREN=45 46 | LBRACK=46 47 | RBRACK=47 48 | LBRACE=48 49 | RBRACE=49 50 | DOT=50 51 | COMMA=51 52 | D_QUEST=52 53 | QUEST=53 54 | BANG=54 55 | SEMI=55 56 | COLON=56 57 | D_COLON=57 58 | HASH=58 59 | AT=59 60 | AMP=60 61 | ARROW=61 62 | FAT_ARROW=62 63 | BAR=63 64 | S_QUOTE=64 65 | D_QUOTE=65 66 | EQ=66 67 | EQ_EQ=67 68 | NEQ=68 69 | PLUS=69 70 | PLUS_EQ=70 71 | MINUS=71 72 | MINUS_EQ=72 73 | MUL=73 74 | MUL_EQ=74 75 | DIV=75 76 | DIV_EQ=76 77 | MOD=77 78 | MOD_EQ=78 79 | LT=79 80 | LT_EQ=80 81 | GT=81 82 | GT_EQ=82 83 | POW=83 84 | Ident=84 85 | StringLiteral=85 86 | IntLiteral=86 87 | DecLiteral=87 88 | BoolLiteral=88 89 | CWSPEC_LINE_COMMENT=89 90 | CWSPEC_BLOCK_COMMENT=90 91 | LINE_COMMENT=91 92 | BLOCK_COMMENT=92 93 | WS=93 94 | 'debug!'=1 95 | 'contract'=2 96 | 'interface'=3 97 | 'import'=4 98 | 'implements'=5 99 | 'extends'=6 100 | 'error'=7 101 | 'event'=8 102 | 'instantiate!'=9 103 | 'exec!'=10 104 | 'query!'=11 105 | 'delegate_exec!'=12 106 | 'instantiate'=13 107 | 'exec'=14 108 | 'query'=15 109 | 'reply'=16 110 | 'for'=17 111 | 'in'=18 112 | 'from'=19 113 | 'state'=20 114 | 'if'=21 115 | 'is'=22 116 | 'try'=23 117 | 'catch'=24 118 | 'else'=25 119 | 'not'=26 120 | 'None'=27 121 | 'mut'=28 122 | 'and'=29 123 | 'or'=30 124 | 'true'=31 125 | 'false'=32 126 | 'fn'=33 127 | 'let'=34 128 | 'const'=35 129 | 'fail!'=36 130 | 'return'=37 131 | 'struct'=38 132 | 'enum'=39 133 | 'type'=40 134 | 'emit'=41 135 | 'as'=42 136 | '~'=43 137 | '('=44 138 | ')'=45 139 | '['=46 140 | ']'=47 141 | '{'=48 142 | '}'=49 143 | '.'=50 144 | ','=51 145 | '??'=52 146 | '?'=53 147 | '!'=54 148 | ';'=55 149 | ':'=56 150 | '::'=57 151 | '#'=58 152 | '@'=59 153 | '&'=60 154 | '->'=61 155 | '=>'=62 156 | '|'=63 157 | '\''=64 158 | '"'=65 159 | '='=66 160 | '=='=67 161 | '!='=68 162 | '+'=69 163 | '+='=70 164 | '-'=71 165 | '-='=72 166 | '*'=73 167 | '*='=74 168 | '/'=75 169 | '/='=76 170 | '%'=77 171 | '%='=78 172 | '<'=79 173 | '<='=80 174 | '>'=81 175 | '>='=82 176 | '**'=83 177 | -------------------------------------------------------------------------------- /gen/CWScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | DEBUG=1 2 | CONTRACT=2 3 | INTERFACE=3 4 | IMPORT=4 5 | IMPLEMENTS=5 6 | EXTENDS=6 7 | ERROR=7 8 | EVENT=8 9 | DEFER=9 10 | INSTANTIATE_NOW=10 11 | EXEC_NOW=11 12 | QUERY_NOW=12 13 | DELEGATE_EXEC=13 14 | INSTANTIATE=14 15 | EXEC=15 16 | QUERY=16 17 | REPLY=17 18 | FOR=18 19 | IN=19 20 | FROM=20 21 | STATE=21 22 | IF=22 23 | IS=23 24 | TRY=24 25 | CATCH=25 26 | ELSE=26 27 | NOT=27 28 | NONE=28 29 | MUT=29 30 | AND=30 31 | OR=31 32 | TRUE=32 33 | FALSE=33 34 | FN=34 35 | LET=35 36 | CONST=36 37 | FAIL=37 38 | RETURN=38 39 | STRUCT=39 40 | ENUM=40 41 | TYPE=41 42 | EMIT=42 43 | AS=43 44 | TILDE=44 45 | LPAREN=45 46 | RPAREN=46 47 | LBRACK=47 48 | RBRACK=48 49 | LBRACE=49 50 | RBRACE=50 51 | DOT=51 52 | COMMA=52 53 | D_QUEST=53 54 | QUEST=54 55 | BANG=55 56 | SEMI=56 57 | COLON=57 58 | D_COLON=58 59 | HASH=59 60 | AT=60 61 | AMP=61 62 | ARROW=62 63 | FAT_ARROW=63 64 | BAR=64 65 | S_QUOTE=65 66 | D_QUOTE=66 67 | EQ=67 68 | EQ_EQ=68 69 | NEQ=69 70 | PLUS=70 71 | PLUS_EQ=71 72 | MINUS=72 73 | MINUS_EQ=73 74 | MUL=74 75 | MUL_EQ=75 76 | DIV=76 77 | DIV_EQ=77 78 | MOD=78 79 | MOD_EQ=79 80 | LT=80 81 | LT_EQ=81 82 | GT=82 83 | GT_EQ=83 84 | POW=84 85 | Ident=85 86 | StringLiteral=86 87 | IntLiteral=87 88 | DecLiteral=88 89 | BoolLiteral=89 90 | CWSPEC_LINE_COMMENT=90 91 | CWSPEC_BLOCK_COMMENT=91 92 | LINE_COMMENT=92 93 | BLOCK_COMMENT=93 94 | WS=94 95 | 'debug!'=1 96 | 'contract'=2 97 | 'interface'=3 98 | 'import'=4 99 | 'implements'=5 100 | 'extends'=6 101 | 'error'=7 102 | 'event'=8 103 | 'defer'=9 104 | 'instantiate!'=10 105 | 'exec!'=11 106 | 'query!'=12 107 | 'delegate_exec!'=13 108 | 'instantiate'=14 109 | 'exec'=15 110 | 'query'=16 111 | 'reply'=17 112 | 'for'=18 113 | 'in'=19 114 | 'from'=20 115 | 'state'=21 116 | 'if'=22 117 | 'is'=23 118 | 'try'=24 119 | 'catch'=25 120 | 'else'=26 121 | 'not'=27 122 | 'None'=28 123 | 'mut'=29 124 | 'and'=30 125 | 'or'=31 126 | 'true'=32 127 | 'false'=33 128 | 'fn'=34 129 | 'let'=35 130 | 'const'=36 131 | 'fail!'=37 132 | 'return'=38 133 | 'struct'=39 134 | 'enum'=40 135 | 'type'=41 136 | 'emit'=42 137 | 'as'=43 138 | '~'=44 139 | '('=45 140 | ')'=46 141 | '['=47 142 | ']'=48 143 | '{'=49 144 | '}'=50 145 | '.'=51 146 | ','=52 147 | '??'=53 148 | '?'=54 149 | '!'=55 150 | ';'=56 151 | ':'=57 152 | '::'=58 153 | '#'=59 154 | '@'=60 155 | '&'=61 156 | '->'=62 157 | '=>'=63 158 | '|'=64 159 | '\''=65 160 | '"'=66 161 | '='=67 162 | '=='=68 163 | '!='=69 164 | '+'=70 165 | '+='=71 166 | '-'=72 167 | '-='=73 168 | '*'=74 169 | '*='=75 170 | '/'=76 171 | '/='=77 172 | '%'=78 173 | '%='=79 174 | '<'=80 175 | '<='=81 176 | '>'=82 177 | '>='=83 178 | '**'=84 179 | -------------------------------------------------------------------------------- /src/grammar/CWScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | DEBUG=1 2 | CONTRACT=2 3 | INTERFACE=3 4 | IMPORT=4 5 | IMPLEMENTS=5 6 | EXTENDS=6 7 | ERROR=7 8 | EVENT=8 9 | DEFER=9 10 | INSTANTIATE_NOW=10 11 | EXEC_NOW=11 12 | QUERY_NOW=12 13 | DELEGATE_EXEC=13 14 | INSTANTIATE=14 15 | EXEC=15 16 | QUERY=16 17 | REPLY=17 18 | FOR=18 19 | IN=19 20 | FROM=20 21 | STATE=21 22 | IF=22 23 | IS=23 24 | TRY=24 25 | CATCH=25 26 | ELSE=26 27 | NOT=27 28 | NONE=28 29 | MUT=29 30 | AND=30 31 | OR=31 32 | TRUE=32 33 | FALSE=33 34 | FN=34 35 | LET=35 36 | CONST=36 37 | FAIL=37 38 | RETURN=38 39 | STRUCT=39 40 | ENUM=40 41 | TYPE=41 42 | EMIT=42 43 | AS=43 44 | TILDE=44 45 | LPAREN=45 46 | RPAREN=46 47 | LBRACK=47 48 | RBRACK=48 49 | LBRACE=49 50 | RBRACE=50 51 | DOT=51 52 | COMMA=52 53 | D_QUEST=53 54 | QUEST=54 55 | BANG=55 56 | SEMI=56 57 | COLON=57 58 | D_COLON=58 59 | HASH=59 60 | AT=60 61 | AMP=61 62 | ARROW=62 63 | FAT_ARROW=63 64 | BAR=64 65 | S_QUOTE=65 66 | D_QUOTE=66 67 | EQ=67 68 | EQ_EQ=68 69 | NEQ=69 70 | PLUS=70 71 | PLUS_EQ=71 72 | MINUS=72 73 | MINUS_EQ=73 74 | MUL=74 75 | MUL_EQ=75 76 | DIV=76 77 | DIV_EQ=77 78 | MOD=78 79 | MOD_EQ=79 80 | LT=80 81 | LT_EQ=81 82 | GT=82 83 | GT_EQ=83 84 | POW=84 85 | Ident=85 86 | StringLiteral=86 87 | IntLiteral=87 88 | DecLiteral=88 89 | BoolLiteral=89 90 | CWSPEC_LINE_COMMENT=90 91 | CWSPEC_BLOCK_COMMENT=91 92 | LINE_COMMENT=92 93 | BLOCK_COMMENT=93 94 | WS=94 95 | 'debug!'=1 96 | 'contract'=2 97 | 'interface'=3 98 | 'import'=4 99 | 'implements'=5 100 | 'extends'=6 101 | 'error'=7 102 | 'event'=8 103 | 'defer'=9 104 | 'instantiate!'=10 105 | 'exec!'=11 106 | 'query!'=12 107 | 'delegate_exec!'=13 108 | 'instantiate'=14 109 | 'exec'=15 110 | 'query'=16 111 | 'reply'=17 112 | 'for'=18 113 | 'in'=19 114 | 'from'=20 115 | 'state'=21 116 | 'if'=22 117 | 'is'=23 118 | 'try'=24 119 | 'catch'=25 120 | 'else'=26 121 | 'not'=27 122 | 'None'=28 123 | 'mut'=29 124 | 'and'=30 125 | 'or'=31 126 | 'true'=32 127 | 'false'=33 128 | 'fn'=34 129 | 'let'=35 130 | 'const'=36 131 | 'fail!'=37 132 | 'return'=38 133 | 'struct'=39 134 | 'enum'=40 135 | 'type'=41 136 | 'emit'=42 137 | 'as'=43 138 | '~'=44 139 | '('=45 140 | ')'=46 141 | '['=47 142 | ']'=48 143 | '{'=49 144 | '}'=50 145 | '.'=51 146 | ','=52 147 | '??'=53 148 | '?'=54 149 | '!'=55 150 | ';'=56 151 | ':'=57 152 | '::'=58 153 | '#'=59 154 | '@'=60 155 | '&'=61 156 | '->'=62 157 | '=>'=63 158 | '|'=64 159 | '\''=65 160 | '"'=66 161 | '='=67 162 | '=='=68 163 | '!='=69 164 | '+'=70 165 | '+='=71 166 | '-'=72 167 | '-='=73 168 | '*'=74 169 | '*='=75 170 | '/'=76 171 | '/='=77 172 | '%'=78 173 | '%='=79 174 | '<'=80 175 | '<='=81 176 | '>'=82 177 | '>='=83 178 | '**'=84 179 | -------------------------------------------------------------------------------- /src/grammar/CWScriptParser.tokens: -------------------------------------------------------------------------------- 1 | DEBUG=1 2 | CONTRACT=2 3 | INTERFACE=3 4 | IMPORT=4 5 | IMPLEMENTS=5 6 | EXTENDS=6 7 | ERROR=7 8 | EVENT=8 9 | DEFER=9 10 | INSTANTIATE_NOW=10 11 | EXEC_NOW=11 12 | QUERY_NOW=12 13 | DELEGATE_EXEC=13 14 | INSTANTIATE=14 15 | EXEC=15 16 | QUERY=16 17 | REPLY=17 18 | FOR=18 19 | IN=19 20 | FROM=20 21 | STATE=21 22 | IF=22 23 | IS=23 24 | TRY=24 25 | CATCH=25 26 | ELSE=26 27 | NOT=27 28 | NONE=28 29 | MUT=29 30 | AND=30 31 | OR=31 32 | TRUE=32 33 | FALSE=33 34 | FN=34 35 | LET=35 36 | CONST=36 37 | FAIL=37 38 | RETURN=38 39 | STRUCT=39 40 | ENUM=40 41 | TYPE=41 42 | EMIT=42 43 | AS=43 44 | TILDE=44 45 | LPAREN=45 46 | RPAREN=46 47 | LBRACK=47 48 | RBRACK=48 49 | LBRACE=49 50 | RBRACE=50 51 | DOT=51 52 | COMMA=52 53 | D_QUEST=53 54 | QUEST=54 55 | BANG=55 56 | SEMI=56 57 | COLON=57 58 | D_COLON=58 59 | HASH=59 60 | AT=60 61 | AMP=61 62 | ARROW=62 63 | FAT_ARROW=63 64 | BAR=64 65 | S_QUOTE=65 66 | D_QUOTE=66 67 | EQ=67 68 | EQ_EQ=68 69 | NEQ=69 70 | PLUS=70 71 | PLUS_EQ=71 72 | MINUS=72 73 | MINUS_EQ=73 74 | MUL=74 75 | MUL_EQ=75 76 | DIV=76 77 | DIV_EQ=77 78 | MOD=78 79 | MOD_EQ=79 80 | LT=80 81 | LT_EQ=81 82 | GT=82 83 | GT_EQ=83 84 | POW=84 85 | Ident=85 86 | StringLiteral=86 87 | IntLiteral=87 88 | DecLiteral=88 89 | BoolLiteral=89 90 | CWSPEC_LINE_COMMENT=90 91 | CWSPEC_BLOCK_COMMENT=91 92 | LINE_COMMENT=92 93 | BLOCK_COMMENT=93 94 | WS=94 95 | 'debug!'=1 96 | 'contract'=2 97 | 'interface'=3 98 | 'import'=4 99 | 'implements'=5 100 | 'extends'=6 101 | 'error'=7 102 | 'event'=8 103 | 'defer'=9 104 | 'instantiate!'=10 105 | 'exec!'=11 106 | 'query!'=12 107 | 'delegate_exec!'=13 108 | 'instantiate'=14 109 | 'exec'=15 110 | 'query'=16 111 | 'reply'=17 112 | 'for'=18 113 | 'in'=19 114 | 'from'=20 115 | 'state'=21 116 | 'if'=22 117 | 'is'=23 118 | 'try'=24 119 | 'catch'=25 120 | 'else'=26 121 | 'not'=27 122 | 'None'=28 123 | 'mut'=29 124 | 'and'=30 125 | 'or'=31 126 | 'true'=32 127 | 'false'=33 128 | 'fn'=34 129 | 'let'=35 130 | 'const'=36 131 | 'fail!'=37 132 | 'return'=38 133 | 'struct'=39 134 | 'enum'=40 135 | 'type'=41 136 | 'emit'=42 137 | 'as'=43 138 | '~'=44 139 | '('=45 140 | ')'=46 141 | '['=47 142 | ']'=48 143 | '{'=49 144 | '}'=50 145 | '.'=51 146 | ','=52 147 | '??'=53 148 | '?'=54 149 | '!'=55 150 | ';'=56 151 | ':'=57 152 | '::'=58 153 | '#'=59 154 | '@'=60 155 | '&'=61 156 | '->'=62 157 | '=>'=63 158 | '|'=64 159 | '\''=65 160 | '"'=66 161 | '='=67 162 | '=='=68 163 | '!='=69 164 | '+'=70 165 | '+='=71 166 | '-'=72 167 | '-='=73 168 | '*'=74 169 | '*='=75 170 | '/'=76 171 | '/='=77 172 | '%'=78 173 | '%='=79 174 | '<'=80 175 | '<='=81 176 | '>'=82 177 | '>='=83 178 | '**'=84 179 | -------------------------------------------------------------------------------- /__tests__/interpreter/TerraswapToken.test.ts: -------------------------------------------------------------------------------- 1 | import { ContractInstance, CWSInterpreter, Env } from '../../src/interpreter'; 2 | import { 3 | ContractDefn, 4 | ContractReference, 5 | CWSString, 6 | STDLIB, 7 | StringT, 8 | AddressT, 9 | None, 10 | U8_T, 11 | U128_T, 12 | IntT, 13 | args, 14 | InterfaceDefn, 15 | StructDefn, 16 | ListT, 17 | FnDefn, 18 | } from '../../src/stdlib'; 19 | import * as fs from 'fs'; 20 | 21 | const EXAMPLES_DIR = __dirname + '/../../examples'; 22 | const TERRASWAP_TOKEN_FILE = EXAMPLES_DIR + '/terraswap/TerraswapToken.cws'; 23 | 24 | describe('Interpreter: TerraswapToken', () => { 25 | it('should be able to parse and interpret a TerraswapToken contract', () => { 26 | const sourceText = fs.readFileSync(TERRASWAP_TOKEN_FILE, 'utf8'); 27 | 28 | const interpreter = new CWSInterpreter({ 29 | sources: { 30 | [TERRASWAP_TOKEN_FILE]: sourceText, 31 | }, 32 | env: STDLIB, 33 | }); 34 | 35 | let TerraswapToken = interpreter.getSymbol('TerraswapToken'); 36 | let CW20 = interpreter.getSymbol('CW20'); 37 | let Coin = CW20.getSymbol('Coin'); 38 | let CoinList = new ListT(Coin); 39 | 40 | let myAddress = CWSString.TYPE.value( 41 | 'terra1hzh9vpxhsk82503se0vv5jj6etdvxu3nv8z07e' 42 | ); 43 | let instantiateArgs = args([], { 44 | name: StringT.value('Terran One Token'), 45 | symbol: StringT.value('TONE'), 46 | decimals: U8_T.value(6), 47 | initial_balances: CoinList.value([ 48 | Coin.value(args([StringT.value('yogesh'), U128_T.value('1000000000')])), 49 | Coin.value( 50 | args([StringT.value('william'), U128_T.value('1000000000')]) 51 | ), 52 | ]), 53 | }); 54 | let instantiateMsg = TerraswapToken.instantiate(instantiateArgs); 55 | // call the instantiate implementation 56 | 57 | let env: Env = { 58 | block: { 59 | height: 1, 60 | time: 1, 61 | chain_id: 'terran-1', 62 | }, 63 | contract: { 64 | address: 't1tokenaddr', 65 | }, 66 | }; 67 | 68 | let info = { 69 | sender: 'william', 70 | funds: [ 71 | { 72 | amount: '1000000000', 73 | denom: 'utone', 74 | }, 75 | ], 76 | }; 77 | 78 | let myToken = new ContractInstance(interpreter, TerraswapToken); 79 | let res = myToken.instantiate(env, info, instantiateArgs); 80 | let res2 = myToken.exec( 81 | env, 82 | info, 83 | 'transfer', 84 | args([], { 85 | recipient: StringT.value('yogesh'), 86 | amount: U128_T.value('5000000'), 87 | }) 88 | ); 89 | console.log(res2); 90 | myToken.state; 91 | expect(TerraswapToken).toBeInstanceOf(ContractDefn); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 17 | 18 | 26 | 27 | 30 | 31 | 38 | 39 | 46 | 47 | 54 | 55 | 60 | 61 | -------------------------------------------------------------------------------- /dist/parser/validation.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/parser/validation.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /examples/atomic-order-example/AtomicOrderExample.cws: -------------------------------------------------------------------------------- 1 | import { SubaccountId, MarketId } from "injective/types" 2 | import { FPDecimal } from "injective/math" 3 | import { CW2 } from "standards/cw2" 4 | 5 | const CONTRACT_NAME = "crates.io:atomic-order-example" 6 | const CONTRACT_VERSION = "0.0.1" 7 | 8 | contract AtomicOrderExample extends CW2 { 9 | 10 | state { 11 | config: struct ContractConfigState { 12 | market_id: MarketId, 13 | owner: Address, 14 | contract_subaccount_id: SubaccountId, 15 | base_denom: String, 16 | quote_denom: String 17 | } 18 | swap_operation_state: struct SwapCacheState { 19 | sender_address: String, 20 | deposited_amount: Coin 21 | } 22 | } 23 | 24 | #instantiate( 25 | market_id: MarketId 26 | ) { 27 | 28 | let market = try { 29 | query! Exchange.#market(market_id) 30 | } else fail! "Market with id: {market_id} not found" 31 | 32 | let config = ContractConfigState { 33 | market_id, 34 | base_denom: market.base_denom, 35 | quote_denom: market.quote_denom, 36 | owner: $info.sender, 37 | contract_subaccount_id: SubaccountId($env.contract.address, 0), 38 | } 39 | 40 | CW2.set_contract_version!($, CONTRACT_NAME, CONTRACT_VERSION) 41 | 42 | // we've changed it to "config" 43 | $state.config = config 44 | emit event(method="instantiate", owner=$info.sender) // anonymous event 45 | } 46 | 47 | reply.success handle_atomic_order() { 48 | let dec_scale_factor = FPDecimal(1000000000000000000) 49 | let order_response = Exchange.#create_spot_market_order::parse_response!($data) 50 | 51 | let trade_data = order_response.results ?? fail! "No trade data in order response" 52 | let quantity = FPDecimal!(trade_data.quantity) 53 | let price = FPDecimal!(trade_data.price) 54 | let fee = FPDecimal!(trade_data.fee) 55 | 56 | let { config, cache } = $state 57 | let contract_address = $env.contract.address 58 | let subaccount_id = config.contract_subaccount_id 59 | let cache = $state.cache 60 | let purchased_coins = coin(quantity, config.base_denom) 61 | let pair = quantity * price + fee 62 | let leftover = cache.deposited_amount.amount - paid 63 | 64 | 65 | exec! Exchange.#withdraw(contract_address, subaccount_id, purchased_coins) 66 | exec! Exchange.#withdraw(contract_address, subaccount_id, leftover_coins) 67 | exec! Bank.#send(cache.sender_address, [purchased_coins, leftover_coins]) 68 | } 69 | 70 | exec #swap_spot(quantity: FPDecimal, price: FPDecimal) { 71 | let { config } = $state 72 | let contract = $env.contract.address 73 | let subaccount_id = config.contract_subaccount_id 74 | let min_deposit = price quantity 75 | 76 | if $info.funds.is_empty() { 77 | fail! "No funds deposited!" 78 | } 79 | 80 | let message_deposit = FPDecimal!($info.funds[0].amount) 81 | 82 | if message_deposit < min_deposit { 83 | fail! "Deposit: {message_deposit} below min_deposit: {min_deposit}" 84 | } 85 | 86 | let order = SpotOrder( 87 | price, quantity, OrderType.#BuyAtomic, config.market_id, subaccount_id, contract 88 | ) 89 | 90 | let coins = $info.funds[0] 91 | 92 | $state.swap_operation_state = SwapCacheState($info.sender, coins) 93 | 94 | exec! Exchange.#deposit(contract, subaccount_id, coins) 95 | 96 | @reply.success(handle_atomic_order) 97 | exec! Exchange.create_spot_market_order(contract, order) 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /dist/parser/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/util/result.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/util/result.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /oclif.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "commands": { 4 | "parse": { 5 | "id": "parse", 6 | "description": "Parse a CWScript source file into AST.", 7 | "strict": true, 8 | "pluginName": "@terran-one/cwsc", 9 | "pluginAlias": "@terran-one/cwsc", 10 | "pluginType": "core", 11 | "aliases": [], 12 | "examples": [ 13 | "<%= config.bin %> <%= command.id %> FILE", 14 | "<%= config.bin %> <%= command.id %> FILE --format sexp" 15 | ], 16 | "flags": { 17 | "verbose": { 18 | "name": "verbose", 19 | "type": "boolean", 20 | "char": "V", 21 | "description": "Show verbose output - turns on all logs", 22 | "allowNo": false 23 | }, 24 | "silent": { 25 | "name": "silent", 26 | "type": "boolean", 27 | "char": "Q", 28 | "description": "Show no output", 29 | "allowNo": false, 30 | "exclusive": [ 31 | "verbose" 32 | ], 33 | "aliases": [ 34 | "quiet" 35 | ] 36 | }, 37 | "logs": { 38 | "name": "logs", 39 | "type": "option", 40 | "char": "L", 41 | "description": "Show logs of the specified level", 42 | "multiple": true, 43 | "options": [ 44 | "none", 45 | "info", 46 | "debug", 47 | "warn", 48 | "error" 49 | ], 50 | "exclusive": [ 51 | "silent" 52 | ], 53 | "default": [ 54 | "warn", 55 | "error" 56 | ], 57 | "delimiter": "," 58 | }, 59 | "log-file": { 60 | "name": "log-file", 61 | "type": "option", 62 | "description": "Write logs to a file", 63 | "multiple": false, 64 | "dependsOn": [ 65 | "logs" 66 | ] 67 | }, 68 | "project-dir": { 69 | "name": "project-dir", 70 | "type": "option", 71 | "char": "D", 72 | "description": "Specify a directory containing a `cwsproject.toml` file to run the command in a specific project.", 73 | "multiple": false, 74 | "exclusive": [ 75 | "project-config", 76 | "project-dir" 77 | ] 78 | }, 79 | "cwsconfig": { 80 | "name": "cwsconfig", 81 | "type": "option", 82 | "char": "C", 83 | "description": "Specify a path to `cwsconfig.toml` to use base compiler tool settings.", 84 | "multiple": false 85 | }, 86 | "X": { 87 | "name": "X", 88 | "type": "option", 89 | "description": "Set a config value temporarily for this command. This flag can be used multiple times to set multiple values.", 90 | "helpLabel": "-Xkey value", 91 | "multiple": true 92 | }, 93 | "format": { 94 | "name": "format", 95 | "type": "option", 96 | "description": "Desired format of the parsed AST output", 97 | "required": true, 98 | "multiple": false, 99 | "options": [ 100 | "json", 101 | "sexp" 102 | ], 103 | "default": "json" 104 | }, 105 | "out": { 106 | "name": "out", 107 | "type": "option", 108 | "char": "o", 109 | "description": "Output file to write the parsed AST to", 110 | "required": false, 111 | "multiple": false 112 | } 113 | }, 114 | "args": { 115 | "file": { 116 | "name": "file", 117 | "description": "File to parse into AST; if not provided, can read from .", 118 | "required": true 119 | } 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /src/cli/BaseCommand.ts: -------------------------------------------------------------------------------- 1 | import { Command, Flags, Args, Interfaces } from '@oclif/core'; 2 | import * as fs from 'fs-extra'; 3 | import * as path from 'path'; 4 | 5 | export type FlagsT = Interfaces.InferredFlags< 6 | typeof BaseCommand['baseFlags'] & T['flags'] 7 | >; 8 | export type ArgsT = Interfaces.InferredArgs< 9 | T['args'] 10 | >; 11 | 12 | export class ConfigKV { 13 | constructor(public key: string, public value: string) {} 14 | } 15 | 16 | export abstract class BaseCommand extends Command { 17 | async loadConfig() { 18 | const userConfig = await fs.readJSON( 19 | path.join(this.config.configDir, 'cwsconfig.json') 20 | ); 21 | 22 | this.log('User config:'); 23 | console.dir(userConfig); 24 | } 25 | 26 | protected flags!: FlagsT; 27 | protected args!: ArgsT; 28 | 29 | public async init(): Promise { 30 | await super.init(); 31 | const { args, flags } = await this.parse({ 32 | flags: this.ctor.flags, 33 | baseFlags: (super.ctor as typeof BaseCommand).baseFlags, 34 | args: this.ctor.args, 35 | strict: this.ctor.strict, 36 | }); 37 | this.flags = flags as FlagsT; 38 | this.args = args as ArgsT; 39 | } 40 | 41 | static baseFlags = { 42 | verbose: Flags.boolean({ 43 | char: 'V', 44 | description: 'Show verbose output - turns on all logs and diagnostics.', 45 | default: false, 46 | }), 47 | silent: Flags.boolean({ 48 | char: 'Q', 49 | description: 'Show no output', 50 | default: false, 51 | aliases: ['quiet'], 52 | exclusive: ['verbose'], 53 | }), 54 | 'show-hints': Flags.boolean({ 55 | description: 'Show CWScript "hint" and "info" diagnostics when parsing.', 56 | default: false, 57 | exclusive: ['silent'], 58 | }), 59 | 'show-warnings': Flags.boolean({ 60 | description: 'Show CWScript "warning" diagnostics when parsing.', 61 | default: true, 62 | exclusive: ['silent'], 63 | }), 64 | logs: Flags.string({ 65 | description: 'Show compiler tool logs above a certain level', 66 | options: ['NONE', 'INFO', 'DEBUG', 'WARNING', 'ERROR'], 67 | default: ['ERROR'], 68 | exclusive: ['silent'], 69 | }), 70 | 'log-file': Flags.file({ 71 | description: 'Write logs to a file', 72 | env: 'CWSC_LOG_FILE', 73 | dependsOn: ['logs'], 74 | }), 75 | 'project-dir': Flags.directory({ 76 | char: 'D', 77 | description: 78 | 'Specify a directory containing a `cwsproject.toml` file to run the command in a specific project.', 79 | exclusive: ['project-config', 'project-dir'], 80 | env: 'CWS_PROJECT_DIR', 81 | }), 82 | cwsconfig: Flags.file({ 83 | char: 'C', 84 | description: 85 | 'Specify a path to `cwsconfig.toml` to use base compiler tool settings.', 86 | env: 'CWS_CONFIG', 87 | }), 88 | // set: Flags.custom({ 89 | // multiple: true, 90 | // description: `Set a config value temporarily for this command. This flag can be used multiple times to set multiple values.`, 91 | // helpLabel: '-Xset=value', 92 | // parse: async (input: string) => { 93 | // const [key, value] = input.split('='); 94 | // return new ConfigKV(key, value); 95 | // }, 96 | // })(), 97 | }; 98 | 99 | protected async catch(err: Error & { exitCode?: number }): Promise { 100 | // add any custom logic to handle errors from the command 101 | // or simply return the parent class error handling 102 | return super.catch(err); 103 | } 104 | 105 | protected async finally(_: Error | undefined): Promise { 106 | // called after run and catch regardless of whether or not the command errored 107 | return super.finally(_); 108 | } 109 | 110 | abstract run(): Promise; 111 | } 112 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@terran-one/cwsc", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "main": "dist/index.js", 6 | "typings": "dist/index.d.ts", 7 | "type": "commonjs", 8 | "files": [ 9 | "bin", 10 | "dist", 11 | "src", 12 | "/oclif.manifest.json" 13 | ], 14 | "engines": { 15 | "node": ">=10" 16 | }, 17 | "bin": { 18 | "cwsc": "./bin/run" 19 | }, 20 | "scripts": { 21 | "prepack": "bun run build && oclif manifest", 22 | "postpack": "shx rm -f oclif.manifest.json", 23 | "build": "shx rm -rf dist && tsc --module commonjs && webpack --mode production", 24 | "build:types": "tsc --declaration --emitDeclarationOnly", 25 | "format": "prettier --check ./src/**/*.ts", 26 | "format:fix": "prettier --write ./src/**/*.ts", 27 | "lint": "eslint src --ext .js,.ts", 28 | "lint:fix": "eslint src --ext .js,.ts --fix", 29 | "parse": "ts-node src/parser/index.ts", 30 | "viz": "ts-node src/vizserver.ts", 31 | "cli": "./bin/dev", 32 | "size": "size-limit", 33 | "analyze": "size-limit --why", 34 | "gen:tm-grammar": "ts-node ./scripts/gen-tm-grammar.ts", 35 | "antlr-lexer": "antlr4ts ./grammar/CWScriptLexer.g4 -o ./src", 36 | "antlr-parser": "antlr4ts -visitor ./grammar/CWScriptParser.g4 -o ./src -lib ./src/grammar", 37 | "antlr": "bun run antlr-lexer && bun run antlr-parser", 38 | "doc": "typedoc", 39 | "prepublishOnly": "npm run build", 40 | "test": "jest __tests__" 41 | }, 42 | "husky": { 43 | "hooks": { 44 | "pre-commit": "tsdx lint" 45 | } 46 | }, 47 | "prettier": { 48 | "printWidth": 80, 49 | "semi": true, 50 | "singleQuote": true, 51 | "trailingComma": "es5" 52 | }, 53 | "author": "William Chen", 54 | "module": "dist/cwsc.esm.js", 55 | "oclif": { 56 | "bin": "cwsc", 57 | "dirname": "cwsc", 58 | "commands": "./dist/cli/commands", 59 | "plugins": [ 60 | "@oclif/plugin-help", 61 | "@oclif/plugin-autocomplete" 62 | ], 63 | "topicSeparator": " ", 64 | "topics": {} 65 | }, 66 | "devDependencies": { 67 | "@size-limit/preset-small-lib": "^7.0.8", 68 | "@swc/cli": "^0.1.62", 69 | "@swc/core": "^1.3.55", 70 | "@swc/jest": "^0.2.26", 71 | "@types/chalk": "^2.2.0", 72 | "@types/cytoscape": "^3.19.4", 73 | "@types/cytoscape-dagre": "^2.3.0", 74 | "@types/ejs": "^3.1.0", 75 | "@types/fs-extra": "^11.0.1", 76 | "@types/jest": "^27.5.0", 77 | "@types/lodash": "^4.14.178", 78 | "@types/omelette": "^0.4.2", 79 | "@types/plist": "^3.0.2", 80 | "antlr4ts-cli": "^0.5.0-alpha.4", 81 | "eslint": "^8.12.0", 82 | "husky": "^7.0.4", 83 | "jest": "^29.5.0", 84 | "oclif": "^3", 85 | "path-browserify": "^1.0.1", 86 | "plist": "^3.0.6", 87 | "prettier": "^2.6.1", 88 | "shx": "^0.3.4", 89 | "size-limit": "^7.0.8", 90 | "swc-loader": "^0.2.3", 91 | "terser-webpack-plugin": "4", 92 | "tmlanguage-generator": "^0.4.0", 93 | "ts-loader": "^9.2.8", 94 | "ts-node": "^10.5.0", 95 | "tsconfig-paths-webpack-plugin": "^3.5.2", 96 | "tslib": "^2.3.1", 97 | "typedoc": "^0.22.13", 98 | "typescript": "^4.6.4", 99 | "typescript-call-graph": "^0.0.3", 100 | "webpack": "5.76.0", 101 | "webpack-cli": "^4.9.2" 102 | }, 103 | "dependencies": { 104 | "@oclif/core": "^2", 105 | "@oclif/plugin-autocomplete": "^2.1.9", 106 | "@oclif/plugin-help": "^5", 107 | "antlr4ts": "^0.5.0-alpha.4", 108 | "assert": "^2.0.0", 109 | "buffer": "^6.0.3", 110 | "chalk": "4.1.2", 111 | "commander": "^9.0.0", 112 | "ejs": "^3.1.6", 113 | "fs-extra": "^11.1.1", 114 | "immutable": "^4.0.0", 115 | "listr": "^0.14.3", 116 | "lodash": "^4.17.21", 117 | "omelette": "^0.4.17", 118 | "process": "^0.11.10", 119 | "source-map": "^0.7.3", 120 | "stream-browserify": "^3.0.0", 121 | "toml": "^3.0.0", 122 | "ts-results": "^3.3.0", 123 | "vscode-languageserver": "^8.1.0", 124 | "winston": "^3.8.2", 125 | "yaml": "^1.10.2" 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /dist/util/result.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.DgnsResult = exports.CWSValidationError = void 0; 4 | const ts_results_1 = require("ts-results"); 5 | class CWSValidationError extends Error { 6 | constructor(diagnostics) { 7 | super(); 8 | this.diagnostics = diagnostics; 9 | } 10 | } 11 | exports.CWSValidationError = CWSValidationError; 12 | class DgnsResult { 13 | constructor(res, diagnostics) { 14 | this.res = res; 15 | this.diagnostics = diagnostics; 16 | this.flatMap = this.andThen; 17 | } 18 | static Ok(res, diagnostics) { 19 | return new DgnsResult((0, ts_results_1.Ok)(res), diagnostics); 20 | } 21 | static Err(err, diagnostics) { 22 | return new DgnsResult((0, ts_results_1.Err)(err), diagnostics); 23 | } 24 | isOk() { 25 | return this.res.ok; 26 | } 27 | isErr() { 28 | return this.res.err; 29 | } 30 | map(f) { 31 | if (this.isOk()) { 32 | let x = f(this.res.val, this.diagnostics); 33 | let d = x instanceof DgnsResult ? x.diagnostics : []; 34 | return DgnsResult.Ok(x, [...this.diagnostics, ...d]); 35 | } 36 | else { 37 | return DgnsResult.Err(this.res.val, this.diagnostics); 38 | } 39 | } 40 | mapErr(f) { 41 | if (this.isErr()) { 42 | let x = f(this.res.val, this.diagnostics); 43 | let d = x instanceof DgnsResult ? x.diagnostics : []; 44 | return DgnsResult.Err(f(this.res.val, this.diagnostics), [ 45 | ...this.diagnostics, 46 | ...d, 47 | ]); 48 | } 49 | else { 50 | return DgnsResult.Ok(this.res.val, this.diagnostics); 51 | } 52 | } 53 | andThen(f) { 54 | if (this.isOk()) { 55 | let x = f(this.res.val, this.diagnostics); 56 | if (x instanceof DgnsResult) { 57 | return new DgnsResult(x.res, [...this.diagnostics, ...x.diagnostics]); 58 | } 59 | } 60 | return DgnsResult.Err(this.res.val, this.diagnostics); 61 | } 62 | unwrap() { 63 | return this.res.unwrap(); 64 | } 65 | static all(results) { 66 | let res = []; 67 | let err; 68 | let diagnostics = []; 69 | let hasErr = false; 70 | for (let result of results) { 71 | diagnostics = [...diagnostics, ...result.diagnostics]; 72 | if (result.isOk() && !hasErr) { 73 | res.push(result.res.val); 74 | } 75 | else { 76 | if (!hasErr) { 77 | err = result.res.val; 78 | } 79 | hasErr = true; 80 | } 81 | } 82 | if (hasErr) { 83 | return DgnsResult.Err(err, diagnostics); 84 | } 85 | else { 86 | return DgnsResult.Ok(res, diagnostics); 87 | } 88 | } 89 | static allOk(results) { 90 | let res = []; 91 | let diagnostics = []; 92 | for (let result of results) { 93 | res.push(result.res.val); 94 | diagnostics = [...diagnostics, ...result.diagnostics]; 95 | } 96 | return DgnsResult.Ok(res, diagnostics); 97 | } 98 | static allErr(results) { 99 | let diagnostics = []; 100 | for (let result of results) { 101 | diagnostics = [...diagnostics, ...result.diagnostics]; 102 | } 103 | return DgnsResult.Err(results[0].res.val, diagnostics); 104 | } 105 | catchErr(errC, f) { 106 | if (this.isErr() && this.res.val instanceof errC) { 107 | let x = f(this.res.val, this.diagnostics); 108 | let d = x instanceof DgnsResult ? x.diagnostics : []; 109 | return new DgnsResult(x.res, [...this.diagnostics, ...d]); 110 | } 111 | else { 112 | return new DgnsResult(this.res, this.diagnostics); 113 | } 114 | } 115 | } 116 | exports.DgnsResult = DgnsResult; 117 | //# sourceMappingURL=result.js.map -------------------------------------------------------------------------------- /dist/util/position.d.ts: -------------------------------------------------------------------------------- 1 | import { ParserRuleContext } from 'antlr4ts'; 2 | import { LinesAndColumns } from 'lines-and-columns'; 3 | export declare class TextView { 4 | text: string; 5 | lc: LinesAndColumns; 6 | textLines: string[]; 7 | constructor(text: string); 8 | /** 9 | * Returns the character at the given line and character. 10 | * If char is undefined, returns the entire line. 11 | * If oneIndexed is true, line and char are 1-indexed. 12 | * @param line 13 | * @param char 14 | * @param oneIndexed 15 | */ 16 | at(line: number, char?: number, oneIndexed?: boolean): string; 17 | /** 18 | * Returns the text in the given range. 19 | * If oneIndexed is true, line and char in the Range are 1-indexed. 20 | * @param range 21 | * @param oneIndexed 22 | */ 23 | textInRange(range: Range, oneIndexed?: boolean): string | null; 24 | /** 25 | * Returns the lines in the given range. 26 | * If oneIndexed is true, `startLine` and `endLine` are 1-indexed. 27 | * By default, it expects 0-indexed line numbers. 28 | * @param startLine 29 | * @param endLine 30 | * @param oneIndexed 31 | */ 32 | lines(startLine: number, endLine: number, oneIndexed?: boolean): string[]; 33 | /** 34 | * Returns the lines surrounding the given line. 35 | * If oneIndexed is true, `line` is 1-indexed. 36 | * By default, it expects 0-indexed line numbers. 37 | * 38 | * @param line Line number to get surrounding lines for. 39 | * @param numLines Number of lines to return on either side of the given line. 40 | * @param oneIndexed Whether the given line number is 1-indexed or 0-indexed. 41 | */ 42 | surroundingLines(line: number, numLines: number, oneIndexed?: boolean): { 43 | text: string; 44 | line: number; 45 | }[]; 46 | /** 47 | * Returns the lines surrounding the given range. 48 | * If oneIndexed is true, `startLine` and `endLine` are 1-indexed. 49 | * By default, it expects 0-indexed line numbers. 50 | * @param range 51 | * @param numLines 52 | * @param oneIndexed 53 | */ 54 | surroundingLinesOfRange(range: Range, numLines: number, oneIndexed?: boolean): { 55 | text: string; 56 | line: number; 57 | }[]; 58 | /** 59 | * Returns the text surrounding the given line. 60 | * If oneIndexed is true, `line` is 1-indexed. 61 | * By default, it expects 0-indexed line numbers. 62 | * @param line 63 | * @param numLines 64 | * @param oneIndexed 65 | */ 66 | surroundingText(line: number, numLines: number, oneIndexed?: boolean): string; 67 | /** 68 | * Returns the line and character for the given index. 69 | * By default, the line and character returned are 0-indexed unless specified 70 | * by the `makeOneIndexed` parameter. 71 | * 72 | * @param ix 73 | * @param makeOneIndexed Whether the returned line and character should be 1-indexed or 0-indexed. 74 | */ 75 | lcAtIndex(ix: number, makeOneIndexed?: boolean): [number, number] | null; 76 | /** 77 | * Returns the Range object for the given indices of start and 78 | * end. Note that the end index is inclusive. 79 | * 80 | * @param start The start index 81 | * @param end The end index 82 | * @param makeOneIndexed Whether the returned Range should be 1-indexed or 0-indexed. 83 | * @returns The Range object, or null if the indices are invalid. 84 | */ 85 | range(start: number, end: number, makeOneIndexed?: boolean): Range | null; 86 | rangeOfNode(ctx: ParserRuleContext): Range | null; 87 | } 88 | export declare function getIx(ctx: ParserRuleContext): TextIndices; 89 | /** 90 | * Returns the start and end indices of the given node. 91 | */ 92 | export interface TextIndices { 93 | start: number; 94 | end: number; 95 | } 96 | /** 97 | * Compatible with LSP's Range object -- 0-indexed. 98 | */ 99 | export interface Range { 100 | start: { 101 | line: number; 102 | character: number; 103 | }; 104 | end: { 105 | line: number; 106 | character: number; 107 | }; 108 | } 109 | -------------------------------------------------------------------------------- /dist/util/position.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"position.js","sourceRoot":"","sources":["../../src/util/position.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /src/util/result.ts: -------------------------------------------------------------------------------- 1 | import { Diagnostic } from 'vscode-languageserver'; 2 | import { 3 | Result, 4 | Ok, 5 | Err, 6 | Option, 7 | Some, 8 | None, 9 | ResultOkType, 10 | ResultErrType, 11 | } from 'ts-results'; 12 | 13 | export type DgnsOk = DgnsResult>; 14 | export type DgnsErr = DgnsResult>; 15 | 16 | export class CWSValidationError extends Error { 17 | constructor(public diagnostics: Diagnostic[]) { 18 | super(); 19 | } 20 | } 21 | 22 | export class DgnsResult = Result> { 23 | constructor(public res: R, public diagnostics: Diagnostic[]) {} 24 | 25 | static Ok(res: T, diagnostics: Diagnostic[]): DgnsOk { 26 | return new DgnsResult(Ok(res), diagnostics) as DgnsOk; 27 | } 28 | 29 | static Err(err: E, diagnostics: Diagnostic[]): DgnsErr { 30 | return new DgnsResult(Err(err), diagnostics) as DgnsErr; 31 | } 32 | 33 | isOk(): this is DgnsOk { 34 | return this.res.ok; 35 | } 36 | 37 | isErr(): this is DgnsErr { 38 | return this.res.err; 39 | } 40 | 41 | map(f: (t: T, d: Diagnostic[]) => U): DgnsResult { 42 | if (this.isOk()) { 43 | let x = f(this.res.val, this.diagnostics); 44 | let d = x instanceof DgnsResult ? x.diagnostics : []; 45 | return DgnsResult.Ok(x, [...this.diagnostics, ...d]); 46 | } else { 47 | return DgnsResult.Err(this.res.val as E, this.diagnostics); 48 | } 49 | } 50 | 51 | mapErr(f: (e: E, d: Diagnostic[]) => U): DgnsResult { 52 | if (this.isErr()) { 53 | let x = f(this.res.val, this.diagnostics); 54 | let d = x instanceof DgnsResult ? x.diagnostics : []; 55 | return DgnsResult.Err(f(this.res.val, this.diagnostics), [ 56 | ...this.diagnostics, 57 | ...d, 58 | ]); 59 | } else { 60 | return DgnsResult.Ok(this.res.val as T, this.diagnostics); 61 | } 62 | } 63 | 64 | public flatMap = this.andThen; 65 | 66 | andThen(f: (r: T, d: Diagnostic[]) => DgnsResult): DgnsResult { 67 | if (this.isOk()) { 68 | let x = f(this.res.val, this.diagnostics); 69 | if (x instanceof DgnsResult) { 70 | return new DgnsResult(x.res, [...this.diagnostics, ...x.diagnostics]); 71 | } 72 | } 73 | return DgnsResult.Err(this.res.val as E, this.diagnostics); 74 | } 75 | 76 | unwrap(): T { 77 | return this.res.unwrap(); 78 | } 79 | 80 | static all(results: DgnsResult[]): DgnsResult { 81 | let res: T[] = []; 82 | let err: E; 83 | let diagnostics: Diagnostic[] = []; 84 | let hasErr = false; 85 | for (let result of results) { 86 | diagnostics = [...diagnostics, ...result.diagnostics]; 87 | if (result.isOk() && !hasErr) { 88 | res.push(result.res.val); 89 | } else { 90 | if (!hasErr) { 91 | err = result.res.val as E; 92 | } 93 | hasErr = true; 94 | } 95 | } 96 | if (hasErr) { 97 | return DgnsResult.Err(err!, diagnostics); 98 | } else { 99 | return DgnsResult.Ok(res, diagnostics); 100 | } 101 | } 102 | 103 | static allOk(results: DgnsOk[]): DgnsOk { 104 | let res: T[] = []; 105 | let diagnostics: Diagnostic[] = []; 106 | for (let result of results) { 107 | res.push(result.res.val); 108 | diagnostics = [...diagnostics, ...result.diagnostics]; 109 | } 110 | return DgnsResult.Ok(res, diagnostics); 111 | } 112 | 113 | static allErr(results: DgnsErr[]): DgnsErr { 114 | let diagnostics: Diagnostic[] = []; 115 | for (let result of results) { 116 | diagnostics = [...diagnostics, ...result.diagnostics]; 117 | } 118 | return DgnsResult.Err(results[0].res.val as E, diagnostics); 119 | } 120 | 121 | catchErr( 122 | errC: new (...args: any[]) => F, 123 | f: (e: F, d: Diagnostic[]) => DgnsResult 124 | ): DgnsResult { 125 | if (this.isErr() && this.res.val instanceof errC) { 126 | let x = f(this.res.val, this.diagnostics); 127 | let d = x instanceof DgnsResult ? x.diagnostics : []; 128 | return new DgnsResult(x.res, [...this.diagnostics, ...d]); 129 | } else { 130 | return new DgnsResult(this.res, this.diagnostics); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /dist/grammar/CWScriptLexer.d.ts: -------------------------------------------------------------------------------- 1 | import { ATN } from "antlr4ts/atn/ATN"; 2 | import { CharStream } from "antlr4ts/CharStream"; 3 | import { Lexer } from "antlr4ts/Lexer"; 4 | import { Vocabulary } from "antlr4ts/Vocabulary"; 5 | export declare class CWScriptLexer extends Lexer { 6 | static readonly DEBUG = 1; 7 | static readonly CONTRACT = 2; 8 | static readonly INTERFACE = 3; 9 | static readonly IMPORT = 4; 10 | static readonly IMPLEMENTS = 5; 11 | static readonly EXTENDS = 6; 12 | static readonly ERROR = 7; 13 | static readonly EVENT = 8; 14 | static readonly DEFER = 9; 15 | static readonly INSTANTIATE_NOW = 10; 16 | static readonly EXEC_NOW = 11; 17 | static readonly QUERY_NOW = 12; 18 | static readonly DELEGATE_EXEC = 13; 19 | static readonly INSTANTIATE = 14; 20 | static readonly EXEC = 15; 21 | static readonly QUERY = 16; 22 | static readonly REPLY = 17; 23 | static readonly FOR = 18; 24 | static readonly IN = 19; 25 | static readonly FROM = 20; 26 | static readonly STATE = 21; 27 | static readonly IF = 22; 28 | static readonly IS = 23; 29 | static readonly TRY = 24; 30 | static readonly CATCH = 25; 31 | static readonly ELSE = 26; 32 | static readonly NOT = 27; 33 | static readonly NONE = 28; 34 | static readonly MUT = 29; 35 | static readonly AND = 30; 36 | static readonly OR = 31; 37 | static readonly TRUE = 32; 38 | static readonly FALSE = 33; 39 | static readonly FN = 34; 40 | static readonly LET = 35; 41 | static readonly CONST = 36; 42 | static readonly FAIL = 37; 43 | static readonly RETURN = 38; 44 | static readonly STRUCT = 39; 45 | static readonly ENUM = 40; 46 | static readonly TYPE = 41; 47 | static readonly EMIT = 42; 48 | static readonly AS = 43; 49 | static readonly TILDE = 44; 50 | static readonly LPAREN = 45; 51 | static readonly RPAREN = 46; 52 | static readonly LBRACK = 47; 53 | static readonly RBRACK = 48; 54 | static readonly LBRACE = 49; 55 | static readonly RBRACE = 50; 56 | static readonly DOT = 51; 57 | static readonly COMMA = 52; 58 | static readonly D_QUEST = 53; 59 | static readonly QUEST = 54; 60 | static readonly BANG = 55; 61 | static readonly SEMI = 56; 62 | static readonly COLON = 57; 63 | static readonly D_COLON = 58; 64 | static readonly HASH = 59; 65 | static readonly AT = 60; 66 | static readonly AMP = 61; 67 | static readonly ARROW = 62; 68 | static readonly FAT_ARROW = 63; 69 | static readonly BAR = 64; 70 | static readonly S_QUOTE = 65; 71 | static readonly D_QUOTE = 66; 72 | static readonly EQ = 67; 73 | static readonly EQ_EQ = 68; 74 | static readonly NEQ = 69; 75 | static readonly PLUS = 70; 76 | static readonly PLUS_EQ = 71; 77 | static readonly MINUS = 72; 78 | static readonly MINUS_EQ = 73; 79 | static readonly MUL = 74; 80 | static readonly MUL_EQ = 75; 81 | static readonly DIV = 76; 82 | static readonly DIV_EQ = 77; 83 | static readonly MOD = 78; 84 | static readonly MOD_EQ = 79; 85 | static readonly LT = 80; 86 | static readonly LT_EQ = 81; 87 | static readonly GT = 82; 88 | static readonly GT_EQ = 83; 89 | static readonly POW = 84; 90 | static readonly Ident = 85; 91 | static readonly StringLiteral = 86; 92 | static readonly IntLiteral = 87; 93 | static readonly DecLiteral = 88; 94 | static readonly BoolLiteral = 89; 95 | static readonly CWSPEC_LINE_COMMENT = 90; 96 | static readonly CWSPEC_BLOCK_COMMENT = 91; 97 | static readonly LINE_COMMENT = 92; 98 | static readonly BLOCK_COMMENT = 93; 99 | static readonly WS = 94; 100 | static readonly channelNames: string[]; 101 | static readonly modeNames: string[]; 102 | static readonly ruleNames: string[]; 103 | private static readonly _LITERAL_NAMES; 104 | private static readonly _SYMBOLIC_NAMES; 105 | static readonly VOCABULARY: Vocabulary; 106 | get vocabulary(): Vocabulary; 107 | constructor(input: CharStream); 108 | get grammarFileName(): string; 109 | get ruleNames(): string[]; 110 | get serializedATN(): string; 111 | get channelNames(): string[]; 112 | get modeNames(): string[]; 113 | private static readonly _serializedATNSegments; 114 | private static readonly _serializedATNSegment0; 115 | private static readonly _serializedATNSegment1; 116 | static readonly _serializedATN: string; 117 | static __ATN: ATN; 118 | static get _ATN(): ATN; 119 | } 120 | -------------------------------------------------------------------------------- /examples/terraswap/TerraswapFactory.cws: -------------------------------------------------------------------------------- 1 | import * from "./common.cws" 2 | 3 | contract TerraswapFactory { 4 | 5 | error Unauthorized() 6 | event UpdateConfig() 7 | 8 | state { 9 | config: Config // since these are not option, we will type-check these... 10 | tmp_pair_info: TmpPairInfo 11 | pairs[U8]: PairInfo? = None 12 | allow_native_tokens[U8[2]]: U8? = None 13 | } 14 | 15 | fn query_decimals!(account_addr: address, asset_info: AssetInfo) -> U8 { 16 | if asset_info is AssetInfo.#Token { 17 | let { contract_addr } = asset_info 18 | let token_info = query! CW20(asset_info).#token_info() 19 | return token_info.decimals 20 | } else { 21 | // asset_info is AssetInfo::NativeToken 22 | // this does a self-query 23 | let res = query! $.#native_token_decimals(asset_info.denom) 24 | return res.decimals 25 | } 26 | } 27 | 28 | // #1. how do we let users pass context around ($) 29 | // #2. how can we make it obvious that instantiate is not a function that the user can call 30 | #instantiate(pair_code_id: U64, token_code_id: U64) { 31 | $state.config = Config(token_code_id, pair_code_id, $info.sender) 32 | } 33 | 34 | exec #update_config(owner?: String, token_code_id?: U64, pair_code_id?: U64) { 35 | if $info.sender != $state.config.owner { 36 | fail! Unauthorized() 37 | } 38 | 39 | // auto-unwraps if safe 40 | if owner? { 41 | $state.config.owner = Address.validate!(owner) 42 | } 43 | 44 | if token_code_id? { 45 | $state.token_code_id = token_code_id 46 | } 47 | 48 | if pair_code_id? { 49 | $state.pair_code_id = pair_code_id 50 | } 51 | 52 | emit UpdateConfig() 53 | } 54 | 55 | reply.success post_instantiate() { 56 | let { tmp_pair_info } = $state 57 | // parse_response! 58 | // the parse_response!() function expects the context variable "$" 59 | let response = Wasm.Instantiate::parse_response!($data) 60 | let pair_contract = response.address 61 | let pair_info = query! TerraswapPair(pair_contract).#pair() ~ .token_supply 62 | $state.pairs = PairInfo( 63 | Address.Canonical!(pair_info.liquidity_token), 64 | Address.Canonical!(pair_info.liquidity_token), 65 | asset_infos=tmp_pair_info.asset_infos, 66 | asset_decimals=tmp_pair_info.asset_decimals 67 | ) 68 | emit PostInstantiate(pair_contract, pair_info.liquidity_token) 69 | } 70 | 71 | exec #create_pair(asset_infos: AssetInfo[2]) { 72 | if asset_infos[0] == asset_infos[1] { 73 | fail! "same asset" 74 | } 75 | 76 | let asset_1_decimal = query_decimals!($env.contract.address, asset_infos[0]) 77 | let asset_2_decimal = query_decimals!($env.contract.address, asset_infos[1]) 78 | let asset_decimals = [asset_1_decimal, asset_2_decimal] 79 | 80 | let pair_key = String!(asset_infos[0]) + String!(asset_infos[1]) 81 | 82 | // $state::pairs::has_key(pair_key) 83 | // optimization: check if key is there 84 | if pair_key in $state.pairs { 85 | fail! "Pair already exists" 86 | } 87 | 88 | $state.tmp_pair_info = TmpPairInfo { pair_key, asset_infos, asset_decimals } 89 | emit CreatePair(asset_infos[0], asset_infos[1]) 90 | 91 | @gas_limit(5000000) 92 | @reply.on_success(post_instantiate) 93 | instantiate! #TerraswapPair(asset_infos, $state.config.token_code_id, asset_decimals) { 94 | code_id: $state.config.pair_code_id, 95 | admin: $env.contract.address, 96 | label: "pair" 97 | } 98 | } 99 | 100 | exec #add_native_token_decimals(denom: String, decimals: U8) { 101 | if $info.sender != $state.config.owner { 102 | fail! Unauthorized() 103 | } 104 | 105 | let balance = query! Bank.#balance($env.contract.address, denom) 106 | 107 | if balance.amount == 0 { 108 | fail! "A balance greater than zero is required by the factory for verification" 109 | } 110 | 111 | $state.allow_native_tokens[denom] = decimals 112 | emit AddAllowNativeToken(denom, decimals) 113 | } 114 | 115 | query #config() { 116 | return $state.config 117 | } 118 | 119 | query #pair(asset_infos: AssetInfo[2]) { 120 | let pairs = $state.pairs[asset_infos] 121 | return { pairs } // type is inferred 122 | // intuition is, if you're too lazy to name it and define it, 123 | // it probably can be referred to as just the response type of query 124 | } 125 | 126 | query #native_token_decimal(denom: String) { 127 | let decimals = $state.allow_native_tokens[denom] 128 | return { decimals } 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /dist/cli/BaseCommand.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | Object.defineProperty(exports, "__esModule", { value: true }); 26 | exports.BaseCommand = exports.ConfigKV = void 0; 27 | const core_1 = require("@oclif/core"); 28 | const fs = __importStar(require("fs-extra")); 29 | const path = __importStar(require("path")); 30 | class ConfigKV { 31 | constructor(key, value) { 32 | this.key = key; 33 | this.value = value; 34 | } 35 | } 36 | exports.ConfigKV = ConfigKV; 37 | class BaseCommand extends core_1.Command { 38 | async loadConfig() { 39 | const userConfig = await fs.readJSON(path.join(this.config.configDir, 'cwsconfig.json')); 40 | this.log('User config:'); 41 | console.dir(userConfig); 42 | } 43 | async init() { 44 | await super.init(); 45 | const { args, flags } = await this.parse({ 46 | flags: this.ctor.flags, 47 | baseFlags: super.ctor.baseFlags, 48 | args: this.ctor.args, 49 | strict: this.ctor.strict, 50 | }); 51 | this.flags = flags; 52 | this.args = args; 53 | } 54 | async catch(err) { 55 | // add any custom logic to handle errors from the command 56 | // or simply return the parent class error handling 57 | return super.catch(err); 58 | } 59 | async finally(_) { 60 | // called after run and catch regardless of whether or not the command errored 61 | return super.finally(_); 62 | } 63 | } 64 | exports.BaseCommand = BaseCommand; 65 | BaseCommand.baseFlags = { 66 | verbose: core_1.Flags.boolean({ 67 | char: 'V', 68 | description: 'Show verbose output - turns on all logs and diagnostics.', 69 | default: false, 70 | }), 71 | silent: core_1.Flags.boolean({ 72 | char: 'Q', 73 | description: 'Show no output', 74 | default: false, 75 | aliases: ['quiet'], 76 | exclusive: ['verbose'], 77 | }), 78 | 'show-hints': core_1.Flags.boolean({ 79 | description: 'Show CWScript "hint" and "info" diagnostics when parsing.', 80 | default: false, 81 | exclusive: ['silent'], 82 | }), 83 | 'show-warnings': core_1.Flags.boolean({ 84 | description: 'Show CWScript "warning" diagnostics when parsing.', 85 | default: true, 86 | exclusive: ['silent'], 87 | }), 88 | logs: core_1.Flags.string({ 89 | description: 'Show compiler tool logs above a certain level', 90 | options: ['NONE', 'INFO', 'DEBUG', 'WARNING', 'ERROR'], 91 | default: ['ERROR'], 92 | exclusive: ['silent'], 93 | }), 94 | 'log-file': core_1.Flags.file({ 95 | description: 'Write logs to a file', 96 | env: 'CWSC_LOG_FILE', 97 | dependsOn: ['logs'], 98 | }), 99 | 'project-dir': core_1.Flags.directory({ 100 | char: 'D', 101 | description: 'Specify a directory containing a `cwsproject.toml` file to run the command in a specific project.', 102 | exclusive: ['project-config', 'project-dir'], 103 | env: 'CWS_PROJECT_DIR', 104 | }), 105 | cwsconfig: core_1.Flags.file({ 106 | char: 'C', 107 | description: 'Specify a path to `cwsconfig.toml` to use base compiler tool settings.', 108 | env: 'CWS_CONFIG', 109 | }), 110 | // set: Flags.custom({ 111 | // multiple: true, 112 | // description: `Set a config value temporarily for this command. This flag can be used multiple times to set multiple values.`, 113 | // helpLabel: '-Xset=value', 114 | // parse: async (input: string) => { 115 | // const [key, value] = input.split('='); 116 | // return new ConfigKV(key, value); 117 | // }, 118 | // })(), 119 | }; 120 | //# sourceMappingURL=BaseCommand.js.map -------------------------------------------------------------------------------- /dist/parser/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.CWSParser = exports.CheckSymbolsDeclaredBeforeUse = exports.CWSSyntaxErrorListener = exports.CWSDiagnosticsCollector = void 0; 7 | // @ts-nocheck 8 | const antlr4ts_1 = require("antlr4ts"); 9 | const CWScriptLexer_1 = require("../grammar/CWScriptLexer"); 10 | const CWScriptParser_1 = require("../grammar/CWScriptParser"); 11 | const visitor_1 = require("./visitor"); 12 | const position_1 = require("../util/position"); 13 | const vscode_languageserver_1 = require("vscode-languageserver"); 14 | const path_1 = __importDefault(require("path")); 15 | class CWSDiagnosticsCollector { 16 | constructor() { 17 | this.diagnostics = []; 18 | } 19 | get errors() { 20 | return this.diagnostics.filter((d) => d.severity === vscode_languageserver_1.DiagnosticSeverity.Error); 21 | } 22 | get warnings() { 23 | return this.diagnostics.filter((d) => d.severity === vscode_languageserver_1.DiagnosticSeverity.Warning); 24 | } 25 | get infos() { 26 | return this.diagnostics.filter((d) => d.severity === vscode_languageserver_1.DiagnosticSeverity.Information); 27 | } 28 | get hints() { 29 | return this.diagnostics.filter((d) => d.severity === vscode_languageserver_1.DiagnosticSeverity.Hint); 30 | } 31 | } 32 | exports.CWSDiagnosticsCollector = CWSDiagnosticsCollector; 33 | class CWSSyntaxErrorListener { 34 | constructor(parser) { 35 | this.parser = parser; 36 | } 37 | syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) { 38 | this.parser.diagnostics.push({ 39 | severity: vscode_languageserver_1.DiagnosticSeverity.Error, 40 | message: 'SyntaxError: ' + msg, 41 | range: { 42 | start: { line: line - 1, character: charPositionInLine }, 43 | end: { line: line - 1, character: charPositionInLine + 1 }, 44 | }, 45 | }); 46 | } 47 | } 48 | exports.CWSSyntaxErrorListener = CWSSyntaxErrorListener; 49 | class CheckSymbolsDeclaredBeforeUse { 50 | get scope() { 51 | return this.scopes[this.scopes.length - 1]; 52 | } 53 | constructor(parser) { 54 | this.parser = parser; 55 | this.scopes = [{}]; 56 | } 57 | enterIdentExpr(ctx) { 58 | if (!this.scope[ctx.ident().text]) { 59 | this.parser.diagnostics.push({ 60 | message: `Symbol '${ctx.ident().text}' is not declared`, 61 | range: this.env.sourceText.rangeFromNodeCtx(ctx), 62 | severity: vscode_languageserver_1.DiagnosticSeverity.Error, 63 | }); 64 | } 65 | } 66 | // definitions below 67 | enterIdentBinding_(ctx) { 68 | this.scope[ctx._name.text] = ''; 69 | } 70 | enterImportItemsStmt(ctx) { 71 | ctx._items.forEach((sym) => { 72 | this.scope[sym.text] = ''; 73 | }); 74 | } 75 | enterParam(ctx) { 76 | this.scope[ctx._name.text] = ''; 77 | } 78 | enterInstantiateDefn(ctx) { 79 | this.scope[ctx._name.text] = ''; 80 | } 81 | enterFnDefn(ctx) { 82 | if (ctx._name) { 83 | this.scope[ctx._name.text] = ''; 84 | } 85 | } 86 | enterStructDefn(ctx) { 87 | if (ctx._name) { 88 | this.scope[ctx._name.text] = ''; 89 | } 90 | } 91 | enterEnumDefn(ctx) { 92 | if (ctx._name) { 93 | this.scope[ctx._name.text] = ''; 94 | } 95 | } 96 | } 97 | exports.CheckSymbolsDeclaredBeforeUse = CheckSymbolsDeclaredBeforeUse; 98 | class CWSParser extends CWSDiagnosticsCollector { 99 | constructor(sourceInput, sourceFile = null) { 100 | super(); 101 | this.sourceInput = sourceInput; 102 | this.sourceText = new position_1.TextView(sourceInput); 103 | this.sourceFile = sourceFile ? path_1.default.resolve(sourceFile) : null; 104 | } 105 | /** 106 | * This is the public-facing interface for parsing a source file. 107 | */ 108 | parse() { 109 | let parseTree = this.antlrParse(); 110 | if (this.errors.length > 0) { 111 | throw new Error('Syntax error occurred while parsing.'); 112 | } 113 | // build AST 114 | let visitor = new visitor_1.CWSASTBuilderVisitor(); 115 | return visitor.visitSourceFile(parseTree); 116 | } 117 | antlrParse() { 118 | let syntaxErrorListener = new CWSSyntaxErrorListener(this); 119 | let antlrLexer = new CWScriptLexer_1.CWScriptLexer(antlr4ts_1.CharStreams.fromString(this.sourceInput)); 120 | antlrLexer.removeErrorListeners(); 121 | antlrLexer.addErrorListener(syntaxErrorListener); 122 | let antlrParser = new CWScriptParser_1.CWScriptParser(new antlr4ts_1.CommonTokenStream(antlrLexer)); 123 | antlrParser.removeErrorListeners(); 124 | antlrParser.addErrorListener(syntaxErrorListener); 125 | let tree = antlrParser.sourceFile(); 126 | return tree; 127 | } 128 | } 129 | exports.CWSParser = CWSParser; 130 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /src/parser/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import { ANTLRErrorListener, CharStreams, CommonTokenStream } from 'antlr4ts'; 3 | import { CWScriptLexer as ANTLRCWScriptLexer } from '../grammar/CWScriptLexer'; 4 | import { 5 | CWScriptParser as ANTLRCWScriptParser, 6 | SourceFileContext, 7 | } from '../grammar/CWScriptParser'; 8 | import { CWSASTBuilderVisitor } from './visitor'; 9 | import * as AST from '../ast'; 10 | import { TextView } from '../util/position'; 11 | import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver'; 12 | import { DgnsOk, DgnsResult, DgnsErr } from '../util/result'; 13 | import path from 'path'; 14 | import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'; 15 | import * as P from '../grammar/CWScriptParser'; 16 | import { CWScriptParserListener } from '../grammar/CWScriptParserListener'; 17 | import { RecognitionException } from 'antlr4ts/RecognitionException'; 18 | 19 | export abstract class CWSDiagnosticsCollector { 20 | public diagnostics: Diagnostic[] = []; 21 | 22 | public get errors(): Diagnostic[] { 23 | return this.diagnostics.filter( 24 | (d) => d.severity === DiagnosticSeverity.Error 25 | ); 26 | } 27 | 28 | public get warnings(): Diagnostic[] { 29 | return this.diagnostics.filter( 30 | (d) => d.severity === DiagnosticSeverity.Warning 31 | ); 32 | } 33 | 34 | public get infos(): Diagnostic[] { 35 | return this.diagnostics.filter( 36 | (d) => d.severity === DiagnosticSeverity.Information 37 | ); 38 | } 39 | 40 | public get hints(): Diagnostic[] { 41 | return this.diagnostics.filter( 42 | (d) => d.severity === DiagnosticSeverity.Hint 43 | ); 44 | } 45 | } 46 | 47 | export class CWSSyntaxErrorListener implements ANTLRErrorListener { 48 | constructor(public parser: CWSParser) {} 49 | 50 | syntaxError( 51 | recognizer: any, 52 | offendingSymbol: any, 53 | line: number, 54 | charPositionInLine: number, 55 | msg: string, 56 | e: RecognitionException | undefined 57 | ) { 58 | this.parser.diagnostics.push({ 59 | severity: DiagnosticSeverity.Error, 60 | message: 'SyntaxError: ' + msg, 61 | range: { 62 | start: { line: line - 1, character: charPositionInLine }, 63 | end: { line: line - 1, character: charPositionInLine + 1 }, 64 | }, 65 | }); 66 | } 67 | } 68 | 69 | export class CheckSymbolsDeclaredBeforeUse implements CWScriptParserListener { 70 | public scopes: any = [{}]; 71 | 72 | get scope() { 73 | return this.scopes[this.scopes.length - 1]; 74 | } 75 | 76 | constructor(public parser: CWSParser) {} 77 | 78 | enterIdentExpr(ctx: P.IdentExprContext) { 79 | if (!this.scope[ctx.ident().text]) { 80 | this.parser.diagnostics.push({ 81 | message: `Symbol '${ctx.ident().text}' is not declared`, 82 | range: this.env.sourceText.rangeFromNodeCtx(ctx), 83 | severity: DiagnosticSeverity.Error, 84 | }); 85 | } 86 | } 87 | 88 | // definitions below 89 | enterIdentBinding_(ctx: P.IdentBinding_Context) { 90 | this.scope[ctx._name.text] = ''; 91 | } 92 | 93 | enterImportItemsStmt(ctx: P.ImportItemsStmtContext) { 94 | ctx._items.forEach((sym) => { 95 | this.scope[sym.text] = ''; 96 | }); 97 | } 98 | 99 | enterParam(ctx: P.ParamContext) { 100 | this.scope[ctx._name.text] = ''; 101 | } 102 | 103 | enterInstantiateDefn(ctx: P.InstantiateDefnContext) { 104 | this.scope[ctx._name.text] = ''; 105 | } 106 | 107 | enterFnDefn(ctx: P.FnDefnContext) { 108 | if (ctx._name) { 109 | this.scope[ctx._name.text] = ''; 110 | } 111 | } 112 | 113 | enterStructDefn(ctx: P.StructDefnContext) { 114 | if (ctx._name) { 115 | this.scope[ctx._name.text] = ''; 116 | } 117 | } 118 | 119 | enterEnumDefn(ctx: P.EnumDefnContext) { 120 | if (ctx._name) { 121 | this.scope[ctx._name.text] = ''; 122 | } 123 | } 124 | } 125 | 126 | export class CWSParser extends CWSDiagnosticsCollector { 127 | constructor(public sourceInput: string, sourceFile: string | null = null) { 128 | super(); 129 | this.sourceText = new TextView(sourceInput); 130 | this.sourceFile = sourceFile ? path.resolve(sourceFile) : null; 131 | } 132 | 133 | /** 134 | * This is the public-facing interface for parsing a source file. 135 | */ 136 | public parse(): AST.SourceFile { 137 | let parseTree = this.antlrParse(); 138 | if (this.errors.length > 0) { 139 | throw new Error('Syntax error occurred while parsing.'); 140 | } 141 | 142 | // build AST 143 | let visitor = new CWSASTBuilderVisitor(); 144 | return visitor.visitSourceFile(parseTree); 145 | } 146 | 147 | protected antlrParse(): SourceFileContext { 148 | let syntaxErrorListener = new CWSSyntaxErrorListener(this); 149 | let antlrLexer = new ANTLRCWScriptLexer( 150 | CharStreams.fromString(this.sourceInput) 151 | ); 152 | antlrLexer.removeErrorListeners(); 153 | antlrLexer.addErrorListener(syntaxErrorListener); 154 | let antlrParser = new ANTLRCWScriptParser( 155 | new CommonTokenStream(antlrLexer) 156 | ); 157 | antlrParser.removeErrorListeners(); 158 | antlrParser.addErrorListener(syntaxErrorListener); 159 | 160 | let tree = antlrParser.sourceFile(); 161 | return tree; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /dist/parser/visitor.d.ts: -------------------------------------------------------------------------------- 1 | import { ParserRuleContext } from 'antlr4ts'; 2 | import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'; 3 | import * as P from '../grammar/CWScriptParser'; 4 | import { CWScriptParserVisitor as ANTLRCWScriptParserVisitor } from '../grammar/CWScriptParserVisitor'; 5 | import * as AST from '../ast'; 6 | export declare class CWSASTBuilderVisitor extends AbstractParseTreeVisitor implements ANTLRCWScriptParserVisitor { 7 | visitSourceFile(ctx: P.SourceFileContext): AST.SourceFile; 8 | visitContractDefn(ctx: P.ContractDefnContext): AST.ContractDefn; 9 | visitTypePath(ctx: P.TypePathContext): AST.TypePath; 10 | visitTypeVariant(ctx: P.TypeVariantContext): AST.TypeVariant; 11 | visitTypeLens(ctx: P.TypeLensContext): AST.TypeLens; 12 | visitOptionT(ctx: P.OptionTContext): AST.OptionT; 13 | visitListT(ctx: P.ListTContext): AST.ListT | AST.TupleT; 14 | visitTupleT(ctx: P.TupleTContext): AST.TupleT; 15 | visitStructDefn(ctx: P.StructDefnContext): AST.StructDefn; 16 | visitTypeAliasDefn(ctx: P.TypeAliasDefnContext): AST.TypeAliasDefn; 17 | visitInterfaceDefn(ctx: P.InterfaceDefnContext): AST.InterfaceDefn; 18 | visitImportAllStmt(ctx: P.ImportAllStmtContext): AST.ImportAllStmt; 19 | visitImportItemsStmt(ctx: P.ImportItemsStmtContext): AST.ImportItemsStmt; 20 | visitParam(ctx: P.ParamContext): AST.Param; 21 | visitStringLit(ctx: P.StringLitContext): AST.StringLit; 22 | visitContractBlock(ctx: P.ContractBlockContext): AST.ContractBlock; 23 | visitStateDefnBlock(ctx: P.StateDefnBlockContext): AST.StateDefnBlock; 24 | visitStateDefn_Item(ctx: P.StateDefn_ItemContext): AST.StateDefnItem; 25 | visitStateDefn_Map(ctx: P.StateDefn_MapContext): AST.StateDefnMap; 26 | visitFnDefn(ctx: P.FnDefnContext): AST.FnDefn; 27 | visitFnParams(ctx: P.FnParamsContext): AST.List; 28 | visitMapKeyDefn(ctx: P.MapKeyDefnContext): AST.MapKeyDefn; 29 | visitInstantiateDefn(ctx: P.InstantiateDefnContext): AST.InstantiateDefn; 30 | visitInstantiateDecl(ctx: P.InstantiateDeclContext): AST.InstantiateDecl; 31 | visitExecDefn(ctx: P.ExecDefnContext): AST.ExecDefn; 32 | visitExecDecl(ctx: P.ExecDeclContext): AST.ExecDecl; 33 | visitQueryDefn(ctx: P.QueryDefnContext): AST.QueryDefn; 34 | visitQueryDecl(ctx: P.QueryDeclContext): AST.QueryDecl; 35 | visitErrorDefn(ctx: P.ErrorDefnContext): AST.ErrorDefn; 36 | visitStructDefn_fn(ctx: P.StructDefn_fnContext): AST.StructDefn; 37 | visitErrorDefnBlock(ctx: P.ErrorDefnBlockContext): AST.ErrorDefnBlock; 38 | visitEventDefn(ctx: P.EventDefnContext): AST.EventDefn; 39 | visitEventDefnBlock(ctx: P.EventDefnBlockContext): AST.EventDefnBlock; 40 | visitReplyDefn(ctx: P.ReplyDefnContext): AST.ReplyDefn; 41 | visitEnumDefn(ctx: P.EnumDefnContext): AST.EnumDefn; 42 | visitVariant_struct(ctx: P.Variant_structContext): AST.EnumVariantStruct; 43 | visitParamList(ctx: P.ParamListContext): AST.List; 44 | visitVariant_unit(ctx: P.Variant_unitContext): AST.EnumVariantUnit; 45 | visitDebugStmt_(ctx: P.DebugStmt_Context): AST.DebugStmt; 46 | visitDebugStmt(ctx: P.DebugStmtContext): AST.DebugStmt; 47 | visitLetStmt_(ctx: P.LetStmt_Context): AST.LetStmt; 48 | visitLetStmt(ctx: P.LetStmtContext): AST.LetStmt; 49 | visitConstStmt_(ctx: P.ConstStmt_Context): AST.ConstStmt; 50 | visitConstStmt(ctx: P.ConstStmtContext): AST.ConstStmt; 51 | visitAssignStmt_(ctx: P.AssignStmt_Context): AST.AssignStmt; 52 | visitAssignStmt(ctx: P.AssignStmtContext): AST.AssignStmt; 53 | visitIfStmt_(ctx: P.IfStmt_Context): AST.IfStmt; 54 | visitElseClause(ctx: P.ElseClauseContext): AST.Block; 55 | visitBlock(ctx: P.BlockContext): AST.Block; 56 | visitForStmt_(ctx: P.ForStmt_Context): AST.ForStmt; 57 | visitForStmt(ctx: P.ForStmtContext): AST.ForStmt; 58 | visitExecStmt(ctx: P.ExecStmtContext): AST.ExecStmt; 59 | visitDelegateExecStmt(ctx: P.DelegateExecStmtContext): AST.DelegateExecStmt; 60 | visitInstantiateStmt(ctx: P.InstantiateStmtContext): AST.InstantiateStmt; 61 | visitCallOptions(ctx: P.CallOptionsContext): AST.List; 62 | visitEmitStmt(ctx: P.EmitStmtContext): AST.EmitStmt; 63 | visitReturnStmt(ctx: P.ReturnStmtContext): AST.ReturnStmt; 64 | visitFailStmt(ctx: P.FailStmtContext): AST.FailStmt; 65 | visitExprStmt(ctx: P.ExprStmtContext): AST.Expr; 66 | visitIdentBinding_(ctx: P.IdentBinding_Context): AST.IdentBinding; 67 | visitStructBinding(ctx: P.StructBindingContext): AST.StructBinding; 68 | visitTupleBinding(ctx: P.TupleBindingContext): AST.TupleBinding; 69 | visitIdentLHS(ctx: P.IdentLHSContext): AST.IdentLHS; 70 | visitDotLHS(ctx: P.DotLHSContext): AST.DotLHS; 71 | visitIndexLHS(ctx: P.IndexLHSContext): AST.IndexLHS; 72 | visitGroupedExpr(ctx: P.GroupedExprContext): AST.GroupedExpr; 73 | visitGrouped2Expr(ctx: P.Grouped2ExprContext): AST.Grouped2Expr; 74 | visitDotExpr(ctx: P.DotExprContext): AST.DotExpr; 75 | visitAsExpr(ctx: P.AsExprContext): AST.AsExpr; 76 | visitIndexExpr(ctx: P.IndexExprContext): AST.IndexExpr; 77 | visitDColonExpr(ctx: P.DColonExprContext): AST.DColonExpr; 78 | visitTypeDColonExpr(ctx: P.TypeDColonExprContext): AST.DColonExpr; 79 | visitArg(ctx: P.ArgContext): AST.Arg; 80 | visitFnCallExpr(ctx: P.FnCallExprContext): AST.FnCallExpr; 81 | visitTypeFnCallExpr(ctx: P.TypeFnCallExprContext): AST.FnCallExpr; 82 | visitMulExpr(ctx: P.MulExprContext): AST.BinOpExpr; 83 | visitAddExpr(ctx: P.AddExprContext): AST.BinOpExpr; 84 | visitCompExpr(ctx: P.CompExprContext): AST.BinOpExpr; 85 | visitEqExpr(ctx: P.EqExprContext): AST.BinOpExpr; 86 | visitNoneCheckExpr(ctx: P.NoneCheckExprContext): AST.NoneCheckExpr; 87 | visitIsExpr(ctx: P.IsExprContext): AST.IsExpr; 88 | visitInExpr(ctx: P.InExprContext): AST.InExpr; 89 | visitShortTryExpr(ctx: P.ShortTryExprContext): AST.TryCatchElseExpr; 90 | visitTryCatchElseExpr_(ctx: P.TryCatchElseExpr_Context): AST.TryCatchElseExpr; 91 | visitCatch(ctx: P.CatchContext): AST.CatchClause; 92 | visitCatchBind(ctx: P.CatchBindContext): AST.CatchClause; 93 | visitAndExpr(ctx: P.AndExprContext): AST.AndExpr; 94 | visitOrExpr(ctx: P.OrExprContext): AST.OrExpr; 95 | visitQueryNowExpr(ctx: P.QueryNowExprContext): AST.QueryNowExpr; 96 | visitFailExpr(ctx: P.FailExprContext): AST.FailExpr; 97 | visitClosure(ctx: P.ClosureContext): AST.Closure; 98 | visitTupleExpr(ctx: P.TupleExprContext): AST.TupleExpr; 99 | visitClosureParams(ctx: P.ClosureParamsContext): AST.List; 100 | visitMemberVal(ctx: P.MemberValContext): AST.MemberVal; 101 | visitStructExpr(ctx: P.StructExprContext): AST.StructExpr; 102 | visitUnitVariantExpr(ctx: P.UnitVariantExprContext): AST.UnitVariantExpr; 103 | visitIntLit(ctx: P.IntLitContext): AST.IntLit; 104 | visitDecLit(ctx: P.DecLitContext): AST.DecLit; 105 | visitBoolLit(ctx: P.BoolLitContext): AST.BoolLit; 106 | visitNoneLit(ctx: P.NoneLitContext): AST.NoneLit; 107 | visitIdent(ctx: P.IdentContext): AST.Ident; 108 | protected vlist(ctx: ParserRuleContext[]): AST.List; 109 | protected defaultResult(): AST.AST; 110 | } 111 | -------------------------------------------------------------------------------- /scripts/generate-textmate.ts: -------------------------------------------------------------------------------- 1 | import * as tm from 'tmlanguage-generator'; 2 | import path from 'path'; 3 | import plist from 'plist'; 4 | 5 | export const grammarPath = path.resolve(__dirname, '../cwscript.tmlanguage'); 6 | 7 | type Rule = tm.Rule; 8 | type IncludeRule = tm.IncludeRule; 9 | type BeginEndRule = tm.BeginEndRule; 10 | type MatchRule = tm.MatchRule; 11 | type Grammar = tm.Grammar; 12 | 13 | export type CWScriptScope = 14 | | 'comment.block.cwscript' 15 | | 'comment.line.double-slash.cwscript' 16 | | 'constant.character.escape.cwscript' 17 | | 'constant.numeric.cwscript' 18 | | 'constant.language.cwscript' 19 | | 'entity.name.function.cwscript' 20 | | 'keyword.control.declaration.cwscript' 21 | | 'string.quoted.single.cwscript' 22 | | 'string.quoted.multi.cwscript' 23 | | 'variable.other.readwrite.cwscript' 24 | | 'variable.other.property.cwscript' 25 | | 'punctuation.definition.template-expression.begin.cwscript' 26 | | 'punctuation.definition.template-expression.end.cwscript'; 27 | 28 | const bounded = (text: string) => `\\b${text}\\b`; 29 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 30 | const after = (regex: string) => `(?<=${regex})`; 31 | const notAfter = (regex: string) => `(? `(?=${regex})`; 33 | const notBefore = (regex: string) => `(?!${regex})`; 34 | 35 | const meta: typeof tm.meta = tm.meta; 36 | const identifierStart = '[_$[:alpha:]]'; 37 | const identifierContinue = '[_$[:alnum:]]'; 38 | const identifier = bounded(`${identifierStart}${identifierContinue}*`); 39 | const directive = bounded(`[_a-zA-Z-0-9]+`); 40 | 41 | // whitespace. ideally we'd tokenize in-line block comments, but that's a lot of work. For now, ignore them. 42 | const ws = `(?:[ \\t\\r\\n]|\\/\\*(?:\\*(?!\\/)|[^*])*\\*\\/)*`; 43 | 44 | const keywords = [ 45 | 'metadata', 46 | 'targetScope', 47 | 'resource', 48 | 'module', 49 | 'param', 50 | 'var', 51 | 'output', 52 | 'for', 53 | 'in', 54 | 'if', 55 | 'existing', 56 | 'import', 57 | 'as', 58 | 'type', 59 | 'with', 60 | 'using', 61 | ]; 62 | 63 | const keywordExpression: MatchRule = { 64 | key: 'keyword', 65 | scope: 'keyword.control.declaration.cwscript', 66 | match: bounded(`(${keywords.join('|')})`), 67 | }; 68 | 69 | const lineComment: MatchRule = { 70 | key: 'line-comment', 71 | scope: 'comment.line.double-slash.cwscript', 72 | match: `//.*${before(`$`)}`, 73 | }; 74 | 75 | const blockComment: BeginEndRule = { 76 | key: 'block-comment', 77 | scope: 'comment.block.cwscript', 78 | begin: `/\\*`, 79 | end: `\\*/`, 80 | }; 81 | 82 | const comments: IncludeRule = { 83 | key: 'comments', 84 | patterns: [lineComment, blockComment], 85 | }; 86 | 87 | function withComments(input: Rule[]): Rule[] { 88 | return [...input, comments]; 89 | } 90 | 91 | const expression: IncludeRule = { 92 | key: 'expression', 93 | patterns: [ 94 | /* placeholder filled later due to cycle*/ 95 | ], 96 | }; 97 | 98 | const escapeChar: MatchRule = { 99 | key: 'escape-character', 100 | scope: 'constant.character.escape.cwscript', 101 | match: `\\\\(u{[0-9A-Fa-f]+}|n|r|t|\\\\|'|\\\${)`, 102 | }; 103 | 104 | const stringVerbatim: BeginEndRule = { 105 | key: 'string-verbatim', 106 | scope: 'string.quoted.multi.cwscript', 107 | begin: `'''`, 108 | end: `'''`, 109 | patterns: [], 110 | }; 111 | 112 | const stringSubstitution: BeginEndRule = { 113 | key: 'string-literal-subst', 114 | scope: meta, 115 | begin: `${notAfter(`\\\\`)}(\\\${)`, 116 | beginCaptures: { 117 | '1': { scope: 'punctuation.definition.template-expression.begin.cwscript' }, 118 | }, 119 | end: `(})`, 120 | endCaptures: { 121 | '1': { scope: 'punctuation.definition.template-expression.end.cwscript' }, 122 | }, 123 | patterns: withComments([expression]), 124 | }; 125 | 126 | const stringLiteral: BeginEndRule = { 127 | key: 'string-literal', 128 | scope: 'string.quoted.single.cwscript', 129 | begin: `'${notBefore(`''`)}`, 130 | end: `'`, 131 | patterns: [escapeChar, stringSubstitution], 132 | }; 133 | 134 | const numericLiteral: MatchRule = { 135 | key: 'numeric-literal', 136 | scope: 'constant.numeric.cwscript', 137 | match: `[0-9]+`, 138 | }; 139 | 140 | const namedLiteral: MatchRule = { 141 | key: 'named-literal', 142 | scope: 'constant.language.cwscript', 143 | match: bounded(`(true|false|null)`), 144 | }; 145 | 146 | const identifierExpression: MatchRule = { 147 | key: 'identifier', 148 | scope: 'variable.other.readwrite.cwscript', 149 | match: `${identifier}${notBefore(`${ws}\\(`)}`, 150 | }; 151 | 152 | const objectLiteral: BeginEndRule = { 153 | key: 'object-literal', 154 | scope: meta, 155 | begin: `{`, 156 | end: `}`, 157 | patterns: withComments([ 158 | { 159 | key: 'object-property-key', 160 | scope: 'variable.other.property.cwscript', 161 | match: `${identifier}${before(`${ws}:`)}`, 162 | }, 163 | expression, 164 | ]), 165 | }; 166 | 167 | const arrayLiteral: BeginEndRule = { 168 | key: 'array-literal', 169 | scope: meta, 170 | begin: `\\[${notBefore(`${ws}${bounded(`for`)}`)}`, 171 | end: `]`, 172 | patterns: withComments([expression]), 173 | }; 174 | 175 | const functionCall: BeginEndRule = { 176 | key: 'function-call', 177 | scope: meta, 178 | begin: `(${identifier})${ws}\\(`, 179 | beginCaptures: { 180 | '1': { scope: 'entity.name.function.cwscript' }, 181 | }, 182 | end: `\\)`, 183 | patterns: withComments([expression]), 184 | }; 185 | 186 | const decorator: BeginEndRule = { 187 | key: 'decorator', 188 | scope: meta, 189 | begin: `@${ws}${before(identifier)}`, 190 | end: ``, 191 | patterns: withComments([expression]), 192 | }; 193 | 194 | const lambdaStart = 195 | `(` + 196 | `\\(${ws}${identifier}${ws}(,${ws}${identifier}${ws})*\\)|` + 197 | `\\(${ws}\\)|` + 198 | `${ws}${identifier}${ws}` + 199 | `)${before(`${ws}=>`)}`; 200 | 201 | const lambda: BeginEndRule = { 202 | key: 'lambda-start', 203 | scope: meta, 204 | begin: lambdaStart, 205 | beginCaptures: { 206 | '1': { 207 | scope: meta, 208 | patterns: withComments([identifierExpression]), 209 | }, 210 | }, 211 | end: `${ws}=>`, 212 | }; 213 | 214 | const directiveStatement: BeginEndRule = { 215 | key: 'directive', 216 | scope: meta, 217 | begin: `#${directive}`, 218 | end: `$`, 219 | patterns: withComments([ 220 | { 221 | key: 'directive-variable', 222 | scope: 'keyword.control.declaration.cwscript', 223 | match: directive, 224 | }, 225 | ]), 226 | }; 227 | 228 | expression.patterns = [ 229 | stringLiteral, 230 | stringVerbatim, 231 | numericLiteral, 232 | namedLiteral, 233 | objectLiteral, 234 | arrayLiteral, 235 | keywordExpression, 236 | identifierExpression, 237 | functionCall, 238 | decorator, 239 | lambda, 240 | directiveStatement, 241 | ]; 242 | 243 | const grammar: Grammar = { 244 | $schema: tm.schema, 245 | name: 'Bicep', 246 | scopeName: 'source.cwscript', 247 | fileTypes: ['.cwscript'], 248 | patterns: withComments([expression]), 249 | }; 250 | 251 | export async function generateGrammar(): Promise { 252 | const json = await tm.emitJSON(grammar); 253 | 254 | return plist.build(JSON.parse(json)); 255 | } 256 | -------------------------------------------------------------------------------- /dist/util/position.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.getIx = exports.TextView = void 0; 4 | const lines_and_columns_1 = require("lines-and-columns"); 5 | class TextView { 6 | constructor(text) { 7 | this.text = text; 8 | this.lc = new lines_and_columns_1.LinesAndColumns(text); 9 | this.textLines = this.text.split('\n'); 10 | } 11 | /** 12 | * Returns the character at the given line and character. 13 | * If char is undefined, returns the entire line. 14 | * If oneIndexed is true, line and char are 1-indexed. 15 | * @param line 16 | * @param char 17 | * @param oneIndexed 18 | */ 19 | at(line, char, oneIndexed = false) { 20 | if (oneIndexed) { 21 | line--; 22 | if (char !== undefined) { 23 | char--; 24 | } 25 | } 26 | if (char === undefined) { 27 | return this.textLines[line]; 28 | } 29 | else { 30 | return this.textLines[line][char]; 31 | } 32 | } 33 | /** 34 | * Returns the text in the given range. 35 | * If oneIndexed is true, line and char in the Range are 1-indexed. 36 | * @param range 37 | * @param oneIndexed 38 | */ 39 | textInRange(range, oneIndexed = false) { 40 | // the LineAndColumns library expects a 0-indexed { line, column } object 41 | if (oneIndexed) { 42 | range = { 43 | start: { 44 | line: range.start.line - 1, 45 | character: range.start.character - 1, 46 | }, 47 | end: { 48 | line: range.end.line - 1, 49 | character: range.end.character - 1, 50 | }, 51 | }; 52 | } 53 | let startLineCol = { 54 | line: range.start.line, 55 | column: range.start.character, 56 | }; 57 | let endLineCol = { 58 | line: range.end.line, 59 | column: range.end.character, 60 | }; 61 | let start = this.lc.indexForLocation(startLineCol); 62 | let end = this.lc.indexForLocation(endLineCol); 63 | if (start === null || end === null) { 64 | return null; 65 | } 66 | return this.text.slice(start, end + 1); 67 | } 68 | /** 69 | * Returns the lines in the given range. 70 | * If oneIndexed is true, `startLine` and `endLine` are 1-indexed. 71 | * By default, it expects 0-indexed line numbers. 72 | * @param startLine 73 | * @param endLine 74 | * @param oneIndexed 75 | */ 76 | lines(startLine, endLine, oneIndexed = false) { 77 | if (oneIndexed) { 78 | startLine -= 1; 79 | endLine -= 1; 80 | } 81 | return this.textLines.slice(startLine, endLine + 1); 82 | } 83 | /** 84 | * Returns the lines surrounding the given line. 85 | * If oneIndexed is true, `line` is 1-indexed. 86 | * By default, it expects 0-indexed line numbers. 87 | * 88 | * @param line Line number to get surrounding lines for. 89 | * @param numLines Number of lines to return on either side of the given line. 90 | * @param oneIndexed Whether the given line number is 1-indexed or 0-indexed. 91 | */ 92 | surroundingLines(line, numLines, oneIndexed = false) { 93 | if (oneIndexed) { 94 | line -= 1; 95 | } 96 | let start = Math.max(0, line - numLines); 97 | let end = Math.min(this.textLines.length - 1, line + numLines); 98 | return this.lines(start, end).map((x) => ({ 99 | text: x, 100 | line: start++ + (oneIndexed ? 1 : 0), 101 | })); 102 | } 103 | /** 104 | * Returns the lines surrounding the given range. 105 | * If oneIndexed is true, `startLine` and `endLine` are 1-indexed. 106 | * By default, it expects 0-indexed line numbers. 107 | * @param range 108 | * @param numLines 109 | * @param oneIndexed 110 | */ 111 | surroundingLinesOfRange(range, numLines, oneIndexed = false) { 112 | if (oneIndexed) { 113 | range = { 114 | start: { 115 | line: range.start.line - 1, 116 | character: range.start.character - 1, 117 | }, 118 | end: { 119 | line: range.end.line - 1, 120 | character: range.end.character - 1, 121 | }, 122 | }; 123 | } 124 | let start = Math.max(0, range.start.line - numLines); 125 | let end = Math.min(this.textLines.length - 1, range.end.line + numLines); 126 | return this.lines(start, end).map((x) => ({ 127 | text: x, 128 | line: start++ + (oneIndexed ? 1 : 0), 129 | })); 130 | } 131 | /** 132 | * Returns the text surrounding the given line. 133 | * If oneIndexed is true, `line` is 1-indexed. 134 | * By default, it expects 0-indexed line numbers. 135 | * @param line 136 | * @param numLines 137 | * @param oneIndexed 138 | */ 139 | surroundingText(line, numLines, oneIndexed = false) { 140 | return this.surroundingLines(line, numLines, oneIndexed).join('\n'); 141 | } 142 | /** 143 | * Returns the line and character for the given index. 144 | * By default, the line and character returned are 0-indexed unless specified 145 | * by the `makeOneIndexed` parameter. 146 | * 147 | * @param ix 148 | * @param makeOneIndexed Whether the returned line and character should be 1-indexed or 0-indexed. 149 | */ 150 | lcAtIndex(ix, makeOneIndexed = false) { 151 | let loc = this.lc.locationForIndex(ix); 152 | if (loc === null) { 153 | return null; 154 | } 155 | if (makeOneIndexed) { 156 | loc.line += 1; 157 | loc.column += 1; 158 | } 159 | return [loc.line, loc.column]; 160 | } 161 | /** 162 | * Returns the Range object for the given indices of start and 163 | * end. Note that the end index is inclusive. 164 | * 165 | * @param start The start index 166 | * @param end The end index 167 | * @param makeOneIndexed Whether the returned Range should be 1-indexed or 0-indexed. 168 | * @returns The Range object, or null if the indices are invalid. 169 | */ 170 | range(start, end, makeOneIndexed = false) { 171 | let lcStart = this.lcAtIndex(start, makeOneIndexed); 172 | let lcEnd = this.lcAtIndex(end, makeOneIndexed); 173 | if (lcStart === null || lcEnd === null) { 174 | return null; 175 | } 176 | return { 177 | start: { 178 | line: lcStart[0], 179 | character: lcStart[1], 180 | }, 181 | end: { 182 | line: lcEnd[0], 183 | character: lcEnd[1], 184 | }, 185 | }; 186 | } 187 | rangeOfNode(ctx) { 188 | let pos = getIx(ctx); 189 | return this.range(pos.start, pos.end); 190 | } 191 | } 192 | exports.TextView = TextView; 193 | function getIx(ctx) { 194 | var _a; 195 | let start = ctx.start.startIndex; 196 | let end = ((_a = ctx.stop) === null || _a === void 0 ? void 0 : _a.stopIndex) || ctx.start.stopIndex; 197 | let length = end - start + 1; 198 | return { 199 | start, 200 | end: start + length, 201 | }; 202 | } 203 | exports.getIx = getIx; 204 | //# sourceMappingURL=position.js.map -------------------------------------------------------------------------------- /src/util/position.ts: -------------------------------------------------------------------------------- 1 | import { ParserRuleContext } from 'antlr4ts'; 2 | import { TerminalNode } from 'antlr4ts/tree/TerminalNode'; 3 | import { LinesAndColumns } from 'lines-and-columns'; 4 | 5 | export class TextView { 6 | lc: LinesAndColumns; 7 | textLines: string[]; 8 | 9 | constructor(public text: string) { 10 | this.lc = new LinesAndColumns(text); 11 | this.textLines = this.text.split('\n'); 12 | } 13 | 14 | /** 15 | * Returns the character at the given line and character. 16 | * If char is undefined, returns the entire line. 17 | * If oneIndexed is true, line and char are 1-indexed. 18 | * @param line 19 | * @param char 20 | * @param oneIndexed 21 | */ 22 | public at(line: number, char?: number, oneIndexed: boolean = false): string { 23 | if (oneIndexed) { 24 | line--; 25 | if (char !== undefined) { 26 | char--; 27 | } 28 | } 29 | if (char === undefined) { 30 | return this.textLines[line]; 31 | } else { 32 | return this.textLines[line][char]; 33 | } 34 | } 35 | 36 | /** 37 | * Returns the text in the given range. 38 | * If oneIndexed is true, line and char in the Range are 1-indexed. 39 | * @param range 40 | * @param oneIndexed 41 | */ 42 | public textInRange(range: Range, oneIndexed: boolean = false): string | null { 43 | // the LineAndColumns library expects a 0-indexed { line, column } object 44 | if (oneIndexed) { 45 | range = { 46 | start: { 47 | line: range.start.line - 1, 48 | character: range.start.character - 1, 49 | }, 50 | end: { 51 | line: range.end.line - 1, 52 | character: range.end.character - 1, 53 | }, 54 | }; 55 | } 56 | let startLineCol = { 57 | line: range.start.line, 58 | column: range.start.character, 59 | }; 60 | let endLineCol = { 61 | line: range.end.line, 62 | column: range.end.character, 63 | }; 64 | let start = this.lc.indexForLocation(startLineCol); 65 | let end = this.lc.indexForLocation(endLineCol); 66 | 67 | if (start === null || end === null) { 68 | return null; 69 | } 70 | return this.text.slice(start, end + 1); 71 | } 72 | 73 | /** 74 | * Returns the lines in the given range. 75 | * If oneIndexed is true, `startLine` and `endLine` are 1-indexed. 76 | * By default, it expects 0-indexed line numbers. 77 | * @param startLine 78 | * @param endLine 79 | * @param oneIndexed 80 | */ 81 | public lines( 82 | startLine: number, 83 | endLine: number, 84 | oneIndexed: boolean = false 85 | ): string[] { 86 | if (oneIndexed) { 87 | startLine -= 1; 88 | endLine -= 1; 89 | } 90 | return this.textLines.slice(startLine, endLine + 1); 91 | } 92 | 93 | /** 94 | * Returns the lines surrounding the given line. 95 | * If oneIndexed is true, `line` is 1-indexed. 96 | * By default, it expects 0-indexed line numbers. 97 | * 98 | * @param line Line number to get surrounding lines for. 99 | * @param numLines Number of lines to return on either side of the given line. 100 | * @param oneIndexed Whether the given line number is 1-indexed or 0-indexed. 101 | */ 102 | public surroundingLines( 103 | line: number, 104 | numLines: number, 105 | oneIndexed: boolean = false 106 | ) { 107 | if (oneIndexed) { 108 | line -= 1; 109 | } 110 | let start = Math.max(0, line - numLines); 111 | let end = Math.min(this.textLines.length - 1, line + numLines); 112 | return this.lines(start, end).map((x) => ({ 113 | text: x, 114 | line: start++ + (oneIndexed ? 1 : 0), 115 | })); 116 | } 117 | 118 | /** 119 | * Returns the lines surrounding the given range. 120 | * If oneIndexed is true, `startLine` and `endLine` are 1-indexed. 121 | * By default, it expects 0-indexed line numbers. 122 | * @param range 123 | * @param numLines 124 | * @param oneIndexed 125 | */ 126 | public surroundingLinesOfRange( 127 | range: Range, 128 | numLines: number, 129 | oneIndexed: boolean = false 130 | ) { 131 | if (oneIndexed) { 132 | range = { 133 | start: { 134 | line: range.start.line - 1, 135 | character: range.start.character - 1, 136 | }, 137 | end: { 138 | line: range.end.line - 1, 139 | character: range.end.character - 1, 140 | }, 141 | }; 142 | } 143 | let start = Math.max(0, range.start.line - numLines); 144 | let end = Math.min(this.textLines.length - 1, range.end.line + numLines); 145 | return this.lines(start, end).map((x) => ({ 146 | text: x, 147 | line: start++ + (oneIndexed ? 1 : 0), 148 | })); 149 | } 150 | 151 | /** 152 | * Returns the text surrounding the given line. 153 | * If oneIndexed is true, `line` is 1-indexed. 154 | * By default, it expects 0-indexed line numbers. 155 | * @param line 156 | * @param numLines 157 | * @param oneIndexed 158 | */ 159 | public surroundingText( 160 | line: number, 161 | numLines: number, 162 | oneIndexed: boolean = false 163 | ): string { 164 | return this.surroundingLines(line, numLines, oneIndexed).join('\n'); 165 | } 166 | 167 | /** 168 | * Returns the line and character for the given index. 169 | * By default, the line and character returned are 0-indexed unless specified 170 | * by the `makeOneIndexed` parameter. 171 | * 172 | * @param ix 173 | * @param makeOneIndexed Whether the returned line and character should be 1-indexed or 0-indexed. 174 | */ 175 | public lcAtIndex( 176 | ix: number, 177 | makeOneIndexed: boolean = false 178 | ): [number, number] | null { 179 | let loc = this.lc.locationForIndex(ix); 180 | if (loc === null) { 181 | return null; 182 | } 183 | if (makeOneIndexed) { 184 | loc.line += 1; 185 | loc.column += 1; 186 | } 187 | return [loc.line, loc.column]; 188 | } 189 | 190 | /** 191 | * Returns the Range object for the given indices of start and 192 | * end. Note that the end index is inclusive. 193 | * 194 | * @param start The start index 195 | * @param end The end index 196 | * @param makeOneIndexed Whether the returned Range should be 1-indexed or 0-indexed. 197 | * @returns The Range object, or null if the indices are invalid. 198 | */ 199 | public range( 200 | start: number, 201 | end: number, 202 | makeOneIndexed: boolean = false 203 | ): Range | null { 204 | let lcStart = this.lcAtIndex(start, makeOneIndexed); 205 | let lcEnd = this.lcAtIndex(end, makeOneIndexed); 206 | 207 | if (lcStart === null || lcEnd === null) { 208 | return null; 209 | } 210 | 211 | return { 212 | start: { 213 | line: lcStart[0], 214 | character: lcStart[1], 215 | }, 216 | end: { 217 | line: lcEnd[0], 218 | character: lcEnd[1], 219 | }, 220 | }; 221 | } 222 | 223 | public rangeOfNode(ctx: ParserRuleContext): Range | null { 224 | let pos = getIx(ctx); 225 | return this.range(pos.start, pos.end); 226 | } 227 | 228 | public rangeOfToken(ctx: ParserRuleContext, token: string): Range | null { 229 | const node = (ctx as any)[token]() as TerminalNode; 230 | return this.range(node.symbol.startIndex, node.symbol.stopIndex + 1); 231 | } 232 | } 233 | 234 | export function getIx(ctx: ParserRuleContext): TextIndices { 235 | let start = ctx.start.startIndex; 236 | let end = ctx.stop?.stopIndex || ctx.start.stopIndex; 237 | let length = end - start + 1; 238 | 239 | return { 240 | start, 241 | end: start + length, 242 | }; 243 | } 244 | 245 | /** 246 | * Returns the start and end indices of the given node. 247 | */ 248 | export interface TextIndices { 249 | start: number; 250 | end: number; 251 | } 252 | 253 | /** 254 | * Compatible with LSP's Range object -- 0-indexed. 255 | */ 256 | export interface Range { 257 | start: { 258 | line: number; 259 | character: number; 260 | }; 261 | 262 | end: { 263 | line: number; 264 | character: number; 265 | }; 266 | } 267 | -------------------------------------------------------------------------------- /src/parser/validation.ts: -------------------------------------------------------------------------------- 1 | // import { CWScriptParserListener } from '../grammar/CWScriptParserListener'; 2 | // import * as P from '../grammar/CWScriptParser'; 3 | // 4 | // import { SymbolTable } from '../util/symbol-table'; 5 | // import { ANTLRErrorListener, ParserRuleContext } from 'antlr4ts'; 6 | // import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver'; 7 | // import { getPosition, TextView } from '../util/position'; 8 | // import { SourceFileContext } from '../grammar/CWScriptParser'; 9 | // import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'; 10 | // import { RecognitionException } from 'antlr4ts/RecognitionException'; 11 | // 12 | // export abstract class CWSDiagnosticsCollector { 13 | // public diagnostics: Diagnostic[] = []; 14 | // 15 | // public get errors(): Diagnostic[] { 16 | // return this.diagnostics.filter( 17 | // (d) => d.severity === DiagnosticSeverity.Error 18 | // ); 19 | // } 20 | // 21 | // public get warnings(): Diagnostic[] { 22 | // return this.diagnostics.filter( 23 | // (d) => d.severity === DiagnosticSeverity.Warning 24 | // ); 25 | // } 26 | // 27 | // public get infos(): Diagnostic[] { 28 | // return this.diagnostics.filter( 29 | // (d) => d.severity === DiagnosticSeverity.Information 30 | // ); 31 | // } 32 | // 33 | // public get hints(): Diagnostic[] { 34 | // return this.diagnostics.filter( 35 | // (d) => d.severity === DiagnosticSeverity.Hint 36 | // ); 37 | // } 38 | // } 39 | // 40 | // export class CWSSyntaxErrorListener 41 | // extends CWSDiagnosticsCollector 42 | // implements ANTLRErrorListener 43 | // { 44 | // public diagnostics: Diagnostic[] = []; 45 | // 46 | // syntaxError( 47 | // recognizer: any, 48 | // offendingSymbol: any, 49 | // line: number, 50 | // charPositionInLine: number, 51 | // msg: string, 52 | // e: RecognitionException | undefined 53 | // ) { 54 | // this.diagnostics.push({ 55 | // severity: DiagnosticSeverity.Error, 56 | // message: 'SyntaxError: ' + msg, 57 | // range: { 58 | // start: { line: line - 1, character: charPositionInLine }, 59 | // end: { line: line - 1, character: charPositionInLine }, 60 | // }, 61 | // }); 62 | // } 63 | // } 64 | // 65 | // export class CWSValidation 66 | // extends CWSDiagnosticsCollector 67 | // implements CWScriptParserListener 68 | // { 69 | // constructor(public env: any) { 70 | // super(); 71 | // } 72 | // 73 | // enterEveryRule(ctx: ParserRuleContext) {} 74 | // 75 | // exitEveryRule(ctx: ParserRuleContext) {} 76 | // 77 | // public isInside(ruleName: string): boolean { 78 | // return this.validator.isInside(ruleName); 79 | // } 80 | // 81 | // public get scope(): SymbolTable { 82 | // return this.validator.scope; 83 | // } 84 | // 85 | // public pushScope(scope?: SymbolTable) { 86 | // this.validator.pushScope(scope); 87 | // } 88 | // 89 | // public popScope() { 90 | // return this.validator.popScope(); 91 | // } 92 | // } 93 | // 94 | // export class CheckSymbolsDeclaredBeforeUse extends CWSValidation { 95 | // enterIdentExpr(ctx: P.IdentExprContext) { 96 | // if (!this.scope.hasSymbol(ctx.ident().text)) { 97 | // this.validator.addError( 98 | // ctx, 99 | // 'Symbol `' + ctx.text + '` used before definition.' 100 | // ); 101 | // } 102 | // } 103 | // 104 | // // definitions below 105 | // enterIdentBinding_(ctx: P.IdentBinding_Context) { 106 | // this.scope.setSymbol(ctx._name.text, ''); 107 | // } 108 | // 109 | // enterImportItemsStmt(ctx: P.ImportItemsStmtContext) { 110 | // ctx._items.forEach((sym) => { 111 | // this.scope.setSymbol(sym.text, ''); 112 | // }); 113 | // } 114 | // 115 | // enterParam(ctx: P.ParamContext) { 116 | // this.scope.setSymbol(ctx._name.text, ''); 117 | // } 118 | // 119 | // enterInstantiateDefn(ctx: P.InstantiateDefnContext) { 120 | // this.scope.setSymbol('#instantiate', ''); 121 | // } 122 | // 123 | // enterFnDefn(ctx: P.FnDefnContext) { 124 | // if (ctx._name) { 125 | // this.scope.setSymbol(ctx._name.text, ''); 126 | // } 127 | // } 128 | // 129 | // enterStructDefn(ctx: P.StructDefnContext) { 130 | // if (ctx._name) { 131 | // this.scope.setSymbol(ctx._name.text, ''); 132 | // } 133 | // } 134 | // 135 | // enterEnumDefn(ctx: P.EnumDefnContext) { 136 | // this.scope.setSymbol(ctx._name.text, ''); 137 | // } 138 | // } 139 | // 140 | // export class CWSParseTreeValidator implements CWScriptParserListener { 141 | // public started: boolean = false; 142 | // public completed: boolean = false; 143 | // public diagnostics: Diagnostic[] = []; 144 | // public stages: ValidationStage[] = []; 145 | // protected scopes: SymbolTable[] = []; 146 | // protected depth: { 147 | // [key: string]: number; 148 | // } = {}; 149 | // 150 | // public isInside(ruleName: string): boolean { 151 | // return this.depth[ruleName] > 0; 152 | // } 153 | // 154 | // public get scope(): SymbolTable { 155 | // return this.scopes[this.scopes.length - 1]; 156 | // } 157 | // 158 | // public pushScope(scope?: SymbolTable) { 159 | // if (scope) { 160 | // this.scopes.push(scope); 161 | // } else { 162 | // this.scopes.push(new SymbolTable()); 163 | // } 164 | // } 165 | // 166 | // public popScope() { 167 | // return this.scopes.pop(); 168 | // } 169 | // 170 | // constructor( 171 | // public tree: SourceFileContext, 172 | // public sourceText: TextView, 173 | // stages: (new (...a: any[]) => ValidationStage)[] = [] 174 | // ) { 175 | // this.scopes.push(new SymbolTable()); 176 | // for (let stage of stages) { 177 | // this.stages.push(new stage(this)); 178 | // } 179 | // } 180 | // 181 | // public hasErrors(): boolean { 182 | // return this.diagnostics.some( 183 | // (d) => d.severity === DiagnosticSeverity.Error 184 | // ); 185 | // } 186 | // 187 | // public validate() { 188 | // this.started = true; 189 | // ParseTreeWalker.DEFAULT.walk(this, this.tree); 190 | // this.completed = true; 191 | // } 192 | // 193 | // enterEveryRule(ctx: ParserRuleContext) { 194 | // let ruleName = ctx.constructor.name.slice(0, -1 * 'Context'.length); 195 | // if (this.depth[ruleName] === undefined) { 196 | // this.depth[ruleName] = 0; 197 | // } else { 198 | // this.depth[ruleName]++; 199 | // } 200 | // for (let stage of this.stages) { 201 | // stage.enterEveryRule(ctx); 202 | // let fnName = `enter${ruleName}`; 203 | // if (fnName in stage) { 204 | // (stage as any)[fnName](ctx); 205 | // } 206 | // } 207 | // } 208 | // 209 | // exitEveryRule(ctx: ParserRuleContext) { 210 | // let ruleName = ctx.constructor.name.slice(0, -1 * 'Context'.length); 211 | // for (let stage of this.stages) { 212 | // stage.exitEveryRule(ctx); 213 | // let fnName = `exit${ruleName}`; 214 | // if (fnName in stage) { 215 | // (stage as any)[fnName](ctx); 216 | // } 217 | // } 218 | // this.depth[ruleName]--; 219 | // } 220 | // 221 | // public addError(ctx: ParserRuleContext, message: string) { 222 | // this.addDiagnostic(ctx, DiagnosticSeverity.Error, message); 223 | // } 224 | // 225 | // public addWarning(ctx: ParserRuleContext, message: string) { 226 | // this.addDiagnostic(ctx, DiagnosticSeverity.Warning, message); 227 | // } 228 | // 229 | // public addInfo(ctx: ParserRuleContext, message: string) { 230 | // this.addDiagnostic(ctx, DiagnosticSeverity.Information, message); 231 | // } 232 | // 233 | // public addHint(ctx: ParserRuleContext, message: string) { 234 | // this.addDiagnostic(ctx, DiagnosticSeverity.Hint, message); 235 | // } 236 | // 237 | // public addDiagnostic( 238 | // ctx: ParserRuleContext, 239 | // severity: DiagnosticSeverity, 240 | // message: string 241 | // ) { 242 | // let pos = getPosition(ctx); 243 | // let range = this.sourceText.range(pos.start, pos.end); 244 | // if (!range) { 245 | // throw new Error('Unable to get range for diagnostic.'); 246 | // } 247 | // this.diagnostics.push({ 248 | // severity, 249 | // message, 250 | // range, 251 | // }); 252 | // } 253 | // } 254 | -------------------------------------------------------------------------------- /dist/parser/validation.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // import { CWScriptParserListener } from '../grammar/CWScriptParserListener'; 3 | // import * as P from '../grammar/CWScriptParser'; 4 | // 5 | // import { SymbolTable } from '../util/symbol-table'; 6 | // import { ANTLRErrorListener, ParserRuleContext } from 'antlr4ts'; 7 | // import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver'; 8 | // import { getPosition, TextView } from '../util/position'; 9 | // import { SourceFileContext } from '../grammar/CWScriptParser'; 10 | // import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'; 11 | // import { RecognitionException } from 'antlr4ts/RecognitionException'; 12 | // 13 | // export abstract class CWSDiagnosticsCollector { 14 | // public diagnostics: Diagnostic[] = []; 15 | // 16 | // public get errors(): Diagnostic[] { 17 | // return this.diagnostics.filter( 18 | // (d) => d.severity === DiagnosticSeverity.Error 19 | // ); 20 | // } 21 | // 22 | // public get warnings(): Diagnostic[] { 23 | // return this.diagnostics.filter( 24 | // (d) => d.severity === DiagnosticSeverity.Warning 25 | // ); 26 | // } 27 | // 28 | // public get infos(): Diagnostic[] { 29 | // return this.diagnostics.filter( 30 | // (d) => d.severity === DiagnosticSeverity.Information 31 | // ); 32 | // } 33 | // 34 | // public get hints(): Diagnostic[] { 35 | // return this.diagnostics.filter( 36 | // (d) => d.severity === DiagnosticSeverity.Hint 37 | // ); 38 | // } 39 | // } 40 | // 41 | // export class CWSSyntaxErrorListener 42 | // extends CWSDiagnosticsCollector 43 | // implements ANTLRErrorListener 44 | // { 45 | // public diagnostics: Diagnostic[] = []; 46 | // 47 | // syntaxError( 48 | // recognizer: any, 49 | // offendingSymbol: any, 50 | // line: number, 51 | // charPositionInLine: number, 52 | // msg: string, 53 | // e: RecognitionException | undefined 54 | // ) { 55 | // this.diagnostics.push({ 56 | // severity: DiagnosticSeverity.Error, 57 | // message: 'SyntaxError: ' + msg, 58 | // range: { 59 | // start: { line: line - 1, character: charPositionInLine }, 60 | // end: { line: line - 1, character: charPositionInLine }, 61 | // }, 62 | // }); 63 | // } 64 | // } 65 | // 66 | // export class CWSValidation 67 | // extends CWSDiagnosticsCollector 68 | // implements CWScriptParserListener 69 | // { 70 | // constructor(public env: any) { 71 | // super(); 72 | // } 73 | // 74 | // enterEveryRule(ctx: ParserRuleContext) {} 75 | // 76 | // exitEveryRule(ctx: ParserRuleContext) {} 77 | // 78 | // public isInside(ruleName: string): boolean { 79 | // return this.validator.isInside(ruleName); 80 | // } 81 | // 82 | // public get scope(): SymbolTable { 83 | // return this.validator.scope; 84 | // } 85 | // 86 | // public pushScope(scope?: SymbolTable) { 87 | // this.validator.pushScope(scope); 88 | // } 89 | // 90 | // public popScope() { 91 | // return this.validator.popScope(); 92 | // } 93 | // } 94 | // 95 | // export class CheckSymbolsDeclaredBeforeUse extends CWSValidation { 96 | // enterIdentExpr(ctx: P.IdentExprContext) { 97 | // if (!this.scope.hasSymbol(ctx.ident().text)) { 98 | // this.validator.addError( 99 | // ctx, 100 | // 'Symbol `' + ctx.text + '` used before definition.' 101 | // ); 102 | // } 103 | // } 104 | // 105 | // // definitions below 106 | // enterIdentBinding_(ctx: P.IdentBinding_Context) { 107 | // this.scope.setSymbol(ctx._name.text, ''); 108 | // } 109 | // 110 | // enterImportItemsStmt(ctx: P.ImportItemsStmtContext) { 111 | // ctx._items.forEach((sym) => { 112 | // this.scope.setSymbol(sym.text, ''); 113 | // }); 114 | // } 115 | // 116 | // enterParam(ctx: P.ParamContext) { 117 | // this.scope.setSymbol(ctx._name.text, ''); 118 | // } 119 | // 120 | // enterInstantiateDefn(ctx: P.InstantiateDefnContext) { 121 | // this.scope.setSymbol('#instantiate', ''); 122 | // } 123 | // 124 | // enterFnDefn(ctx: P.FnDefnContext) { 125 | // if (ctx._name) { 126 | // this.scope.setSymbol(ctx._name.text, ''); 127 | // } 128 | // } 129 | // 130 | // enterStructDefn(ctx: P.StructDefnContext) { 131 | // if (ctx._name) { 132 | // this.scope.setSymbol(ctx._name.text, ''); 133 | // } 134 | // } 135 | // 136 | // enterEnumDefn(ctx: P.EnumDefnContext) { 137 | // this.scope.setSymbol(ctx._name.text, ''); 138 | // } 139 | // } 140 | // 141 | // export class CWSParseTreeValidator implements CWScriptParserListener { 142 | // public started: boolean = false; 143 | // public completed: boolean = false; 144 | // public diagnostics: Diagnostic[] = []; 145 | // public stages: ValidationStage[] = []; 146 | // protected scopes: SymbolTable[] = []; 147 | // protected depth: { 148 | // [key: string]: number; 149 | // } = {}; 150 | // 151 | // public isInside(ruleName: string): boolean { 152 | // return this.depth[ruleName] > 0; 153 | // } 154 | // 155 | // public get scope(): SymbolTable { 156 | // return this.scopes[this.scopes.length - 1]; 157 | // } 158 | // 159 | // public pushScope(scope?: SymbolTable) { 160 | // if (scope) { 161 | // this.scopes.push(scope); 162 | // } else { 163 | // this.scopes.push(new SymbolTable()); 164 | // } 165 | // } 166 | // 167 | // public popScope() { 168 | // return this.scopes.pop(); 169 | // } 170 | // 171 | // constructor( 172 | // public tree: SourceFileContext, 173 | // public sourceText: TextView, 174 | // stages: (new (...a: any[]) => ValidationStage)[] = [] 175 | // ) { 176 | // this.scopes.push(new SymbolTable()); 177 | // for (let stage of stages) { 178 | // this.stages.push(new stage(this)); 179 | // } 180 | // } 181 | // 182 | // public hasErrors(): boolean { 183 | // return this.diagnostics.some( 184 | // (d) => d.severity === DiagnosticSeverity.Error 185 | // ); 186 | // } 187 | // 188 | // public validate() { 189 | // this.started = true; 190 | // ParseTreeWalker.DEFAULT.walk(this, this.tree); 191 | // this.completed = true; 192 | // } 193 | // 194 | // enterEveryRule(ctx: ParserRuleContext) { 195 | // let ruleName = ctx.constructor.name.slice(0, -1 * 'Context'.length); 196 | // if (this.depth[ruleName] === undefined) { 197 | // this.depth[ruleName] = 0; 198 | // } else { 199 | // this.depth[ruleName]++; 200 | // } 201 | // for (let stage of this.stages) { 202 | // stage.enterEveryRule(ctx); 203 | // let fnName = `enter${ruleName}`; 204 | // if (fnName in stage) { 205 | // (stage as any)[fnName](ctx); 206 | // } 207 | // } 208 | // } 209 | // 210 | // exitEveryRule(ctx: ParserRuleContext) { 211 | // let ruleName = ctx.constructor.name.slice(0, -1 * 'Context'.length); 212 | // for (let stage of this.stages) { 213 | // stage.exitEveryRule(ctx); 214 | // let fnName = `exit${ruleName}`; 215 | // if (fnName in stage) { 216 | // (stage as any)[fnName](ctx); 217 | // } 218 | // } 219 | // this.depth[ruleName]--; 220 | // } 221 | // 222 | // public addError(ctx: ParserRuleContext, message: string) { 223 | // this.addDiagnostic(ctx, DiagnosticSeverity.Error, message); 224 | // } 225 | // 226 | // public addWarning(ctx: ParserRuleContext, message: string) { 227 | // this.addDiagnostic(ctx, DiagnosticSeverity.Warning, message); 228 | // } 229 | // 230 | // public addInfo(ctx: ParserRuleContext, message: string) { 231 | // this.addDiagnostic(ctx, DiagnosticSeverity.Information, message); 232 | // } 233 | // 234 | // public addHint(ctx: ParserRuleContext, message: string) { 235 | // this.addDiagnostic(ctx, DiagnosticSeverity.Hint, message); 236 | // } 237 | // 238 | // public addDiagnostic( 239 | // ctx: ParserRuleContext, 240 | // severity: DiagnosticSeverity, 241 | // message: string 242 | // ) { 243 | // let pos = getPosition(ctx); 244 | // let range = this.sourceText.range(pos.start, pos.end); 245 | // if (!range) { 246 | // throw new Error('Unable to get range for diagnostic.'); 247 | // } 248 | // this.diagnostics.push({ 249 | // severity, 250 | // message, 251 | // range, 252 | // }); 253 | // } 254 | // } 255 | //# sourceMappingURL=validation.js.map -------------------------------------------------------------------------------- /dist/interpreter.d.ts: -------------------------------------------------------------------------------- 1 | import * as AST from './ast'; 2 | import { SymbolTable } from './util/symbol-table'; 3 | import { Type, Value, OptionT, Param, FnDefn, Arg, CWSString, ErrorMsg, ContractDefn, StructDefn, EnumDefn, ListT, StateMap, StateItem, CWSBool, Indexable, TupleT, MapKey, StructInstance, ListInstance, TupleInstance, EventMsg } from './stdlib'; 4 | import { TextView } from './util/position'; 5 | export declare function arg(val: Value, name?: string): Arg; 6 | export declare function args(a_pos?: Value[], a_named?: { 7 | [name: string]: Value; 8 | }): Arg[]; 9 | export declare function idx(ix: number): Arg[]; 10 | export interface CWSInterpreterContext { 11 | sources: { 12 | [filename: string]: string; 13 | }; 14 | env?: { 15 | [globalName: string]: any; 16 | }; 17 | } 18 | export declare enum ContextType { 19 | INSTANTIATE = 0, 20 | EXEC = 1, 21 | QUERY = 2 22 | } 23 | export interface Env { 24 | block: { 25 | height: number; 26 | time: number; 27 | chain_id: string; 28 | }; 29 | contract: { 30 | address: string; 31 | }; 32 | } 33 | export interface MessageInfo { 34 | sender: string; 35 | funds: Array<{ 36 | denom: string; 37 | amount: string; 38 | }>; 39 | } 40 | export declare function buildCtxEnv(env: Env): StructInstance; 41 | export declare const CoinListT: ListT; 42 | export declare function buildCtxInfo(info: MessageInfo): StructInstance; 43 | export declare function buildCtxRes(): StructInstance; 44 | export declare function buildMutState(contract: ContractDefn): void; 45 | export declare function buildMutCtx(contract: ContractDefn, state: any, env: Env, info: MessageInfo): SymbolTable; 46 | export declare function buildQueryCtx(contract: ContractDefn, state: any, env: Env): SymbolTable; 47 | export declare class StateMapAccessor extends Value implements Indexable { 48 | state: ContractState; 49 | mapDefn: StateMap; 50 | prefix: string; 51 | mapKeys: MapKey[]; 52 | ty: Type; 53 | default_: Value; 54 | constructor(state: ContractState, mapDefn: StateMap); 55 | getIndex(args: Arg[]): Value; 56 | setIndex(args: Arg[], val: Value): void; 57 | removeIndex(args: Arg[]): void; 58 | buildKey(args: Arg[]): string; 59 | } 60 | export declare const ContractStateT: Type>; 61 | export declare class ContractState extends Value { 62 | interpreter: CWSInterpreter; 63 | contract: ContractDefn; 64 | stateInfo: { 65 | [key: string]: StateItem | StateMap; 66 | }; 67 | constructor(interpreter: CWSInterpreter, contract: ContractDefn); 68 | getSymbol(name: string): T; 69 | getOwnSymbol(name: string): T; 70 | firstTableWithSymbol(name: string): SymbolTable | undefined; 71 | } 72 | export declare class ContractInstance extends Value { 73 | interpreter: CWSInterpreter; 74 | ty: C; 75 | state: ContractState; 76 | constructor(interpreter: CWSInterpreter, ty: C); 77 | instantiate(env: Env, info: MessageInfo, args: Arg[]): any; 78 | exec(env: Env, info: MessageInfo, name: string, args: Arg[]): any; 79 | query(env: Env, name: string, args: Arg[]): Value | import("./stdlib").Impl>, any>; 80 | } 81 | export declare class CWSInterpreter extends SymbolTable { 82 | ctx: CWSInterpreterContext; 83 | visitor?: CWSInterpreterVisitor; 84 | constructor(ctx: CWSInterpreterContext); 85 | runCode(sourceText: string, file?: string): void; 86 | callFn(fn: FnDefn, args: Arg[], scope?: SymbolTable): Value | import("./stdlib").Impl>, any>; 87 | } 88 | export declare class Failure { 89 | error: Value; 90 | constructor(error: Value); 91 | } 92 | export declare class Return { 93 | value: Value; 94 | constructor(value: Value); 95 | } 96 | export declare class InterpreterError extends Error { 97 | constructor(message: string); 98 | } 99 | export declare class CWSInterpreterVisitor extends AST.CWSASTVisitor { 100 | interpreter: CWSInterpreter; 101 | sourceText: string; 102 | ctx: any; 103 | tv: TextView; 104 | scopes: SymbolTable[]; 105 | private debugMode; 106 | get scope(): SymbolTable; 107 | firstTableWithSymbol(name: string): SymbolTable | undefined; 108 | hasSymbol(name: string): boolean; 109 | pushScope(scope: SymbolTable): void; 110 | popScope(): void; 111 | getSymbol(name: string): T; 112 | setSymbol(name: string, value: any): void; 113 | file: string; 114 | constructor(interpreter: CWSInterpreter, sourceText: string, file: string); 115 | makeError(message: string, node: AST.AST): InterpreterError; 116 | visit(node: AST.AST): T; 117 | visitSourceFile(node: AST.SourceFile): void; 118 | visitParam(node: AST.Param): Param; 119 | visitType(node: AST.AST): Type; 120 | visitInterfaceDefn(node: AST.InterfaceDefn): void; 121 | visitContractDefn(node: AST.ContractDefn): void; 122 | visitTypePath(node: AST.TypePath): Type; 123 | visitOptionT(node: AST.OptionT): OptionT; 124 | visitStructDefn(node: AST.ErrorDefn | AST.EventDefn | AST.StructDefn | AST.InstantiateDefn | AST.InstantiateDecl | AST.ExecDefn | AST.ExecDecl | AST.QueryDefn | AST.QueryDecl): StructDefn; 125 | visitEnumDefn(node: AST.EnumDefn): EnumDefn; 126 | visitListT(node: AST.ListT): ListT | TupleT; 127 | visitErrorDefn: (node: AST.ErrorDefn) => ErrorMsg; 128 | visitEventDefn: (node: AST.EventDefn) => EventMsg; 129 | visitMapKeyDefn(node: AST.MapKeyDefn): MapKey; 130 | visitFnDefn(node: AST.FnDefn): FnDefn; 131 | /** 132 | * This visits the function definition for the instantiate message. 133 | * @param node 134 | */ 135 | visitInstantiateDefn(node: AST.InstantiateDefn): void; 136 | visitExecDefn(node: AST.ExecDefn): void; 137 | visitQueryDefn(node: AST.QueryDefn): void; 138 | visitBlock(node: AST.Block): Value; 139 | visitDebugStmt(node: AST.DebugStmt): void; 140 | visitLetStmt(node: AST.LetStmt): void; 141 | visitAssignStmt(node: AST.AssignStmt): void; 142 | visitIfStmt(node: AST.IfStmt): any; 143 | visitForStmt(node: AST.ForStmt): void; 144 | visitEmitStmt(node: AST.EmitStmt): void; 145 | visitExecStmt(node: AST.ExecStmt): void; 146 | visitDelegateExecStmt(node: AST.DelegateExecStmt): Value | import("./stdlib").Impl>, any>; 147 | visitInstantiateStmt(node: AST.InstantiateStmt): void; 148 | visitReturnStmt(node: AST.ReturnStmt): void; 149 | visitFailStmt(node: AST.FailStmt): void; 150 | visitArg(node: AST.Arg): Arg; 151 | visitDotExpr(node: AST.DotExpr): any; 152 | visitAsExpr(node: AST.AsExpr): void; 153 | visitIndexExpr(node: AST.IndexExpr): Value | import("./stdlib").Impl>, any>; 154 | visitDColonExpr(node: AST.DColonExpr): any; 155 | callMethod(obj: Value, method: string, argVals: Value[]): Value | import("./stdlib").Impl>, any>; 156 | callFn(fn: FnDefn, args: Arg[], scope?: SymbolTable): Value | import("./stdlib").Impl>, any>; 157 | visitFnCallExpr(node: AST.FnCallExpr): Value | import("./stdlib").Impl>, any> | import("./stdlib").Failure; 158 | executeBinOp(op: AST.Op, lhs: Value, rhs: Value): Value | import("./stdlib").Impl>, any>; 159 | visitBinOpExpr(node: AST.BinOpExpr): Value | import("./stdlib").Impl>, any>; 160 | visitAndExpr(node: AST.AndExpr): any; 161 | visitOrExpr(node: AST.OrExpr): any; 162 | visitIsExpr(node: AST.IsExpr): Value; 163 | visitInExpr(node: AST.InExpr): Value; 164 | visitNotExpr(node: AST.NotExpr): Value; 165 | visitNoneCheckExpr(node: AST.NoneCheckExpr): Value; 166 | visitTryCatchElseExpr(node: AST.TryCatchElseExpr): any; 167 | visitFailExpr(node: AST.FailExpr): Failure; 168 | visitClosure(node: AST.Closure): FnDefn | import("./stdlib").Impl>>; 169 | visitTupleExpr(node: AST.TupleExpr): TupleInstance | ListInstance | import("./stdlib").Impl>>; 170 | visitStructExpr(node: AST.StructExpr): StructInstance; 171 | visitUnitVariantExpr(node: AST.UnitVariantExpr): any; 172 | visitIdent(node: AST.Ident): any; 173 | visitGroupedExpr(node: AST.GroupedExpr): any; 174 | visitGrouped2Expr(node: AST.Grouped2Expr): any; 175 | visitStringLit(node: AST.StringLit): Value; 176 | visitIntLit(node: AST.IntLit): Value; 177 | visitDecLit(node: AST.DecLit): Value; 178 | visitBoolLit(node: AST.BoolLit): Value; 179 | visitNoneLit(node: AST.NoneLit): Value; 180 | } 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `cwsc`: CWScript Compiler 2 | 3 | CWScript is a high-level programming language designed for writing smart contracts on the CosmWasm platform. It is focused on simplifying the process of creating smart contracts while maintaining compatibility with Rust and CosmWasm programming patterns. CWScript enforces a more constrained framework for writing smart contracts, allowing developers to build on a well-defined domain. This approach aims to streamline code organization, composability patterns, and the overall development experience. 4 | 5 | cwsc is written in TypeScript and requires Node.js v16 or later. 6 | 7 | 8 | * [`cwsc`: CWScript Compiler](#cwsc-cwscript-compiler) 9 | * [Features](#features) 10 | * [Installation](#installation) 11 | * [Usage](#usage) 12 | * [Examples](#examples) 13 | * [Hello World](#hello-world) 14 | * [Simple Token Contract](#simple-token-contract) 15 | * [Proxy Contract](#proxy-contract) 16 | * [AtomicOrderExample (Injective Protocol)](#atomicorderexample-injective-protocol) 17 | * [License](#license) 18 | * [Copyright](#copyright) 19 | 20 | 21 | ## Features 22 | - Simplified syntax, reducing syntactic noise and enhancing readability 23 | - High-level translation to idiomatic CosmWasm Rust patterns 24 | - Tooling-first approach, built for seamless integration with existing and new development tools 25 | - Designed to be extensible and compatible with Rust 26 | - Comprehensive documentation to guide you through the CWScript journey 27 | 28 | 29 | ## Installation 30 | **Initial release coming soon. Announcement will be made on official channels.** 31 | ## 32 | ## Usage 33 | Please refer to the official documentation for a complete guide on how to use CWScript and the cwsc compiler. Discover how to create, compile, and deploy smart contracts, and learn about the unique features of CWScript that simplify development and increase productivity. 34 | 35 | ## Examples 36 | 37 | ### Hello World 38 | 39 | ```rs 40 | contract HelloWorld { 41 | state { 42 | greeting: String 43 | } 44 | 45 | #instantiate(init_greeting: String) { 46 | $state.greeting = init_greeting 47 | } 48 | 49 | exec #update_greeting(new_greeting: String) { 50 | $state.greeting = new_greeting 51 | } 52 | 53 | query #get_greeting() -> String { 54 | return $state.greeting 55 | } 56 | } 57 | ``` 58 | 59 | ### Simple Token Contract 60 | 61 | ```rs 62 | contract MyToken { 63 | state { 64 | total_supply: Uint128, 65 | balances[Address]: Uint128 = 0 66 | } 67 | 68 | #instantiate(initial_supply: Uint128) { 69 | let creator = $info.sender 70 | $state.total_supply = initial_supply 71 | $state.balances[creator] = initial_supply 72 | } 73 | 74 | exec #transfer(to: Address, amount: Uint128) { 75 | let sender = $info.sender 76 | let sender_balance = $state.balances[sender] ?? Uint128(0) 77 | 78 | assert!(sender_balance >= amount, "Insufficient balance") 79 | 80 | $state.balances[sender] = sender_balance - amount 81 | $state.balances[to] += amount 82 | } 83 | 84 | query #balance_of(address: Address) -> Uint128 { 85 | return $state.balances[address] ?? Uint128(0) 86 | } 87 | 88 | query #total_supply() -> Uint128 { 89 | return $state.total_supply 90 | } 91 | } 92 | ``` 93 | 94 | ### Proxy Contract 95 | 96 | ```rs 97 | import { CW20 } from "standards/cw20" 98 | 99 | contract ProxyContract { 100 | state { 101 | target_token: Address 102 | } 103 | 104 | #instantiate(target_token_address: Address) { 105 | $state.target_token = target_token_address 106 | } 107 | 108 | exec #transfer_proxy(to: Address, amount: Uint128) { 109 | let sender = $info.sender 110 | 111 | // Call the transfer method of the target CW20 contract 112 | exec! CW20($state.target_token).#transfer(to, amount) 113 | } 114 | 115 | query #balance_of_proxy(address: Address) -> Uint128 { 116 | // Call the balance_of method of the target CW20 contract 117 | return query! CW20($state.target_token).#balance_of(address) 118 | } 119 | } 120 | ``` 121 | 122 | ### AtomicOrderExample (Injective Protocol) 123 | 124 | ```rs 125 | import { SubaccountId, MarketId } from "injective/types" 126 | import { FPDecimal } from "injective/math" 127 | import { CW2 } from "standards/cw2" 128 | 129 | const CONTRACT_NAME = "crates.io:atomic-order-example" 130 | const CONTRACT_VERSION = "0.0.1" 131 | 132 | contract AtomicOrderExample extends CW2 { 133 | 134 | state { 135 | config: struct ContractConfigState { 136 | market_id: MarketId, 137 | owner: Address, 138 | contract_subaccount_id: SubaccountId, 139 | base_denom: String, 140 | quote_denom: String 141 | } 142 | swap_operation_state: struct SwapCacheState { 143 | sender_address: String, 144 | deposited_amount: Coin 145 | } 146 | } 147 | 148 | #instantiate( 149 | market_id: MarketId 150 | ) { 151 | 152 | let market = try { 153 | query! Exchange.#market(market_id) 154 | } else fail! "Market with id: {market_id} not found" 155 | 156 | let config = ContractConfigState { 157 | market_id, 158 | base_denom: market.base_denom, 159 | quote_denom: market.quote_denom, 160 | owner: $info.sender, 161 | contract_subaccount_id: SubaccountId($env.contract.address, 0), 162 | } 163 | 164 | CW2.set_contract_version!($, CONTRACT_NAME, CONTRACT_VERSION) 165 | 166 | // we've changed it to "config" 167 | $state.config = config 168 | emit event(method="instantiate", owner=$info.sender) // anonymous event 169 | } 170 | 171 | reply.success handle_atomic_order() { 172 | let dec_scale_factor = FPDecimal(1000000000000000000) 173 | let order_response = Exchange.#create_spot_market_order::parse_response!($data) 174 | 175 | let trade_data = order_response.results ?? fail! "No trade data in order response" 176 | let quantity = FPDecimal!(trade_data.quantity) 177 | let price = FPDecimal!(trade_data.price) 178 | let fee = FPDecimal!(trade_data.fee) 179 | 180 | let { config, cache } = $state 181 | let contract_address = $env.contract.address 182 | let subaccount_id = config.contract_subaccount_id 183 | let cache = $state.cache 184 | let purchased_coins = coin(quantity, config.base_denom) 185 | let pair = quantity * price + fee 186 | let leftover = cache.deposited_amount.amount - paid 187 | 188 | 189 | exec! Exchange.#withdraw(contract_address, subaccount_id, purchased_coins) 190 | exec! Exchange.#withdraw(contract_address, subaccount_id, leftover_coins) 191 | exec! Bank.#send(cache.sender_address, [purchased_coins, leftover_coins]) 192 | } 193 | 194 | exec #swap_spot(quantity: FPDecimal, price: FPDecimal) { 195 | let { config } = $state 196 | let contract = $env.contract.address 197 | let subaccount_id = config.contract_subaccount_id 198 | let min_deposit = price quantity 199 | 200 | if $info.funds.is_empty() { 201 | fail! "No funds deposited!" 202 | } 203 | 204 | let message_deposit = FPDecimal!($info.funds[0].amount) 205 | 206 | if message_deposit < min_deposit { 207 | fail! "Deposit: {message_deposit} below min_deposit: {min_deposit}" 208 | } 209 | 210 | let order = SpotOrder( 211 | price, quantity, OrderType.#BuyAtomic, config.market_id, subaccount_id, contract 212 | ) 213 | 214 | let coins = $info.funds[0] 215 | 216 | $state.swap_operation_state = SwapCacheState($info.sender, coins) 217 | 218 | exec! Exchange.#deposit(contract, subaccount_id, coins) 219 | 220 | @reply.success(handle_atomic_order) 221 | exec! Exchange.create_spot_market_order(contract, order) 222 | } 223 | 224 | } 225 | ``` 226 | 227 | ## Related 228 | 229 | Checkout these related projects: 230 | 231 | * [@cosmology/telescope](https://github.com/cosmology-tech/telescope) Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules. 232 | * [@cosmwasm/ts-codegen](https://github.com/CosmWasm/ts-codegen) Convert your CosmWasm smart contracts into dev-friendly TypeScript classes. 233 | * [chain-registry](https://github.com/cosmology-tech/chain-registry) Everything from token symbols, logos, and IBC denominations for all assets you want to support in your application. 234 | * [cosmos-kit](https://github.com/cosmology-tech/cosmos-kit) Experience the convenience of connecting with a variety of web3 wallets through a single, streamlined interface. 235 | * [create-cosmos-app](https://github.com/cosmology-tech/create-cosmos-app) Set up a modern Cosmos app by running one command. 236 | * [interchain-ui](https://github.com/cosmology-tech/interchain-ui) The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit. 237 | * [starship](https://github.com/cosmology-tech/starship) Unified Testing and Development for the Interchain. 238 | 239 | ## Credits 240 | 241 | 🛠 Built by Cosmology — if you like our tools, please consider delegating to [our validator ⚛️](https://cosmology.zone/validator) 242 | 243 | 244 | ## Disclaimer 245 | 246 | AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND. 247 | 248 | No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value. 249 | 250 | ## License 251 | CWScript, cwsc, and its bundled toolchain are licensed under the MIT License. 252 | 253 | ## Copyright 254 | 255 | Copyright © 2021-2023 Web, Inc. 256 | --------------------------------------------------------------------------------