├── .gitignore
├── CHANGELOG.md
├── README.md
├── SECURITY.md
├── lerna.json
├── package.json
├── packages
├── sooho-advisory-db
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── README.md
│ ├── ethereum
│ │ └── solidity
│ │ │ └── cve
│ │ │ ├── 2018-12056.yml
│ │ │ ├── 2018-12511.yml
│ │ │ ├── 2018-13158.yml
│ │ │ ├── 2018-14001.yml
│ │ │ ├── 2018-14002.yml
│ │ │ ├── 2018-15552.yml
│ │ │ ├── 2018-17050.yml
│ │ │ ├── 2018-17071.yml
│ │ │ └── 2018-17877.yml
│ ├── index.js
│ ├── package.json
│ └── yarn.lock
├── sooho-cli
│ ├── .editorconfig
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── bin
│ │ ├── run
│ │ └── run.cmd
│ ├── package.json
│ ├── src
│ │ ├── commands
│ │ │ ├── audit.ts
│ │ │ ├── encrypt.ts
│ │ │ └── generate-db.ts
│ │ ├── index.ts
│ │ └── utils
│ │ │ ├── filters.ts
│ │ │ ├── flags.ts
│ │ │ └── parse-files.ts
│ ├── test
│ │ ├── commands
│ │ │ ├── Test
│ │ │ │ └── Test.sol
│ │ │ ├── Vulnerable.sol
│ │ │ ├── audit.test.ts
│ │ │ └── encrypt.test.ts
│ │ ├── mocha.opts
│ │ └── tsconfig.json
│ ├── tsconfig.json
│ ├── tslint.json
│ └── yarn.lock
├── sooho-flattener
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── package.json
│ ├── src
│ │ └── flattener.js
│ └── yarn.lock
└── sooho-parser
│ ├── .babelrc
│ ├── .editorconfig
│ ├── .eslintrc
│ ├── .gitignore
│ ├── .gitmodules
│ ├── .npmignore
│ ├── .travis.yml
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── package.json
│ ├── scripts
│ └── antlr4.sh
│ ├── src
│ ├── ASTBuilder.js
│ ├── ErrorListener.js
│ ├── antlr4
│ │ ├── BufferedTokenStream.js
│ │ ├── CharStreams.js
│ │ ├── CommonTokenFactory.js
│ │ ├── CommonTokenStream.js
│ │ ├── FileStream.js
│ │ ├── InputStream.js
│ │ ├── IntervalSet.js
│ │ ├── LL1Analyzer.js
│ │ ├── Lexer.js
│ │ ├── Parser.js
│ │ ├── ParserRuleContext.js
│ │ ├── PredictionContext.js
│ │ ├── README.md
│ │ ├── Recognizer.js
│ │ ├── RuleContext.js
│ │ ├── Token.js
│ │ ├── Utils.js
│ │ ├── atn
│ │ │ ├── ATN.js
│ │ │ ├── ATNConfig.js
│ │ │ ├── ATNConfigSet.js
│ │ │ ├── ATNDeserializationOptions.js
│ │ │ ├── ATNDeserializer.js
│ │ │ ├── ATNSimulator.js
│ │ │ ├── ATNState.js
│ │ │ ├── ATNType.js
│ │ │ ├── LexerATNSimulator.js
│ │ │ ├── LexerAction.js
│ │ │ ├── LexerActionExecutor.js
│ │ │ ├── ParserATNSimulator.js
│ │ │ ├── PredictionMode.js
│ │ │ ├── SemanticContext.js
│ │ │ ├── Transition.js
│ │ │ └── index.js
│ │ ├── dfa
│ │ │ ├── DFA.js
│ │ │ ├── DFASerializer.js
│ │ │ ├── DFAState.js
│ │ │ └── index.js
│ │ ├── error
│ │ │ ├── DiagnosticErrorListener.js
│ │ │ ├── ErrorListener.js
│ │ │ ├── ErrorStrategy.js
│ │ │ ├── Errors.js
│ │ │ └── index.js
│ │ ├── index.js
│ │ ├── package.json
│ │ ├── polyfills
│ │ │ ├── codepointat.js
│ │ │ └── fromcodepoint.js
│ │ └── tree
│ │ │ ├── Tree.js
│ │ │ ├── Trees.js
│ │ │ └── index.js
│ ├── index.js
│ ├── lib
│ │ ├── Solidity.interp
│ │ ├── Solidity.tokens
│ │ ├── SolidityLexer.interp
│ │ ├── SolidityLexer.js
│ │ ├── SolidityLexer.tokens
│ │ ├── SolidityListener.js
│ │ └── SolidityParser.js
│ └── tokens.js
│ ├── test
│ ├── ast.js
│ ├── index.js
│ ├── test.sol
│ └── utils.js
│ └── yarn.lock
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/node,webstorm+all
3 |
4 | ### Node ###
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 |
24 | # nyc test coverage
25 | .nyc_output
26 |
27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
28 | .grunt
29 |
30 | # Bower dependency directory (https://bower.io/)
31 | bower_components
32 |
33 | # node-waf configuration
34 | .lock-wscript
35 |
36 | # Compiled binary addons (https://nodejs.org/api/addons.html)
37 | build/Release
38 |
39 | # Dependency directories
40 | node_modules/
41 | jspm_packages/
42 |
43 | # TypeScript v1 declaration files
44 | typings/
45 |
46 | # Optional npm cache directory
47 | .npm
48 |
49 | # Optional eslint cache
50 | .eslintcache
51 |
52 | # Optional REPL history
53 | .node_repl_history
54 |
55 | # Output of 'npm pack'
56 | *.tgz
57 |
58 | # Yarn Integrity file
59 | .yarn-integrity
60 |
61 | # dotenv environment variables file
62 | .env
63 |
64 | # parcel-bundler cache (https://parceljs.org/)
65 | .cache
66 |
67 | # next.js build output
68 | .next
69 |
70 | # nuxt.js build output
71 | .nuxt
72 |
73 | # vuepress build output
74 | .vuepress/dist
75 |
76 | ### WebStorm+all ###
77 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
78 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
79 |
80 | # User-specific stuff
81 | .idea/**/workspace.xml
82 | .idea/**/tasks.xml
83 | .idea/**/usage.statistics.xml
84 | .idea/**/dictionaries
85 | .idea/**/shelf
86 |
87 | # Sensitive or high-churn files
88 | .idea/**/dataSources/
89 | .idea/**/dataSources.ids
90 | .idea/**/dataSources.local.xml
91 | .idea/**/sqlDataSources.xml
92 | .idea/**/dynamic.xml
93 | .idea/**/uiDesigner.xml
94 | .idea/**/dbnavigator.xml
95 |
96 | # Gradle
97 | .idea/**/gradle.xml
98 | .idea/**/libraries
99 |
100 | # Gradle and Maven with auto-import
101 | # When using Gradle or Maven with auto-import, you should exclude module files,
102 | # since they will be recreated, and may cause churn. Uncomment if using
103 | # auto-import.
104 | # .idea/modules.xml
105 | # .idea/*.iml
106 | # .idea/modules
107 |
108 | # CMake
109 | cmake-build-*/
110 |
111 | # Mongo Explorer plugin
112 | .idea/**/mongoSettings.xml
113 |
114 | # File-based project format
115 | *.iws
116 |
117 | # IntelliJ
118 | out/
119 |
120 | # mpeltonen/sbt-idea plugin
121 | .idea_modules/
122 |
123 | # JIRA plugin
124 | atlassian-ide-plugin.xml
125 |
126 | # Cursive Clojure plugin
127 | .idea/replstate.xml
128 |
129 | # Crashlytics plugin (for Android Studio and IntelliJ)
130 | com_crashlytics_export_strings.xml
131 | crashlytics.properties
132 | crashlytics-build.properties
133 | fabric.properties
134 |
135 | # Editor-based Rest Client
136 | .idea/httpRequests
137 |
138 | ### WebStorm+all Patch ###
139 | # Ignores the whole .idea folder and all .iml files
140 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
141 |
142 | .idea/
143 |
144 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
145 |
146 | *.iml
147 | modules.xml
148 | .idea/misc.xml
149 | *.ipr
150 |
151 | .DS_Store
152 | .webpack
153 |
154 |
155 |
156 | # End of https://www.gitignore.io/api/node,webstorm+all
157 | .DS_Store
158 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.3.4](https://github.com/soohoio/sooho/compare/v0.3.3...v0.3.4) (2020-04-28)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **lerna:** track package-lock.json on git ([9efd395](https://github.com/soohoio/sooho/commit/9efd395fe8e3b5acf55f676c9a96036b1f457dca))
12 | * **parser:** inject space between tokens @ getText ([622e9e1](https://github.com/soohoio/sooho/commit/622e9e11c6924bffc578fb73afdbe132a49b1b78))
13 | * **parser:** relative path to token def. file ([36671a5](https://github.com/soohoio/sooho/commit/36671a52ef9c9409a410027920f45812c9660155))
14 | * **util:** remove unused parameter in parse-files ([9591425](https://github.com/soohoio/sooho/commit/95914254effaf9e576f23d9f4a0e8c0aba7d2941))
15 |
16 |
17 | ### Features
18 |
19 | * **cli:** add command for generating advisory db ([faaadba](https://github.com/soohoio/sooho/commit/faaadba564401bc9cbef8460a219f45feb3b181c))
20 | * **flattener:** Add new package @sooho/sooho-flattener ([497cd7f](https://github.com/soohoio/sooho/commit/497cd7f09b7fc0776b0fd0c2df5e128e8c8e7323))
21 | * **signature:** update signature generation logic ([5173827](https://github.com/soohoio/sooho/commit/517382715617af124864d93e460869daf5e8d36f))
22 |
23 |
24 |
25 |
26 |
27 | ## [0.3.3](https://github.com/soohoio/sooho/compare/v0.3.1...v0.3.3) (2018-12-19)
28 |
29 |
30 | ### Bug Fixes
31 |
32 | * **advisory-db:** Fix demo version of cli audit and add test files ([624ba74](https://github.com/soohoio/sooho/commit/624ba74))
33 | * **config:** Change lerna config to versioning in release branch ([df6cb16](https://github.com/soohoio/sooho/commit/df6cb16))
34 | * **package:** Add dependent libary ([abc65c3](https://github.com/soohoio/sooho/commit/abc65c3))
35 | * **publish:** Change publish config from private to public ([e246551](https://github.com/soohoio/sooho/commit/e246551))
36 |
37 |
38 | ### Features
39 |
40 | * **advisory:** Add new package [@sooho](https://github.com/sooho)/sooho-advisory-db ([941d518](https://github.com/soohoio/sooho/commit/941d518))
41 |
42 |
43 |
44 |
45 |
46 | ## [0.3.2](https://github.com/soohoio/sooho/compare/v0.3.1...v0.3.2) (2018-12-19)
47 |
48 |
49 | ### Bug Fixes
50 |
51 | * **advisory-db:** Fix demo version of cli audit and add test files ([624ba74](https://github.com/soohoio/sooho/commit/624ba74))
52 | * **config:** Change lerna config to versioning in release branch ([7f54a18](https://github.com/soohoio/sooho/commit/7f54a18))
53 |
54 |
55 | ### Features
56 |
57 | * **advisory:** Add new package [@sooho](https://github.com/sooho)/sooho-advisory-db ([941d518](https://github.com/soohoio/sooho/commit/941d518))
58 |
59 |
60 |
61 |
62 |
63 | ## [0.3.1](https://github.com/soohoio/sooho/compare/v0.3.0...v0.3.1) (2018-12-16)
64 |
65 |
66 | ### Features
67 |
68 | * **lines:** Add fileinfo details ([c2194cc](https://github.com/soohoio/sooho/commit/c2194cc))
69 |
70 |
71 |
72 |
73 |
74 | ## [0.3.1](https://github.com/soohoio/sooho/compare/v0.3.0...v0.3.1) (2018-12-16)
75 |
76 |
77 | ### Features
78 |
79 | * **lines:** Add fileinfo details ([c2194cc](https://github.com/soohoio/sooho/commit/c2194cc))
80 |
81 |
82 |
83 |
84 |
85 | # [0.3.0](https://github.com/soohoio/sooho/compare/v0.2.0...v0.3.0) (2018-12-16)
86 |
87 |
88 | ### Features
89 |
90 | * **recursive:** Support spinner with recursive ([82dbf37](https://github.com/soohoio/sooho/commit/82dbf37))
91 |
92 |
93 |
94 |
95 |
96 | # [0.2.0](https://github.com/soohoio/sooho/compare/v0.1.1...v0.2.0) (2018-10-16)
97 |
98 |
99 | ### Features
100 |
101 | * **macos:** Support auto-update with macos installer ([bb363f1](https://github.com/soohoio/sooho/commit/bb363f1))
102 |
103 |
104 |
105 |
106 |
107 | ## [0.1.1](https://github.com/soohoio/sooho/compare/v0.1.0...v0.1.1) (2018-10-16)
108 |
109 |
110 | ### Features
111 |
112 | * **readme:** Support save options ([37f6ec3](https://github.com/soohoio/sooho/commit/37f6ec3))
113 |
114 |
115 |
116 |
117 |
118 | # [0.1.0](https://github.com/soohoio/sooho/compare/v0.0.2-alpha.0...v0.1.0) (2018-10-15)
119 |
120 |
121 | ### Code Refactoring
122 |
123 | * **encrypt:** Change output format ([3ab87dc](https://github.com/soohoio/sooho/commit/3ab87dc))
124 |
125 |
126 | ### BREAKING CHANGES
127 |
128 | * **encrypt:** JSON string format changed
129 |
130 |
131 |
132 |
133 |
134 | # Change Log
135 |
136 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
137 |
138 |
139 | # 0.1.0 (2018-10-14)
140 |
141 |
142 | ### Features
143 |
144 | * **init:** initial commit ([8b68b22](https://github.com/soohoio/sooho/commit/8b68b22))
145 |
146 |
147 |
148 |
149 | # [0.0.2](https://github.com/soohoio/sooho/compare/v0.0.1...v0.0.2) (2018-10-14)
150 |
151 | ### Features
152 |
153 | * **init:** initial commit ([8b68b22](https://github.com/soohoio/sooho/commit/8b68b22))
154 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SOOHO
2 |
3 | [](http://commitizen.github.io/cz-cli/)
4 |
5 | **Got a Question?** Send me a mail
6 |
7 | ## Table of Contents
8 | - [Introduction](#introduction)
9 | - [Development](#development)
10 | - [Install](#install)
11 | - [Test](#test)
12 | - [Run](#run)
13 | - [License](#license)
14 | - [About](#about)
15 |
16 | ## Introduction
17 |
18 | **Sooho** used to interact with Sooho services from the command line. It is built using oclif.
19 |
20 | For more about Sooho, see https://sooho.io
21 |
22 | ## Development
23 |
24 | ### Install
25 |
26 | This project is built with [lerna](http://lernajs.io/). The core plugins are located in ./packages.
27 |
28 | ```bash
29 | $ git clone https://github.com/soohoio/sooho
30 | $ lerna bootstrap
31 | $ lerna run build
32 | $ lerna run prepack
33 | ```
34 |
35 | ### Test
36 |
37 | ```bash
38 | $ lerna run test
39 | ```
40 |
41 | ### Run
42 |
43 | 1. Audit smart contract
44 |
45 | ```
46 | USAGE
47 | $ lerna run audit -- INPUT_PATH
48 |
49 | ARGUMENTS
50 | INPUT_PATH entry path
51 |
52 | EXAMPLE
53 | $ lerna run audit -- ./test/commands/Vulnerable.sol
54 | ```
55 |
56 | ## License
57 |
58 | Copyright (c) 2018 SOOHO Inc. It is free software and maybe redistributed under the terms specified in the LICENSE file.
59 |
60 | ## About
61 |
62 | Authored and maintained by **Jisu Park**.
63 |
64 | > Github [@JisuPark](https://github.com/JisuPark)
65 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Reporting Security Issues
2 |
3 | Sooho strongly believes the responsible disclosure of security vulnerabilities in open source helps user privacy and security. We appreciate your efforts to responsibly disclose your findings and will make every effort to acknowledge your contributions.
4 |
5 | To report a security issue, email [security@sooho.io](mailto:security@sooho.io) and include the word "SECURITY" in the subject line.
6 |
7 | We will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement and may ask for additional information or guidance.
8 |
9 | Report the security bugs in third-party modules to the person or team maintaining the module. You can also report a vulnerability through the [Sooho Vulnerability Disclosure](https://goo.gl/forms/BFB76kc0q0Q2a7PN2) program.
10 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "version": "0.3.4",
6 | "lerna": "3.4.3",
7 | "command": {
8 | "publish": {
9 | "allowBranch": [
10 | "master",
11 | "release/*"
12 | ],
13 | "conventionalCommits": true,
14 | "message": "chore(release): publish %s"
15 | }
16 | },
17 | "ignoreChanges": [
18 | "**/test/**",
19 | "**/*.md"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sooho",
3 | "description": "SOOHO CLI",
4 | "repository": "https://github.com/soohoio/sooho",
5 | "author": "Jisu Park",
6 | "private": true,
7 | "devDependencies": {
8 | "commitizen": "^3.0.2",
9 | "commitplease": "^3.2.0",
10 | "cz-conventional-changelog": "^2.1.0",
11 | "lerna": "^3.4.3",
12 | "standard-version": "^4.4.0"
13 | },
14 | "scripts": {
15 | "commit": "git-cz",
16 | "release": "lerna publish"
17 | },
18 | "commitplease": {
19 | "style": "angular",
20 | "nohook": true
21 | },
22 | "config": {
23 | "commitizen": {
24 | "path": "node_modules/cz-conventional-changelog"
25 | }
26 | },
27 | "standard-version": {
28 | "skip": {
29 | "tag": true
30 | }
31 | },
32 | "version": "0.1.0"
33 | }
34 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.3.4](https://github.com/soohoio/sooho/compare/v0.3.3...v0.3.4) (2020-04-28)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **lerna:** track package-lock.json on git ([9efd395](https://github.com/soohoio/sooho/commit/9efd395fe8e3b5acf55f676c9a96036b1f457dca))
12 |
13 |
14 |
15 |
16 |
17 | ## [0.3.3](https://github.com/soohoio/sooho/compare/v0.3.1...v0.3.3) (2018-12-19)
18 |
19 |
20 | ### Bug Fixes
21 |
22 | * **advisory-db:** Fix demo version of cli audit and add test files ([624ba74](https://github.com/soohoio/sooho/commit/624ba74))
23 | * **config:** Change lerna config to versioning in release branch ([df6cb16](https://github.com/soohoio/sooho/commit/df6cb16))
24 | * **package:** Add dependent libary ([abc65c3](https://github.com/soohoio/sooho/commit/abc65c3))
25 | * **publish:** Change publish config from private to public ([e246551](https://github.com/soohoio/sooho/commit/e246551))
26 |
27 |
28 | ### Features
29 |
30 | * **advisory:** Add new package [@sooho](https://github.com/sooho)/sooho-advisory-db ([941d518](https://github.com/soohoio/sooho/commit/941d518))
31 |
32 |
33 |
34 |
35 |
36 | ## [0.3.2](https://github.com/soohoio/sooho/compare/v0.3.1...v0.3.2) (2018-12-19)
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * **advisory-db:** Fix demo version of cli audit and add test files ([624ba74](https://github.com/soohoio/sooho/commit/624ba74))
42 |
43 |
44 | ### Features
45 |
46 | * **advisory:** Add new package [@sooho](https://github.com/sooho)/sooho-advisory-db ([941d518](https://github.com/soohoio/sooho/commit/941d518))
47 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/README.md:
--------------------------------------------------------------------------------
1 | @sooho/sooho-advisory-db
2 | ==
3 |
4 |
5 | This database contains information regarding CVE(s) that affect smart contracts. We currently store version information corresponding to respective modules as understood by select sources.
6 |
7 | |Language|Environments|Metadata|
8 | |--------|-------------|--------|
9 | |Solidity|Ethereum|`name`, `address`|
10 |
11 | This project is inspired by the great work done by the people at [RubySec](http://rubysec.github.io/) and [Victims](https://blog.victi.ms/).
12 |
13 | ### Notes on CVE(s)
14 | If you already have a CVE assigned to your project and would like us to create an entry for it with the correct coordinates, you can send us a [pull request](https://help.github.com/articles/using-pull-requests) or create an issue [here](https://github.com/soohoio/sooho/issues) with CVE details and affected components.
15 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-12056.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-12056
2 | title: "Breking PRNG in All For One"
3 | description: >
4 | The maxRandom function of a smart contract implementation for All For One, an Ethereum gambling game, generates a random value with publicly readable variables because the _seed value can be retrieved with a getStorageAt call. Therefore, it allows attackers to always win and get rewards.
5 | references:
6 | - https://medium.com/coinmonks/to-be-a-winner-of-ethereum-gambling-game-all-for-one-by-breaking-prng-1ab011163d40
7 | - https://nvd.nist.gov/vuln/detail/CVE-2018-12056
8 | credits: "Jonghyuk Song"
9 | vulnerability_type:
10 | cwe: "CWE-338"
11 | swc: "SWC-120"
12 | severity: 7.5
13 | affected:
14 | contractName: "Lottery"
15 | address: "0x9c16cbb9f9bd827f6cbee556c7801073fbac2250"
16 | signature: "a9e7573645bdfd6e95d63117c6dab3ab"
17 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-12511.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-12511
2 | title: "Integer overflow"
3 | description: >
4 | In the mintToken function of a smart contract implementation for Substratum (SUB), an Ethereum ERC20 token, the administrator can control mintedAmount, leverage an integer overflow, and modify a user account's balance arbitrarily.
5 | references:
6 | - https://github.com/n0pn0pn0p/smart_contract_-vulnerability/blob/master/PolyAi.md
7 | credits: "n0pn0pn0p"
8 | vulnerability_type:
9 | cwe: "CWE-190"
10 | swc: "SWC-101"
11 | severity: 7.5
12 | affected:
13 | contractName: "MyAdvancedToken"
14 | address: "0x12480e24eb5bec1a9d4369cab6a80cad3c0a377a"
15 | signature: "f2dea3f6ecb1397e9005efbd42dc90aa"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-13158.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-12056
2 | title: "Integer overflow"
3 | description: >
4 | The mintToken function of a smart contract implementation for AssetToken, an Ethereum token, has an integer overflow that allows the owner of the contract to set the balance of an arbitrary user to any value.
5 | references:
6 | - https://github.com/BlockChainsSecurity/EtherTokens/blob/master/GEMCHAIN/mint%20integer%20overflow.md
7 | - https://github.com/BlockChainsSecurity/EtherTokens/tree/master/AssetToken
8 | credits: "BlockChainsSecurity"
9 | vulnerability_type:
10 | cwe: "CWE-190"
11 | swc: "SWC-101"
12 | severity: 7.5
13 | affected:
14 | contractName: "AssetToken"
15 | address: "0x0bdbc0748ba09fbe9e9ed5938532e41446c2f033"
16 | signature: "8bc5f574da5fabf0b30bc2c9cb454231"
17 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-14001.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-14001
2 | title: "Integer overflow"
3 | description: >
4 | An integer overflow vulnerability exists in the function batchTransfer of SHARKTECH (SKT), an Ethereum token smart contract. An attacker could use it to set any user's balance.
5 | references:
6 | - https://github.com/VenusADLab/EtherTokens/blob/master/SHARKTECH/SHARKTECH.md
7 | credits: "VenusADLab"
8 | vulnerability_type:
9 | cwe: "CWE-190"
10 | swc: "SWC-101"
11 | severity: 7.5
12 | affected:
13 | contractName: "Shark"
14 | address: "0xf4ac238121585456DeE1096fED287F4d8906D519"
15 | signature: "6796f60784392dd620c85d43ba4f734d"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-14002.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-14002
2 | title: "Integer overflow"
3 | description: >
4 | An integer overflow vulnerability exists in the function distribute of MP3 Coin (MP3), an Ethereum token smart contract. An attacker could use it to set any user's balance.
5 | references:
6 | - https://github.com/VenusADLab/EtherTokens/blob/master/SHARKTECH/SHARKTECH.md
7 | credits: "VenusADLab"
8 | vulnerability_type:
9 | cwe: "CWE-190"
10 | swc: "SWC-101"
11 | severity: 7.5
12 | affected:
13 | contractName: "MP3Coin"
14 | address: "0x5ad6dc0a267693c8a14ac9ff2a29c7d63a3d96c2"
15 | signature: "21c275adb76b36bcb05d19966466931d"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-15552.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-15552
2 | title: "Breking PRNG in Ethereum Lottery"
3 | description: >
4 | The "PayWinner" function of a simplelottery smart contract implementation for The Ethereum Lottery, an Ethereum gambling game, generates a random value with publicly readable variable "maxTickets" (which is private, yet predictable and readable by the eth.getStorageAt function). Therefore, it allows attackers to always win and get rewards.
5 | references:
6 | - https://github.com/TEAM-C4B/CVE-LIST/tree/master/CVE-2018-15552
7 | credits: "TEAM-C4B"
8 | vulnerability_type:
9 | cwe: "CWE-338"
10 | swc: "SWC-120"
11 | severity: 7.5
12 | affected:
13 | contractName: "LottoCount"
14 | address: "0x1e217adc6a6adc16e248af109ab7efa4d1bb252d"
15 | signature: "a4aa4756cc71cf9dcf673654010fc5f2"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-17050.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-17050
2 | title: "Integer overflow"
3 | description: >
4 | The mintToken function of a smart contract implementation for PolyAi (AI), an Ethereum token, has an integer overflow that allows the owner of the contract to set the balance of an arbitrary user to any value.
5 | references:
6 | - https://github.com/n0pn0pn0p/smart_contract_-vulnerability/blob/master/PolyAi.md
7 | credits: "n0pn0pn0p"
8 | vulnerability_type:
9 | cwe: "CWE-190"
10 | swc: "SWC-101"
11 | severity: 7.5
12 | affected:
13 | contractName: "PolyAi"
14 | address: "0x5121e348e897daef1eef23959ab290e5557cf274"
15 | signature: "ba41c713dfeca7d69147f8ebcc09f699"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-17071.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-17071
2 | title: "Breking PRNG in Lucky9io"
3 | description: >
4 | The fallback function of a simple lottery smart contract implementation for Lucky9io, an Ethereum gambling game, generates a random value with the publicly readable variable entry_number. This variable is private, yet it is readable by eth.getStorageAt function. Also, attackers can purchase a ticket at a low price by directly calling the fallback function with small msg.value, because the developer set the currency unit incorrectly. Therefore, it allows attackers to always win and get rewards.
5 | references:
6 | - https://github.com/TEAM-C4B/CVE-LIST/tree/master/CVE-2018-17071
7 | credits: "TEAM-C4B"
8 | vulnerability_type:
9 | cwe: "CWE-338"
10 | swc: "SWC-120"
11 | severity: 7.5
12 | affected:
13 | contractName: "lucky9io"
14 | address: "0x94f5a9cecb397a8fb837edb809bc1cd6a66ffed2"
15 | signature: "ac00ddfd6670573c81b30089ed6e4380"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/ethereum/solidity/cve/2018-17877.yml:
--------------------------------------------------------------------------------
1 | id: CVE-2018-17877
2 | title: "Breking PRNG in Greedy 599"
3 | description: >
4 | A lottery smart contract implementation for Greedy 599, an Ethereum gambling game, generates a random value that is predictable via an external contract call. The developer used the extcodesize() function to prevent a malicious contract from being called, but the attacker can bypass it by writing the core code in the constructor of their exploit code. Therefore, it allows attackers to always win and get rewards.
5 | references:
6 | - https://github.com/TEAM-C4B/CVE-LIST/tree/master/CVE-2018-17877
7 | credits: "TEAM-C4B"
8 | vulnerability_type:
9 | cwe: "CWE-338"
10 | swc: "SWC-120"
11 | severity: 7.5
12 | affected:
13 | contractName: "Greedy"
14 | address: "0x3bb5e74f7ff56e0b64d326f8ec07236aa4a07260"
15 | signature: "79c073187783d3569f266d7dc0cdc08c"
16 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const yaml = require('js-yaml');
3 | const fs = require('fs');
4 | const path = require('path');
5 |
6 | const appDirectory = fs.realpathSync(process.cwd());
7 | const cveDirectory = 'ethereum/solidity/cve'
8 | const resolveOwn = relativePath => path.resolve(__dirname, relativePath);
9 |
10 | function getAdvisoryDB() {
11 | let data = [];
12 | try {
13 | const cveDir = resolveOwn(cveDirectory)
14 | fs.readdirSync(cveDir)
15 | .map(item => resolveOwn(`${cveDirectory}/${item}`))
16 | .forEach(filePath => data.push(yaml.safeLoad(
17 | fs.readFileSync(filePath, 'utf8')
18 | )));
19 | return data;
20 | } catch (e) {
21 | throw new Error(e);
22 | }
23 | }
24 |
25 | module.exports = { getAdvisoryDB };
26 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sooho/advisory-db",
3 | "version": "0.3.4",
4 | "description": "A community-driven vulnerability database of smart contract",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/soohoio/sooho"
8 | },
9 | "license": "CC BY-NC-SA-4.0",
10 | "author": "Jisu Park ",
11 | "files": [
12 | "/ethereum/*",
13 | "/yarn.lock"
14 | ],
15 | "main": "index.js",
16 | "bugs": "https://github.com/soohoio/sooho/issues",
17 | "publishConfig": {
18 | "access": "public"
19 | },
20 | "keywords": [
21 | "SOOHO",
22 | "security",
23 | "contract",
24 | "solidity",
25 | "ethereum",
26 | "vulnerability"
27 | ],
28 | "dependencies": {
29 | "js-yaml": "^3.12.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/sooho-advisory-db/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | argparse@^1.0.7:
6 | version "1.0.10"
7 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
8 | dependencies:
9 | sprintf-js "~1.0.2"
10 |
11 | esprima@^4.0.0:
12 | version "4.0.1"
13 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
14 |
15 | js-yaml@^3.12.0:
16 | version "3.12.0"
17 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
18 | dependencies:
19 | argparse "^1.0.7"
20 | esprima "^4.0.0"
21 |
22 | sprintf-js@~1.0.2:
23 | version "1.0.3"
24 | resolved "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
25 |
--------------------------------------------------------------------------------
/packages/sooho-cli/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
--------------------------------------------------------------------------------
/packages/sooho-cli/.gitignore:
--------------------------------------------------------------------------------
1 | *-debug.log
2 | *-error.log
3 | /.nyc_output
4 | /dist
5 | /lib
6 | /oclif.manifest.json
7 | /tmp
8 | node_modules
9 | *.aegis
10 | /*.sol
11 |
--------------------------------------------------------------------------------
/packages/sooho-cli/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.3.4](https://github.com/soohoio/sooho/compare/v0.3.3...v0.3.4) (2020-04-28)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **lerna:** track package-lock.json on git ([9efd395](https://github.com/soohoio/sooho/commit/9efd395fe8e3b5acf55f676c9a96036b1f457dca))
12 | * **util:** remove unused parameter in parse-files ([9591425](https://github.com/soohoio/sooho/commit/95914254effaf9e576f23d9f4a0e8c0aba7d2941))
13 |
14 |
15 | ### Features
16 |
17 | * **cli:** add command for generating advisory db ([faaadba](https://github.com/soohoio/sooho/commit/faaadba564401bc9cbef8460a219f45feb3b181c))
18 | * **signature:** update signature generation logic ([5173827](https://github.com/soohoio/sooho/commit/517382715617af124864d93e460869daf5e8d36f))
19 |
20 |
21 |
22 |
23 |
24 | ## [0.3.3](https://github.com/soohoio/sooho/compare/v0.3.1...v0.3.3) (2018-12-19)
25 |
26 |
27 | ### Bug Fixes
28 |
29 | * **advisory-db:** Fix demo version of cli audit and add test files ([624ba74](https://github.com/soohoio/sooho/commit/624ba74))
30 | * **config:** Change lerna config to versioning in release branch ([df6cb16](https://github.com/soohoio/sooho/commit/df6cb16))
31 | * **package:** Add dependent libary ([abc65c3](https://github.com/soohoio/sooho/commit/abc65c3))
32 |
33 |
34 | ### Features
35 |
36 | * **advisory:** Add new package [@sooho](https://github.com/sooho)/sooho-advisory-db ([941d518](https://github.com/soohoio/sooho/commit/941d518))
37 |
38 |
39 |
40 |
41 |
42 | ## [0.3.2](https://github.com/soohoio/sooho/compare/v0.3.1...v0.3.2) (2018-12-19)
43 |
44 |
45 | ### Bug Fixes
46 |
47 | * **advisory-db:** Fix demo version of cli audit and add test files ([624ba74](https://github.com/soohoio/sooho/commit/624ba74))
48 |
49 |
50 | ### Features
51 |
52 | * **advisory:** Add new package [@sooho](https://github.com/sooho)/sooho-advisory-db ([941d518](https://github.com/soohoio/sooho/commit/941d518))
53 |
54 |
55 |
56 |
57 |
58 | ## [0.3.1](https://github.com/soohoio/sooho/compare/v0.3.0...v0.3.1) (2018-12-16)
59 |
60 |
61 | ### Features
62 |
63 | * **lines:** Add fileinfo details ([c2194cc](https://github.com/soohoio/sooho/commit/c2194cc))
64 |
65 |
66 |
67 |
68 |
69 | ## [0.3.1](https://github.com/soohoio/sooho/compare/v0.3.0...v0.3.1) (2018-12-16)
70 |
71 |
72 | ### Features
73 |
74 | * **lines:** Add fileinfo details ([c2194cc](https://github.com/soohoio/sooho/commit/c2194cc))
75 |
76 |
77 |
78 |
79 |
80 | # [0.3.0](https://github.com/soohoio/sooho/compare/v0.2.0...v0.3.0) (2018-12-16)
81 |
82 |
83 | ### Features
84 |
85 | * **recursive:** Support spinner with recursive ([82dbf37](https://github.com/soohoio/sooho/commit/82dbf37))
86 |
87 |
88 |
89 |
90 |
91 | # [0.2.0](https://github.com/soohoio/sooho/compare/v0.1.1...v0.2.0) (2018-10-16)
92 |
93 |
94 | ### Features
95 |
96 | * **macos:** Support auto-update with macos installer ([bb363f1](https://github.com/soohoio/sooho/commit/bb363f1))
97 |
98 |
99 |
100 |
101 |
102 | ## [0.1.1](https://github.com/soohoio/sooho/compare/v0.1.0...v0.1.1) (2018-10-16)
103 |
104 |
105 | ### Features
106 |
107 | * **readme:** Support save options ([37f6ec3](https://github.com/soohoio/sooho/commit/37f6ec3))
108 |
109 |
110 |
111 |
112 |
113 | # [0.1.0](https://github.com/soohoio/sooho/compare/v0.0.2-alpha.0...v0.1.0) (2018-10-15)
114 |
115 |
116 | ### Code Refactoring
117 |
118 | * **encrypt:** Change output format ([3ab87dc](https://github.com/soohoio/sooho/commit/3ab87dc))
119 |
120 |
121 | ### BREAKING CHANGES
122 |
123 | * **encrypt:** JSON string format changed
124 |
--------------------------------------------------------------------------------
/packages/sooho-cli/README.md:
--------------------------------------------------------------------------------
1 | @sooho/cli
2 | ==========
3 |
4 | CLI tool to interact with Sooho
5 |
6 | [](https://npmjs.org/package/@sooho/cli)
7 | [](https://npmjs.org/package/@sooho/cli)
8 | [](https://github.com/soohoio/sooho/blob/master/package.json)
9 |
10 | * [Usage](#usage)
11 | * [Commands](#commands)
12 |
13 | # Usage
14 |
15 | ```sh-session
16 | $ npm install -g @sooho/cli
17 | $ sooho COMMAND
18 | running command...
19 | $ sooho (-v|--version|version)
20 | @sooho/cli/0.0.2-alpha.0 darwin-x64 node-v9.11.1
21 | $ sooho --help [COMMAND]
22 | USAGE
23 | $ sooho COMMAND
24 | ...
25 | ```
26 |
27 | # Commands
28 |
29 | * [`sooho encrypt INPUT_PATH`](#sooho-encrypt-input-path)
30 | * [`sooho audit INPUT_PATH`](#sooho-audit-input-path)
31 | * [`sooho help [COMMAND]`](#sooho-help-command)
32 |
33 | ## `sooho encrypt INPUT_PATH`
34 |
35 | Encrypt source code into hash file
36 |
37 | ```
38 | USAGE
39 | $ sooho encrypt INPUT_PATH
40 |
41 | ARGUMENTS
42 | INPUT_PATH entry path
43 |
44 | OPTIONS
45 | -a, --abstract turn on abstraction mode
46 | -s, --save save encrypted file
47 | -h, --help show CLI help
48 |
49 | EXAMPLE
50 | $ sooho encrypt INPUT_PATH
51 | ```
52 |
53 | _See code: [src/commands/encrypt.ts](https://github.com/soohoio/sooho/blob/master/packages/sooho-cli/src/commands/encrypt.ts)
54 |
55 | ## `sooho audit INPUT_PATH`
56 |
57 | Audit smart contract
58 |
59 | ```
60 | USAGE
61 | $ sooho audit INPUT_PATH
62 |
63 | ARGUMENTS
64 | INPUT_PATH entry path
65 |
66 | EXAMPLE
67 | $ sooho audit INPUT_PATH
68 | ```
69 |
70 | _See code: [src/commands/audit.ts](https://github.com/soohoio/sooho/blob/master/packages/sooho-cli/src/commands/audit.ts)
71 |
72 | ## `sooho help [COMMAND]`
73 |
74 | display help for sooho
75 |
76 | ```
77 | USAGE
78 | $ sooho help [COMMAND]
79 |
80 | ARGUMENTS
81 | COMMAND command to show help for
82 |
83 | OPTIONS
84 | --all see all commands in CLI
85 | ```
86 |
87 | _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v2.1.3/src/commands/help.ts)
88 |
--------------------------------------------------------------------------------
/packages/sooho-cli/bin/run:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('@oclif/command').run()
4 | .then(require('@oclif/command/flush'))
5 | .catch(require('@oclif/errors/handle'))
6 |
--------------------------------------------------------------------------------
/packages/sooho-cli/bin/run.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | node "%~dp0\run" %*
4 |
--------------------------------------------------------------------------------
/packages/sooho-cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sooho/cli",
3 | "description": "CLI tool to interact with SOOHO",
4 | "version": "0.3.4",
5 | "author": "Jisu Park ",
6 | "bin": {
7 | "sooho": "./bin/run"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/soohoio/sooho"
12 | },
13 | "bugs": "https://github.com/soohoio/sooho/issues",
14 | "dependencies": {
15 | "@oclif/command": "^1",
16 | "@oclif/config": "^1",
17 | "@oclif/plugin-help": "^2.1.4",
18 | "@oclif/plugin-update": "^1.3.9",
19 | "@sooho/advisory-db": "^0.3.4",
20 | "@sooho/parser": "^0.3.4",
21 | "@types/diff": "^4.0.2",
22 | "cli-table": "^0.3.1",
23 | "diff": "^4.0.2",
24 | "ora": "^3.0.0",
25 | "powerwalker": "^0.1.0",
26 | "tslib": "^1",
27 | "yaml": "^1.9.2"
28 | },
29 | "devDependencies": {
30 | "@oclif/dev-cli": "^1",
31 | "@oclif/test": "^1",
32 | "@oclif/tslint": "^3",
33 | "@types/chai": "^4",
34 | "@types/mocha": "^5",
35 | "@types/node": "^10",
36 | "@types/yaml": "^1.9.7",
37 | "aws-sdk": "^2.335.0",
38 | "chai": "^4",
39 | "globby": "^8",
40 | "mocha": "^5",
41 | "nyc": "^13",
42 | "ts-node": "^7",
43 | "tslint": "^5",
44 | "typescript": "^3.0"
45 | },
46 | "engines": {
47 | "node": ">=8.3.0"
48 | },
49 | "files": [
50 | "/bin",
51 | "/lib",
52 | "/npm-shrinkwrap.json",
53 | "/oclif.manifest.json",
54 | "/yarn.lock"
55 | ],
56 | "homepage": "https://github.com/soohoio/sooho",
57 | "keywords": [
58 | "SOOHO",
59 | "security",
60 | "assessments",
61 | "contract",
62 | "solidity",
63 | "vulnerability"
64 | ],
65 | "license": "GPL-3.0",
66 | "main": "lib/index.js",
67 | "oclif": {
68 | "commands": "./lib/commands",
69 | "bin": "sooho",
70 | "plugins": [
71 | "@oclif/plugin-help",
72 | "@oclif/plugin-update"
73 | ],
74 | "update": {
75 | "s3": {
76 | "bucket": "sooho-cli-assets"
77 | },
78 | "node": {
79 | "version": "10.12.0"
80 | }
81 | },
82 | "macos": {
83 | "sign": "Developer ID Installer: Jisu Park",
84 | "identifier": "com.sooho.cli"
85 | }
86 | },
87 | "scripts": {
88 | "audit": "./bin/run audit",
89 | "postpack": "rm -f oclif.manifest.json",
90 | "posttest": "tslint -p test -t stylish",
91 | "prepack": "rm -rf lib && tsc -b && oclif-dev manifest && oclif-dev readme",
92 | "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"",
93 | "version": "oclif-dev readme && git add README.md"
94 | },
95 | "types": "lib/index.d.ts",
96 | "publishConfig": {
97 | "access": "public"
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/packages/sooho-cli/src/commands/audit.ts:
--------------------------------------------------------------------------------
1 | import {Command} from '@oclif/command'
2 | import {getAdvisoryDB} from '@sooho/advisory-db'
3 | import * as fs from 'fs'
4 | import * as ora from 'ora'
5 | import * as powerwalker from 'powerwalker'
6 | import * as Table from 'cli-table'
7 | import {promisify} from 'util'
8 | import {onlySolidity} from '../utils/filters'
9 | import {parseFiles} from '../utils/parse-files'
10 |
11 | export default class Audit extends Command {
12 | static description = 'Audit smart contract'
13 |
14 | static examples = [
15 | '$ sooho audit INPUT_PATH',
16 | ]
17 |
18 | static args = [{name: 'inputPath', required: true, description: 'entry path'}]
19 |
20 | async run() {
21 | const {args: {inputPath}} = this.parse(Audit)
22 |
23 | const spinner = ora({text: 'Parse files', spinner: 'dots'}).start()
24 | const lstat = promisify(fs.lstat)
25 | const stats = await lstat(inputPath)
26 | const routes = stats.isFile() ? [inputPath] : await powerwalker(inputPath)
27 | const filePaths = routes.filter(onlySolidity)
28 | const parsed = await parseFiles(filePaths)
29 | const {errors, success: {functions, constructors}} = parsed
30 |
31 | if (errors.length > 0) {
32 | if (functions.length > 0 || constructors.length > 0) {
33 | spinner.warn('Parse files')
34 | } else {
35 | spinner.fail('Parse files')
36 | }
37 | } else {
38 | spinner.succeed('Parse files')
39 | }
40 |
41 | let isSafe = true
42 | let vulns = []
43 | try {
44 | const signatures = functions.map(func => func.signature)
45 | const db = getAdvisoryDB()
46 |
47 | spinner.start('Checking vulnerabilities')
48 | db.forEach(cve => {
49 | if (signatures.indexOf(cve.signature) > 0) {
50 | isSafe = false
51 | vulns.push(cve)
52 | }
53 | })
54 |
55 | if (isSafe) {
56 | spinner.succeed('Done!')
57 | } else {
58 | const table = new Table({
59 | head: ['CVE ID', 'Type', 'Severity', 'Desc'],
60 | colWidths: [20, 10, 10, 50]
61 | })
62 |
63 | vulns.map(vul => table.push([
64 | vul.id,
65 | vul.vulnerability_type.swc,
66 | vul.severity,
67 | vul.description
68 | ]))
69 |
70 | spinner.fail('Vulnerabilities have detected!')
71 | this.log(table.toString())
72 | }
73 | } catch (e) {
74 | spinner.fail(e)
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/packages/sooho-cli/src/commands/encrypt.ts:
--------------------------------------------------------------------------------
1 | import {Command} from '@oclif/command'
2 | import * as fs from 'fs'
3 | import * as ora from 'ora'
4 | import * as path from 'path'
5 | import * as powerwalker from 'powerwalker'
6 | import {promisify} from 'util'
7 | import {onlySolidity} from '../utils/filters'
8 | import {abstract, help, save} from '../utils/flags'
9 | import {parseFiles} from '../utils/parse-files'
10 |
11 | export default class Encrypt extends Command {
12 | static description = 'Encrypt source code into hash file'
13 |
14 | static examples = [
15 | '$ sooho encrypt INPUT_PATH',
16 | ]
17 |
18 | static flags = {abstract, help, save}
19 | static args = [{name: 'inputPath', required: true, description: 'entry path'}]
20 |
21 | async run() {
22 | const {args: {inputPath}, flags: {abstract, save}} = this.parse(Encrypt)
23 |
24 | const spinner = ora({text: 'Parse files', spinner: 'dots'}).start()
25 | const lstat = promisify(fs.lstat)
26 | const stats = await lstat(inputPath)
27 | const routes = stats.isFile() ? [inputPath] : await powerwalker(inputPath)
28 | const filePaths = routes.filter(onlySolidity)
29 | const parsed = await parseFiles(filePaths)
30 | const {errors, success: {functions, constructors}} = parsed
31 |
32 | if (errors.length > 0) {
33 | if (functions.length > 0 || constructors.length > 0) {
34 | spinner.warn('Parse files')
35 | } else {
36 | spinner.fail('Parse files')
37 | }
38 | } else {
39 | spinner.succeed('Parse files')
40 | }
41 |
42 | const result = JSON.stringify(parsed, null, 4)
43 |
44 | if (save) {
45 | spinner.start('Saving results')
46 | const fileName = `${path.basename(inputPath).split('.sol')[0]}.aegis`
47 | fs.writeFile(fileName, result, err => {
48 | if (err) {
49 | this.error(err)
50 | return
51 | }
52 | spinner.succeed(`${fileName} has been created`)
53 | })
54 | } else {
55 | this.log(result)
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/sooho-cli/src/commands/generate-db.ts:
--------------------------------------------------------------------------------
1 | import {Command} from '@oclif/command'
2 | import {parseFiles} from '../utils/parse-files'
3 | import {promisify} from 'util'
4 | import * as path from 'path'
5 | import * as fs from 'fs'
6 | import * as Diff from 'diff'
7 | import * as YAML from 'yaml'
8 | import * as ora from 'ora'
9 |
10 | export default class GenerateDB extends Command {
11 | static description = 'Generate advisory db'
12 |
13 | static examples = [
14 | '$ sooho generate ORIGIN_SOL_FILE_PATH PATCHED_SOL_FILE_PATH OUTPUT_FILE_PATH',
15 | ]
16 |
17 | static args = [{
18 | name: 'originFilePath',
19 | required: true,
20 | description: 'Original vulnerable solidity file path'
21 | }, {
22 | name: 'patchedFilePath',
23 | required: true,
24 | description: 'Patched safe solidity file path'
25 | }, {
26 | name: 'outputFilePath',
27 | required: true,
28 | description: 'File path to generate yaml file will be located at'
29 | }]
30 |
31 | async run() {
32 | const readFile = promisify(fs.readFile)
33 | const writeFile = promisify(fs.writeFile)
34 |
35 | const {args: {originFilePath, patchedFilePath, outputFilePath}} = this.parse(GenerateDB)
36 | const spinner = ora({spinner: 'dots'})
37 | const originFileName = path.basename(originFilePath, '.sol')
38 |
39 | spinner.start('Parse files')
40 | const parseResult = await parseFiles([originFilePath, patchedFilePath])
41 | if (parseResult.errors.length) {
42 | spinner.fail('Parse files')
43 | } else {
44 | spinner.succeed('Parse files')
45 | }
46 |
47 | const originFile = await readFile(originFilePath)
48 | const patchFile = await readFile(patchedFilePath)
49 |
50 | const functions = parseResult.success.functions
51 | const funcsInOrigin = functions.filter(f => f.filePathIdx === 0)
52 | const funcsInPatch = functions.filter(f => f.filePathIdx === 1)
53 |
54 | // filter patched function only
55 | const patchedFuncs = funcsInPatch.map(f => {
56 | const { signature, contractName } = f
57 | const matchedFunc = funcsInOrigin.find(fo => fo.contractName === contractName && fo.signature === signature)
58 | if (matchedFunc) {
59 | return null
60 | }
61 | return f.functionName
62 | }).filter(f => f)
63 |
64 | spinner.start('Generate advisory db')
65 | const generateYaml = await patchedFuncs.map(async funcName => {
66 | // get original function body
67 | const originFunc = funcsInOrigin.find(f => f.functionName === funcName)
68 | const { startLine: originStart, endLine: originEnd } = originFunc.loc
69 | const originFileBody = originFile.toString()
70 | const originFuncBody = originFileBody.split('\n').slice(originStart-1, originEnd).join('\n')
71 |
72 | // get patched function body
73 | const patchFunc = funcsInPatch.find(f => f.functionName === funcName)
74 | const { startLine: patchStart, endLine: patchEnd } = patchFunc.loc
75 | const patchFileBody = patchFile.toString()
76 | const patchFuncBody = patchFileBody.split('\n').slice(patchStart-1, patchEnd).join('\n')
77 |
78 | // get vulnerable function's signature
79 | const { signature } = originFunc
80 |
81 | // generate patch information
82 | const diff = Diff.diffLines(originFuncBody, patchFuncBody)
83 | let patch = ''
84 | diff.forEach(d => {
85 | if (d.added || d.removed) {
86 | const dSlice = d.value.split('\n')
87 | dSlice.forEach(ds => patch += d.added ? `+${ds}\n` : `-${ds}\n`)
88 | } else {
89 | patch += d.value
90 | }
91 | })
92 |
93 | // yaml format with dummy infos, signature & patch info
94 | const yaml = {
95 | id: '',
96 | title: '',
97 | description: '',
98 | references: ['', ''],
99 | credits: '',
100 | vulnerability_type: {
101 | cwe: '',
102 | swc: '',
103 | },
104 | severity: 0.0,
105 | affected: {
106 | contractName: '',
107 | address: '',
108 | },
109 | signature,
110 | patch,
111 | }
112 |
113 | // write yaml file into disk
114 | await writeFile(`${outputFilePath}/${originFileName}-${funcName}.yml`, YAML.stringify(yaml))
115 | this.log(`\nadvisory-db for function ${funcName} is generated at ${outputFilePath}/${originFileName}-${funcName}.yml`)
116 | })
117 |
118 | await Promise.all(generateYaml)
119 | spinner.succeed('Generate advisory db')
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/packages/sooho-cli/src/index.ts:
--------------------------------------------------------------------------------
1 | export {run} from '@oclif/command'
2 |
--------------------------------------------------------------------------------
/packages/sooho-cli/src/utils/filters.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path'
2 |
3 | export const onlySolidity = filePath => path.extname(filePath) === '.sol'
4 |
--------------------------------------------------------------------------------
/packages/sooho-cli/src/utils/flags.ts:
--------------------------------------------------------------------------------
1 | import {flags} from '@oclif/command'
2 |
3 | export const abstract = flags.boolean({
4 | char: 'a',
5 | description: 'turn on abstraction mode',
6 | default: false
7 | })
8 |
9 | export const help = flags.boolean({
10 | char: 'h',
11 | description: 'show CLI help'
12 | })
13 |
14 | export const save = flags.boolean({
15 | char: 's',
16 | description: 'save encrypted result',
17 | default: false
18 | })
19 |
--------------------------------------------------------------------------------
/packages/sooho-cli/test/commands/Test/Test.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.21;
2 |
3 | contract Test {
4 | struct TodoItem {
5 | bool isActive;
6 | string text;
7 | }
8 |
9 | event LogHello();
10 |
11 | modifier simple(uint test, string tmp) {
12 | _;
13 | }
14 |
15 | TodoItem[] public todos;
16 |
17 | function length() external view simple(5, 'sasd') returns (uint) {
18 | emit LogHello();
19 | return todos.length;
20 | }
21 |
22 | function addTodo(bool _isActive, string _text) public {
23 | TodoItem memory todo = TodoItem(_isActive, _text);
24 | todos.push(todo);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/sooho-cli/test/commands/Vulnerable.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.23;
2 |
3 | library SafeMath {
4 | function mul(uint256 a, uint256 b) internal pure returns (uint256) {
5 | if (a == 0) {
6 | return 0;
7 | }
8 | uint256 c = a * b;
9 | assert(c / a == b);
10 | return c;
11 | }
12 | function div(uint256 a, uint256 b) internal pure returns (uint256) {
13 | // assert(b > 0); // Solidity automatically throws when dividing by 0
14 | uint256 c = a / b;
15 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold
16 | return c;
17 | }
18 | function sub(uint256 a, uint256 b) internal pure returns (uint256) {
19 | assert(b <= a);
20 | return a - b;
21 | }
22 | function add(uint256 a, uint256 b) internal pure returns (uint256) {
23 | uint256 c = a + b;
24 | assert(c >= a);
25 | return c;
26 | }
27 | }
28 |
29 | contract Ownable {
30 | address public owner;
31 |
32 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
33 |
34 | constructor() public {
35 | owner = msg.sender;
36 | }
37 | modifier onlyOwner() {
38 | require(msg.sender == owner);
39 | _;
40 | }
41 | function transferOwnership(address newOwner) public onlyOwner {
42 | require(newOwner != address(0));
43 | emit OwnershipTransferred(owner, newOwner);
44 | owner = newOwner;
45 | }
46 |
47 | }
48 |
49 | contract Lottery is Ownable {
50 | using SafeMath for uint256;
51 | address[] private players;
52 | address[] public winners;
53 | uint256[] public payments;
54 | uint256 private feeValue;
55 | address public lastWinner;
56 | address[] private last10Winners = [0,0,0,0,0,0,0,0,0,0];
57 | uint256 public lastPayOut;
58 | uint256 public amountRised;
59 | address public house;
60 | uint256 public round;
61 | uint256 public playValue;
62 | uint256 public roundEnds;
63 | bool public stopped;
64 | mapping (address => uint256) public payOuts;
65 | uint256 private _seed;
66 |
67 |
68 | function bitSlice(uint256 n, uint256 bits, uint256 slot) private pure returns(uint256) {
69 | uint256 offset = slot * bits;
70 | uint256 mask = uint256((2**bits) - 1) << offset;
71 | return uint256((n & mask) >> offset);
72 | }
73 |
74 | function maxRandom() private returns (uint256 randomNumber) {
75 | _seed = uint256(keccak256(_seed, blockhash(block.number - 1), block.coinbase, block.difficulty));
76 | return _seed;
77 | }
78 |
79 |
80 | function random(uint256 upper) private returns (uint256 randomNumber) {
81 | return maxRandom() % upper;
82 | }
83 |
84 | function setHouseAddress(address _house) onlyOwner public {
85 | house = _house;
86 | }
87 |
88 | function setFee(uint256 _fee) onlyOwner public {
89 | feeValue = _fee;
90 | }
91 |
92 | function setPlayValue(uint256 _amount) onlyOwner public {
93 | playValue = _amount;
94 | }
95 |
96 | function stopLottery(bool _stop) onlyOwner public {
97 | stopped = _stop;
98 | }
99 |
100 | function produceRandom(uint256 upper) private returns (uint256) {
101 | uint256 rand = random(upper);
102 | //output = rand;
103 | return rand;
104 | }
105 |
106 | function getPayOutAmount() private view returns (uint256) {
107 | //uint256 balance = address(this).balance;
108 | uint256 fee = amountRised.mul(feeValue).div(100);
109 | return (amountRised - fee);
110 | }
111 |
112 | function draw() public {
113 | require(now > roundEnds);
114 | uint256 howMuchBets = players.length;
115 | uint256 k;
116 | lastWinner = players[produceRandom(howMuchBets)];
117 | lastPayOut = getPayOutAmount();
118 |
119 | winners.push(lastWinner);
120 | if (winners.length > 9) {
121 | for (uint256 i = (winners.length - 10); i < winners.length; i++) {
122 | last10Winners[k] = winners[i];
123 | k += 1;
124 | }
125 | }
126 |
127 | payments.push(lastPayOut);
128 | payOuts[lastWinner] += lastPayOut;
129 | lastWinner.transfer(lastPayOut);
130 |
131 | players.length = 0;
132 | round += 1;
133 | amountRised = 0;
134 | roundEnds = now + (1 * 1 days);
135 |
136 | emit NewWinner(lastWinner, lastPayOut);
137 | }
138 |
139 | function play() payable public {
140 | require (msg.value == playValue);
141 | require (!stopped);
142 | if (players.length == 0) {
143 | roundEnds = now + (1 * 1 days);
144 | }
145 | if (now > roundEnds) {
146 | draw();
147 | }
148 | players.push(msg.sender);
149 | amountRised = amountRised.add(msg.value);
150 | }
151 |
152 | function() payable public {
153 | play();
154 | }
155 |
156 | constructor() public {
157 | house = msg.sender;
158 | feeValue = 5;
159 | playValue = 1 finney;
160 | }
161 |
162 | function getBalance() onlyOwner public {
163 | uint256 thisBalance = address(this).balance;
164 | house.transfer(thisBalance);
165 | }
166 |
167 | function getPlayersCount() public view returns (uint256) {
168 | return players.length;
169 | }
170 |
171 | function getWinnerCount() public view returns (uint256) {
172 | return winners.length;
173 | }
174 |
175 | function getPlayers() public view returns (address[]) {
176 | return players;
177 | }
178 |
179 | function last10() public view returns (address[]) {
180 | if (winners.length < 11) {
181 | return winners;
182 | } else {
183 | return last10Winners;
184 | }
185 | }
186 | event NewWinner(address _winner, uint256 _amount);
187 | event Conso(uint a, uint b);
188 | }
189 |
--------------------------------------------------------------------------------
/packages/sooho-cli/test/commands/audit.test.ts:
--------------------------------------------------------------------------------
1 | import {expect, test} from '@oclif/test'
2 |
3 | describe('audit', () => {
4 | test
5 | .stdout()
6 | .stderr()
7 | .command(['audit', 'test/commands/Vulnerable.sol'])
8 | .it('parse file', ctx => {
9 | expect(ctx.stderr.includes('Parse files')).to.equal(true)
10 | })
11 |
12 | test
13 | .stdout()
14 | .stderr()
15 | .command(['audit', 'test/commands/Vulnerable.sol'])
16 | .it('detect vulnerabilities', ctx => {
17 | expect(ctx.stderr.includes('Vulnerabilities have detected!')).to.equal(true)
18 | expect(ctx.stdout).to.equal([
19 | '┌────────────────────┬──────────┬──────────┬──────────────────────────────────────────────────┐',
20 | '│ CVE ID │ Type │ Severity │ Desc │',
21 | '├────────────────────┼──────────┼──────────┼──────────────────────────────────────────────────┤',
22 | '│ CVE-2018-12056 │ SWC-120 │ 7.5 │ The maxRandom function of a smart contract impl… │',
23 | '│ │ │ │ │',
24 | '└────────────────────┴──────────┴──────────┴──────────────────────────────────────────────────┘',
25 | ''
26 | ].join('\n'))
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/packages/sooho-cli/test/commands/encrypt.test.ts:
--------------------------------------------------------------------------------
1 | import {expect, test} from '@oclif/test'
2 |
3 | describe('encrypt', () => {
4 | test
5 | .stdout()
6 | .stderr()
7 | .command(['encrypt', 'test/commands/Test/Test.sol'])
8 | .it('accepts file', ctx => {
9 | const result = JSON.parse(ctx.stdout)
10 |
11 | expect(result).to.deep.equal({
12 | version: '0.3.0',
13 | errors: [],
14 | success: {
15 | constructors: [],
16 | functions: [{
17 | filePathIdx: 0,
18 | loc: {
19 | endLine: 20,
20 | startLine: 17
21 | },
22 | signature: "c1804baf32d7f6c23426803ffd8d9456"
23 | }, {
24 | filePathIdx: 0,
25 | loc: {
26 | endLine: 25,
27 | startLine: 22
28 | },
29 | signature: "5e3c146b68293fe4808f0dd8c1a88c8d"
30 | }
31 | ]},
32 | fileInfo: {
33 | files: [{
34 | filePath: "test/commands/Test/Test.sol",
35 | lines: 26
36 | }],
37 | totalFiles: 1,
38 | totalLines: 26,
39 | totalSigns: 2
40 | }
41 | })
42 | })
43 |
44 | test
45 | .stdout()
46 | .stderr()
47 | .command(['encrypt', 'test/commands/Test'])
48 | .it('accepts folder', ctx => {
49 | const result = JSON.parse(ctx.stdout)
50 |
51 | expect(result).to.deep.equal({
52 | version: '0.3.0',
53 | errors: [],
54 | success: {
55 | constructors: [],
56 | functions: [{
57 | filePathIdx: 0,
58 | loc: {
59 | endLine: 20,
60 | startLine: 17
61 | },
62 | signature: "c1804baf32d7f6c23426803ffd8d9456"
63 | }, {
64 | filePathIdx: 0,
65 | loc: {
66 | endLine: 25,
67 | startLine: 22
68 | },
69 | signature: "5e3c146b68293fe4808f0dd8c1a88c8d"
70 | }
71 | ]},
72 | fileInfo: {
73 | files: [{
74 | filePath: "test/commands/Test/Test.sol",
75 | lines: 26
76 | }],
77 | totalFiles: 1,
78 | totalLines: 26,
79 | totalSigns: 2
80 | }
81 | })
82 | })
83 | })
84 |
--------------------------------------------------------------------------------
/packages/sooho-cli/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --require ts-node/register
2 | --watch-extensions ts
3 | --recursive
4 | --reporter spec
5 | --timeout 5000
6 |
--------------------------------------------------------------------------------
/packages/sooho-cli/test/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig",
3 | "compilerOptions": {
4 | "noEmit": true
5 | },
6 | "references": [
7 | {"path": ".."}
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/sooho-cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "importHelpers": true,
5 | "module": "commonjs",
6 | "outDir": "lib",
7 | "rootDir": "src",
8 | "strict": false,
9 | "target": "es2017",
10 | "composite": true
11 | },
12 | "include": [
13 | "src/**/*"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/sooho-cli/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@oclif/tslint",
3 | "rules": {
4 | "ordered-imports": false,
5 | "no-console": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/sooho-flattener/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "commonjs": true,
4 | "es6": true,
5 | "node": true
6 | },
7 | "extends": "eslint:recommended",
8 | "globals": {
9 | "Atomics": "readonly",
10 | "SharedArrayBuffer": "readonly"
11 | },
12 | "parserOptions": {
13 | "ecmaVersion": 2018
14 | },
15 | "rules": {
16 | "no-console": [
17 | "error",
18 | {
19 | "allow": [
20 | "warn",
21 | "error"
22 | ]
23 | }
24 | ],
25 | "indent": [
26 | "error",
27 | 2
28 | ],
29 | "linebreak-style": [
30 | "error",
31 | "unix"
32 | ],
33 | "quotes": [
34 | "error",
35 | "double"
36 | ],
37 | "semi": [
38 | "error",
39 | "always"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/sooho-flattener/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/packages/sooho-flattener/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.3.4](https://github.com/soohoio/sooho/compare/v0.3.3...v0.3.4) (2020-04-28)
7 |
8 |
9 | ### Features
10 |
11 | * **flattener:** Add new package @sooho/sooho-flattener ([497cd7f](https://github.com/soohoio/sooho/commit/497cd7f09b7fc0776b0fd0c2df5e128e8c8e7323))
12 |
--------------------------------------------------------------------------------
/packages/sooho-flattener/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sooho/flattener",
3 | "version": "0.3.4",
4 | "description": "Flatten solidity files",
5 | "main": "index.js",
6 | "scripts": {
7 | "eslint": "eslint src"
8 | },
9 | "author": "Sanggu Han ",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/soohoio/sooho"
13 | },
14 | "bugs": "https://github.com/soohoio/sooho/issues",
15 | "homepage": "https://github.com/soohoio/sooho",
16 | "license": "GPL-3.0",
17 | "dependencies": {
18 | "find-node-modules": "^2.0.0",
19 | "semver": "^6.0.0",
20 | "solidity-parser-antlr": "^0.4.2"
21 | },
22 | "private": true,
23 | "devDependencies": {
24 | "eslint": "^5.16.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/sooho-flattener/src/flattener.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require("fs");
4 | const path = require("path");
5 | const parser = require("solidity-parser-antlr");
6 | const process = require("process");
7 | const semver = require("semver");
8 | const findNodeModules = require("find-node-modules");
9 |
10 | class Graph {
11 | constructor() {
12 | this.node = {};
13 | }
14 |
15 | add(from, to) {
16 | if (!this.node[from]) {
17 | this.node[from] = [];
18 | }
19 |
20 | this.node[from].push(to);
21 | }
22 | }
23 |
24 | function resolvePath(baseDir, filePath) {
25 | let p = path.join(baseDir, filePath);
26 | p = path.normalize(p);
27 | if (fs.existsSync(p)) {
28 | return p;
29 | } else {
30 | const nodeModules = findNodeModules();
31 | for (let nodeModule of nodeModules) {
32 | let m = path.join(nodeModule, filePath);
33 | if (fs.existsSync(m)) {
34 | return m;
35 | }
36 | }
37 | throw new Error(`module path, ${filePath} is not found`);
38 | }
39 | }
40 |
41 | function getInfo(filePath) {
42 | let content = fs.readFileSync(filePath, "utf8");
43 |
44 | // get ast with solidity parser
45 | let ast = parser.parse(content);
46 | let imports = [];
47 | let version;
48 |
49 | // parse import paths in file
50 | parser.visit(ast, {
51 | ImportDirective: function(node) {
52 | /*
53 | * path - import path
54 | * unitAlias / symbolAliases - maybe i can use later
55 | */
56 | imports.push(node.path);
57 | },
58 | PragmaDirective: function(node) {
59 | /*
60 | * value - version sepcified in current file
61 | */
62 | version = node.value;
63 | }
64 | });
65 |
66 | return {
67 | imports: imports,
68 | version: version
69 | };
70 | }
71 |
72 | async function getVersion(versions) {
73 | let caret = [];
74 | let pinned = [];
75 | // unique & group
76 | [...new Set(versions)].forEach(version => {
77 | if (version.includes("^")) {
78 | caret.push(version.substring(1));
79 | } else {
80 | pinned.push(version);
81 | }
82 | });
83 |
84 | let version = "";
85 | if (caret.length) {
86 | version = "^" + caret.reduce((a, b) => semver.gt(a, b) ? a : b);
87 | }
88 |
89 | if (pinned.length) {
90 | version = pinned.reduce((a, b) => semver.gt(a, b) ? a : b);
91 | }
92 |
93 | return version;
94 | }
95 |
96 | async function flatten(filePath, baseDir, log) {
97 | let visited = [];
98 | let order = [];
99 | let versions = [];
100 | let graph = new Graph();
101 |
102 | let target = path.resolve(filePath);
103 | baseDir = path.resolve(baseDir);
104 |
105 | // topological sorting of import graph, cutting cycles
106 | const toposort = async curr => {
107 | visited.push(curr);
108 |
109 | let info = getInfo(curr);
110 | versions.push(info.version);
111 |
112 | for (let dep of info.imports) {
113 | dep = resolvePath(baseDir, dep);
114 | graph.add(curr, dep);
115 | if (!visited.includes(dep)) {
116 | await toposort(dep);
117 | }
118 | }
119 |
120 | order.push(curr);
121 | };
122 |
123 | await toposort(target);
124 |
125 | let version = await getVersion(versions);
126 |
127 | log("pragma solidity " + version + ";\n");
128 |
129 | const PRAGAMA_SOLIDITY_VERSION_REGEX = /^\s*pragma\ssolidity\s+(.*?)\s*;/m;
130 | const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+).*$/gm;
131 |
132 | for (let p of order) {
133 | let content = fs.readFileSync(p, "utf8");
134 | let pure = content
135 | .replace(PRAGAMA_SOLIDITY_VERSION_REGEX, "")
136 | .replace(IMPORT_SOLIDITY_REGEX, "");
137 | log("\n\n" + pure.trim());
138 | }
139 | }
140 |
141 | async function main(args) {
142 | try {
143 | let ret = "";
144 | await flatten(args[0], args[1], str => (ret += str));
145 | return ret;
146 | } catch(err) {
147 | console.error(err);
148 | }
149 | }
150 |
151 | if (require.main == module) {
152 | main(process.argv.slice(2));
153 | }
154 |
155 | module.exports = async function(filePath, baseDir) {
156 | try {
157 | let ret = "";
158 | await flatten(filePath, baseDir, str => (ret += str));
159 | return ret;
160 | } catch(err) {
161 | console.error(err);
162 | }
163 | };
164 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 |
9 | [*.js]
10 | indent_style = space
11 | indent_size = 2
12 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["standard"],
3 | "plugins": [
4 | "standard",
5 | "promise"
6 | ],
7 | "rules": {
8 | "no-var": 2,
9 | "object-curly-spacing": [2, "always"],
10 | "object-shorthand": 2,
11 | "prefer-const": 2,
12 | "max-len": 2
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .nyc_output/
3 | dist/
4 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "solidity-antlr4"]
2 | path = solidity-antlr4
3 | url = https://github.com/solidityj/solidity-antlr4
4 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | scripts/
3 | .nyc_output/
4 | solidity-antlr4/
5 |
--------------------------------------------------------------------------------
/packages/sooho-parser/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 |
--------------------------------------------------------------------------------
/packages/sooho-parser/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.3.4](https://github.com/soohoio/sooho/compare/v0.3.3...v0.3.4) (2020-04-28)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **lerna:** track package-lock.json on git ([9efd395](https://github.com/soohoio/sooho/commit/9efd395fe8e3b5acf55f676c9a96036b1f457dca))
12 | * **parser:** inject space between tokens @ getText ([622e9e1](https://github.com/soohoio/sooho/commit/622e9e11c6924bffc578fb73afdbe132a49b1b78))
13 | * **parser:** relative path to token def. file ([36671a5](https://github.com/soohoio/sooho/commit/36671a52ef9c9409a410027920f45812c9660155))
14 |
15 |
16 |
17 |
18 |
19 | # [0.3.0](https://github.com/soohoio/sooho/compare/v0.2.0...v0.3.0) (2018-12-16)
20 |
21 |
22 | ### Features
23 |
24 | * **recursive:** Support spinner with recursive ([82dbf37](https://github.com/soohoio/sooho/commit/82dbf37))
25 |
26 |
27 |
28 |
29 |
30 | # [0.2.0](https://github.com/soohoio/sooho/compare/v0.1.1...v0.2.0) (2018-10-16)
31 |
32 | **Note:** Version bump only for package @sooho/parser
33 |
34 |
35 |
36 |
37 |
38 | ## [0.1.1](https://github.com/soohoio/sooho/compare/v0.1.0...v0.1.1) (2018-10-16)
39 |
40 |
41 | ### Features
42 |
43 | * **readme:** Support save options ([37f6ec3](https://github.com/soohoio/sooho/commit/37f6ec3))
44 |
45 |
46 |
47 |
48 |
49 | # [0.1.0](https://github.com/soohoio/sooho/compare/v0.0.2-alpha.0...v0.1.0) (2018-10-15)
50 |
51 |
52 | ### Code Refactoring
53 |
54 | * **encrypt:** Change output format ([3ab87dc](https://github.com/soohoio/sooho/commit/3ab87dc))
55 |
56 |
57 | ### BREAKING CHANGES
58 |
59 | * **encrypt:** JSON string format changed
60 |
--------------------------------------------------------------------------------
/packages/sooho-parser/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Sooho 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 |
--------------------------------------------------------------------------------
/packages/sooho-parser/README.md:
--------------------------------------------------------------------------------
1 | @sooho/parser
2 | =====================
3 |
4 | This project is hardly forked from the federicobond's awesome project([solidity-parser-antlr/](https://github.com/federicobond/solidity-parser-antlr/))
5 |
6 | A Solidity parser built on top of a robust [ANTLR4 grammar](https://github.com/solidityj/solidity-antlr4).
7 |
8 | ### Usage
9 |
10 | ```javascript
11 | import parser from 'solidity-parser-antlr';
12 |
13 | var input = `
14 | contract test {
15 | uint256 a;
16 | function f() {}
17 | }
18 | `
19 | try {
20 | parser.parse(input)
21 | } catch (e) {
22 | if (e instanceof parser.ParserError) {
23 | console.log(e.errors)
24 | }
25 | }
26 | ```
27 |
28 | The `parse` method also accepts a second argument which lets you specify the
29 | following options, in a style similar to the _esprima_ API:
30 |
31 | | Key | Type | Default | Description |
32 | |----------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
33 | | tolerant | Boolean | false | When set to `true` it will collect syntax errors and place them in a list under the key `errors` inside the root node of the returned AST. Otherwise, it will raise a `parser.ParserError`. |
34 | | loc | Boolean | false | When set to `true`, it will add location information to each node, with start and stop keys that contain the corresponding line and column numbers. |
35 | | range | Boolean | false | When set to `true`, it will add range information to each node, which consists of a two-element array with start and stop character indexes in the input. |
36 |
37 |
38 | #### Example with location information
39 |
40 | ```javascript
41 | parser.parse('contract test { uint a; }', { loc: true })
42 |
43 | // { type: 'SourceUnit',
44 | // children:
45 | // [ { type: 'ContractDefinition',
46 | // name: 'test',
47 | // baseContracts: [],
48 | // subNodes: [Array],
49 | // kind: 'contract',
50 | // loc: [Object] } ],
51 | // loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 24 } } }
52 |
53 | ```
54 |
55 | #### Example using a visitor to walk over the AST
56 |
57 | ```javascript
58 | var ast = parser.parse('contract test { uint a; }')
59 |
60 | // output the path of each import found
61 | parser.visit(ast, {
62 | ImportDirective: function(node) {
63 | console.log(node.path)
64 | }
65 | })
66 | ```
67 |
68 | ### Author
69 |
70 | Jisu Park ([@jisupark](https://github.com/jisupark))
71 |
72 | And thanks to Federico Bond ([@federicobond](https://github.com/federicobond)) for the previous projects
73 |
74 | ### License
75 |
76 | MIT
77 |
--------------------------------------------------------------------------------
/packages/sooho-parser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sooho/parser",
3 | "version": "0.3.4",
4 | "description": "A Solidity parser forked from federicobond/solidity-parser-antlr",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "antlr4": "sh scripts/antlr4.sh",
8 | "build": "rm -rf dist && babel --out-dir=dist src --copy-files",
9 | "prepublishOnly": "yarn build",
10 | "prettier": "find src -name *.js | egrep -v '^src/(lib|antlr4)/' | xargs prettier --no-semi --single-quote --write",
11 | "eslint": "eslint src",
12 | "test": "nyc mocha"
13 | },
14 | "author": "Jisu Park ",
15 | "homepage": "https://github.com/soohoio/sooho",
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/soohoio/sooho.git"
19 | },
20 | "license": "MIT",
21 | "devDependencies": {
22 | "babel-cli": "^6.26.0",
23 | "babel-preset-env": "^1.7.0",
24 | "chai": "^4.0.2",
25 | "eslint": "^4.0.0",
26 | "eslint-config-standard": "^10.2.1",
27 | "eslint-plugin-import": "^2.3.0",
28 | "eslint-plugin-node": "^5.0.0",
29 | "eslint-plugin-promise": "^3.5.0",
30 | "eslint-plugin-standard": "^3.0.1",
31 | "mocha": "^5.2.0",
32 | "nyc": "^13.1.0",
33 | "prettier": "^1.4.4",
34 | "yarn": "^1.7.0"
35 | },
36 | "nyc": {
37 | "include": [
38 | "src/*.js"
39 | ]
40 | },
41 | "publishConfig": {
42 | "access": "public"
43 | },
44 | "dependencies": {
45 | "lodash": "^4.17.15"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/sooho-parser/scripts/antlr4.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | set -o errexit
4 |
5 | antlr4 -Dlanguage=JavaScript solidity-antlr4/Solidity.g4 -o lib
6 |
7 | mv lib/solidity-antlr4/* src/lib/
8 |
9 | rmdir lib/solidity-antlr4
10 |
11 | sed -i.bak -e 's/antlr4\/index/\.\.\/antlr4\/index/g' src/lib/*.js
12 |
13 | find src/lib -name '*.js.bak' -delete
14 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/ErrorListener.js:
--------------------------------------------------------------------------------
1 | const antlr4 = require('./antlr4/index')
2 |
3 | function ErrorListener() {
4 | antlr4.error.ErrorListener.call(this)
5 | this._errors = []
6 | }
7 |
8 | ErrorListener.prototype = Object.create(antlr4.error.ErrorListener.prototype)
9 | ErrorListener.prototype.constructor = ErrorListener
10 |
11 | ErrorListener.prototype.syntaxError = function(
12 | recognizer,
13 | offendingSymbol,
14 | line,
15 | column,
16 | message
17 | ) {
18 | this._errors.push({ message, line, column })
19 | }
20 |
21 | ErrorListener.prototype.getErrors = function() {
22 | return this._errors
23 | }
24 |
25 | ErrorListener.prototype.hasErrors = function() {
26 | return this._errors.length > 0
27 | }
28 |
29 | module.exports = ErrorListener
30 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/CharStreams.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | //
7 |
8 | var InputStream = require('./InputStream').InputStream;
9 |
10 | var isNodeJs = typeof window === 'undefined' && typeof importScripts === 'undefined';
11 | var fs = isNodeJs ? require("fs") : null;
12 |
13 | // Utility functions to create InputStreams from various sources.
14 | //
15 | // All returned InputStreams support the full range of Unicode
16 | // up to U+10FFFF (the default behavior of InputStream only supports
17 | // code points up to U+FFFF).
18 | var CharStreams = {
19 | // Creates an InputStream from a string.
20 | fromString: function(str) {
21 | return new InputStream(str, true);
22 | },
23 |
24 | // Asynchronously creates an InputStream from a blob given the
25 | // encoding of the bytes in that blob (defaults to 'utf8' if
26 | // encoding is null).
27 | //
28 | // Invokes onLoad(result) on success, onError(error) on
29 | // failure.
30 | fromBlob: function(blob, encoding, onLoad, onError) {
31 | var reader = FileReader();
32 | reader.onload = function(e) {
33 | var is = new InputStream(e.target.result, true);
34 | onLoad(is);
35 | };
36 | reader.onerror = onError;
37 | reader.readAsText(blob, encoding);
38 | },
39 |
40 | // Creates an InputStream from a Buffer given the
41 | // encoding of the bytes in that buffer (defaults to 'utf8' if
42 | // encoding is null).
43 | fromBuffer: function(buffer, encoding) {
44 | return new InputStream(buffer.toString(encoding), true);
45 | },
46 |
47 | // Asynchronously creates an InputStream from a file on disk given
48 | // the encoding of the bytes in that file (defaults to 'utf8' if
49 | // encoding is null).
50 | //
51 | // Invokes callback(error, result) on completion.
52 | fromPath: function(path, encoding, callback) {
53 | fs.readFile(path, encoding, function(err, data) {
54 | var is = null;
55 | if (data !== null) {
56 | is = new InputStream(data, true);
57 | }
58 | callback(err, is);
59 | });
60 | },
61 |
62 | // Synchronously creates an InputStream given a path to a file
63 | // on disk and the encoding of the bytes in that file (defaults to
64 | // 'utf8' if encoding is null).
65 | fromPathSync: function(path, encoding) {
66 | var data = fs.readFileSync(path, encoding);
67 | return new InputStream(data, true);
68 | }
69 | };
70 |
71 | exports.CharStreams = CharStreams;
72 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/CommonTokenFactory.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | //
7 |
8 | //
9 | // This default implementation of {@link TokenFactory} creates
10 | // {@link CommonToken} objects.
11 | //
12 |
13 | var CommonToken = require('./Token').CommonToken;
14 |
15 | function TokenFactory() {
16 | return this;
17 | }
18 |
19 | function CommonTokenFactory(copyText) {
20 | TokenFactory.call(this);
21 | // Indicates whether {@link CommonToken//setText} should be called after
22 | // constructing tokens to explicitly set the text. This is useful for cases
23 | // where the input stream might not be able to provide arbitrary substrings
24 | // of text from the input after the lexer creates a token (e.g. the
25 | // implementation of {@link CharStream//getText} in
26 | // {@link UnbufferedCharStream} throws an
27 | // {@link UnsupportedOperationException}). Explicitly setting the token text
28 | // allows {@link Token//getText} to be called at any time regardless of the
29 | // input stream implementation.
30 | //
31 | //
32 | // The default value is {@code false} to avoid the performance and memory
33 | // overhead of copying text for every token unless explicitly requested.
34 | //
35 | this.copyText = copyText===undefined ? false : copyText;
36 | return this;
37 | }
38 |
39 | CommonTokenFactory.prototype = Object.create(TokenFactory.prototype);
40 | CommonTokenFactory.prototype.constructor = CommonTokenFactory;
41 |
42 | //
43 | // The default {@link CommonTokenFactory} instance.
44 | //
45 | //
46 | // This token factory does not explicitly copy token text when constructing
47 | // tokens.
48 | //
49 | CommonTokenFactory.DEFAULT = new CommonTokenFactory();
50 |
51 | CommonTokenFactory.prototype.create = function(source, type, text, channel, start, stop, line, column) {
52 | var t = new CommonToken(source, type, channel, start, stop);
53 | t.line = line;
54 | t.column = column;
55 | if (text !==null) {
56 | t.text = text;
57 | } else if (this.copyText && source[1] !==null) {
58 | t.text = source[1].getText(start,stop);
59 | }
60 | return t;
61 | };
62 |
63 | CommonTokenFactory.prototype.createThin = function(type, text) {
64 | var t = new CommonToken(null, type);
65 | t.text = text;
66 | return t;
67 | };
68 |
69 | exports.CommonTokenFactory = CommonTokenFactory;
70 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/CommonTokenStream.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | ///
7 |
8 | //
9 | // This class extends {@link BufferedTokenStream} with functionality to filter
10 | // token streams to tokens on a particular channel (tokens where
11 | // {@link Token//getChannel} returns a particular value).
12 | //
13 | //
14 | // This token stream provides access to all tokens by index or when calling
15 | // methods like {@link //getText}. The channel filtering is only used for code
16 | // accessing tokens via the lookahead methods {@link //LA}, {@link //LT}, and
17 | // {@link //LB}.
18 | //
19 | //
20 | // By default, tokens are placed on the default channel
21 | // ({@link Token//DEFAULT_CHANNEL}), but may be reassigned by using the
22 | // {@code ->channel(HIDDEN)} lexer command, or by using an embedded action to
23 | // call {@link Lexer//setChannel}.
24 | //
25 | //
26 | //
27 | // Note: lexer rules which use the {@code ->skip} lexer command or call
28 | // {@link Lexer//skip} do not produce tokens at all, so input text matched by
29 | // such a rule will not be available as part of the token stream, regardless of
30 | // channel.
31 | ///
32 |
33 | var Token = require('./Token').Token;
34 | var BufferedTokenStream = require('./BufferedTokenStream').BufferedTokenStream;
35 |
36 | function CommonTokenStream(lexer, channel) {
37 | BufferedTokenStream.call(this, lexer);
38 | this.channel = channel===undefined ? Token.DEFAULT_CHANNEL : channel;
39 | return this;
40 | }
41 |
42 | CommonTokenStream.prototype = Object.create(BufferedTokenStream.prototype);
43 | CommonTokenStream.prototype.constructor = CommonTokenStream;
44 |
45 | CommonTokenStream.prototype.adjustSeekIndex = function(i) {
46 | return this.nextTokenOnChannel(i, this.channel);
47 | };
48 |
49 | CommonTokenStream.prototype.LB = function(k) {
50 | if (k===0 || this.index-k<0) {
51 | return null;
52 | }
53 | var i = this.index;
54 | var n = 1;
55 | // find k good tokens looking backwards
56 | while (n <= k) {
57 | // skip off-channel tokens
58 | i = this.previousTokenOnChannel(i - 1, this.channel);
59 | n += 1;
60 | }
61 | if (i < 0) {
62 | return null;
63 | }
64 | return this.tokens[i];
65 | };
66 |
67 | CommonTokenStream.prototype.LT = function(k) {
68 | this.lazyInit();
69 | if (k === 0) {
70 | return null;
71 | }
72 | if (k < 0) {
73 | return this.LB(-k);
74 | }
75 | var i = this.index;
76 | var n = 1; // we know tokens[pos] is a good one
77 | // find k good tokens
78 | while (n < k) {
79 | // skip off-channel tokens, but make sure to not look past EOF
80 | if (this.sync(i + 1)) {
81 | i = this.nextTokenOnChannel(i + 1, this.channel);
82 | }
83 | n += 1;
84 | }
85 | return this.tokens[i];
86 | };
87 |
88 | // Count EOF just once.///
89 | CommonTokenStream.prototype.getNumberOfOnChannelTokens = function() {
90 | var n = 0;
91 | this.fill();
92 | for (var i =0; i< this.tokens.length;i++) {
93 | var t = this.tokens[i];
94 | if( t.channel===this.channel) {
95 | n += 1;
96 | }
97 | if( t.type===Token.EOF) {
98 | break;
99 | }
100 | }
101 | return n;
102 | };
103 |
104 | exports.CommonTokenStream = CommonTokenStream;
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/FileStream.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | //
7 |
8 | //
9 | // This is an InputStream that is loaded from a file all at once
10 | // when you construct the object.
11 | //
12 | var InputStream = require('./InputStream').InputStream;
13 | var isNodeJs = typeof window === 'undefined' && typeof importScripts === 'undefined';
14 | var fs = isNodeJs ? require("fs") : null;
15 |
16 | function FileStream(fileName, decodeToUnicodeCodePoints) {
17 | var data = fs.readFileSync(fileName, "utf8");
18 | InputStream.call(this, data, decodeToUnicodeCodePoints);
19 | this.fileName = fileName;
20 | return this;
21 | }
22 |
23 | FileStream.prototype = Object.create(InputStream.prototype);
24 | FileStream.prototype.constructor = FileStream;
25 |
26 | exports.FileStream = FileStream;
27 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/InputStream.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | //
7 |
8 | var Token = require('./Token').Token;
9 | require('./polyfills/codepointat');
10 | require('./polyfills/fromcodepoint');
11 |
12 | // Vacuum all input from a string and then treat it like a buffer.
13 |
14 | function _loadString(stream, decodeToUnicodeCodePoints) {
15 | stream._index = 0;
16 | stream.data = [];
17 | if (stream.decodeToUnicodeCodePoints) {
18 | for (var i = 0; i < stream.strdata.length; ) {
19 | var codePoint = stream.strdata.codePointAt(i);
20 | stream.data.push(codePoint);
21 | i += codePoint <= 0xFFFF ? 1 : 2;
22 | }
23 | } else {
24 | for (var i = 0; i < stream.strdata.length; i++) {
25 | var codeUnit = stream.strdata.charCodeAt(i);
26 | stream.data.push(codeUnit);
27 | }
28 | }
29 | stream._size = stream.data.length;
30 | }
31 |
32 | // If decodeToUnicodeCodePoints is true, the input is treated
33 | // as a series of Unicode code points.
34 | //
35 | // Otherwise, the input is treated as a series of 16-bit UTF-16 code
36 | // units.
37 | function InputStream(data, decodeToUnicodeCodePoints) {
38 | this.name = "";
39 | this.strdata = data;
40 | this.decodeToUnicodeCodePoints = decodeToUnicodeCodePoints || false;
41 | _loadString(this);
42 | return this;
43 | }
44 |
45 | Object.defineProperty(InputStream.prototype, "index", {
46 | get : function() {
47 | return this._index;
48 | }
49 | });
50 |
51 | Object.defineProperty(InputStream.prototype, "size", {
52 | get : function() {
53 | return this._size;
54 | }
55 | });
56 |
57 | // Reset the stream so that it's in the same state it was
58 | // when the object was created *except* the data array is not
59 | // touched.
60 | //
61 | InputStream.prototype.reset = function() {
62 | this._index = 0;
63 | };
64 |
65 | InputStream.prototype.consume = function() {
66 | if (this._index >= this._size) {
67 | // assert this.LA(1) == Token.EOF
68 | throw ("cannot consume EOF");
69 | }
70 | this._index += 1;
71 | };
72 |
73 | InputStream.prototype.LA = function(offset) {
74 | if (offset === 0) {
75 | return 0; // undefined
76 | }
77 | if (offset < 0) {
78 | offset += 1; // e.g., translate LA(-1) to use offset=0
79 | }
80 | var pos = this._index + offset - 1;
81 | if (pos < 0 || pos >= this._size) { // invalid
82 | return Token.EOF;
83 | }
84 | return this.data[pos];
85 | };
86 |
87 | InputStream.prototype.LT = function(offset) {
88 | return this.LA(offset);
89 | };
90 |
91 | // mark/release do nothing; we have entire buffer
92 | InputStream.prototype.mark = function() {
93 | return -1;
94 | };
95 |
96 | InputStream.prototype.release = function(marker) {
97 | };
98 |
99 | // consume() ahead until p==_index; can't just set p=_index as we must
100 | // update line and column. If we seek backwards, just set p
101 | //
102 | InputStream.prototype.seek = function(_index) {
103 | if (_index <= this._index) {
104 | this._index = _index; // just jump; don't update stream state (line,
105 | // ...)
106 | return;
107 | }
108 | // seek forward
109 | this._index = Math.min(_index, this._size);
110 | };
111 |
112 | InputStream.prototype.getText = function(start, stop) {
113 | if (stop >= this._size) {
114 | stop = this._size - 1;
115 | }
116 | if (start >= this._size) {
117 | return "";
118 | } else {
119 | if (this.decodeToUnicodeCodePoints) {
120 | var result = "";
121 | for (var i = start; i <= stop; i++) {
122 | result += String.fromCodePoint(this.data[i]);
123 | }
124 | return result;
125 | } else {
126 | return this.strdata.slice(start, stop + 1);
127 | }
128 | }
129 | };
130 |
131 | InputStream.prototype.toString = function() {
132 | return this.strdata;
133 | };
134 |
135 | exports.InputStream = InputStream;
136 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/IntervalSet.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | /*jslint smarttabs:true */
7 |
8 | var Token = require('./Token').Token;
9 |
10 | /* stop is not included! */
11 | function Interval(start, stop) {
12 | this.start = start;
13 | this.stop = stop;
14 | return this;
15 | }
16 |
17 | Interval.prototype.contains = function(item) {
18 | return item >= this.start && item < this.stop;
19 | };
20 |
21 | Interval.prototype.toString = function() {
22 | if(this.start===this.stop-1) {
23 | return this.start.toString();
24 | } else {
25 | return this.start.toString() + ".." + (this.stop-1).toString();
26 | }
27 | };
28 |
29 |
30 | Object.defineProperty(Interval.prototype, "length", {
31 | get : function() {
32 | return this.stop - this.start;
33 | }
34 | });
35 |
36 | function IntervalSet() {
37 | this.intervals = null;
38 | this.readOnly = false;
39 | }
40 |
41 | IntervalSet.prototype.first = function(v) {
42 | if (this.intervals === null || this.intervals.length===0) {
43 | return Token.INVALID_TYPE;
44 | } else {
45 | return this.intervals[0].start;
46 | }
47 | };
48 |
49 | IntervalSet.prototype.addOne = function(v) {
50 | this.addInterval(new Interval(v, v + 1));
51 | };
52 |
53 | IntervalSet.prototype.addRange = function(l, h) {
54 | this.addInterval(new Interval(l, h + 1));
55 | };
56 |
57 | IntervalSet.prototype.addInterval = function(v) {
58 | if (this.intervals === null) {
59 | this.intervals = [];
60 | this.intervals.push(v);
61 | } else {
62 | // find insert pos
63 | for (var k = 0; k < this.intervals.length; k++) {
64 | var i = this.intervals[k];
65 | // distinct range -> insert
66 | if (v.stop < i.start) {
67 | this.intervals.splice(k, 0, v);
68 | return;
69 | }
70 | // contiguous range -> adjust
71 | else if (v.stop === i.start) {
72 | this.intervals[k].start = v.start;
73 | return;
74 | }
75 | // overlapping range -> adjust and reduce
76 | else if (v.start <= i.stop) {
77 | this.intervals[k] = new Interval(Math.min(i.start, v.start), Math.max(i.stop, v.stop));
78 | this.reduce(k);
79 | return;
80 | }
81 | }
82 | // greater than any existing
83 | this.intervals.push(v);
84 | }
85 | };
86 |
87 | IntervalSet.prototype.addSet = function(other) {
88 | if (other.intervals !== null) {
89 | for (var k = 0; k < other.intervals.length; k++) {
90 | var i = other.intervals[k];
91 | this.addInterval(new Interval(i.start, i.stop));
92 | }
93 | }
94 | return this;
95 | };
96 |
97 | IntervalSet.prototype.reduce = function(k) {
98 | // only need to reduce if k is not the last
99 | if (k < this.intervalslength - 1) {
100 | var l = this.intervals[k];
101 | var r = this.intervals[k + 1];
102 | // if r contained in l
103 | if (l.stop >= r.stop) {
104 | this.intervals.pop(k + 1);
105 | this.reduce(k);
106 | } else if (l.stop >= r.start) {
107 | this.intervals[k] = new Interval(l.start, r.stop);
108 | this.intervals.pop(k + 1);
109 | }
110 | }
111 | };
112 |
113 | IntervalSet.prototype.complement = function(start, stop) {
114 | var result = new IntervalSet();
115 | result.addInterval(new Interval(start,stop+1));
116 | for(var i=0; ii.start && v.stop=i.stop) {
163 | this.intervals.splice(k, 1);
164 | k = k - 1; // need another pass
165 | }
166 | // check for lower boundary
167 | else if(v.start");
235 | } else {
236 | names.push("'" + String.fromCharCode(v.start) + "'");
237 | }
238 | } else {
239 | names.push("'" + String.fromCharCode(v.start) + "'..'" + String.fromCharCode(v.stop-1) + "'");
240 | }
241 | }
242 | if (names.length > 1) {
243 | return "{" + names.join(", ") + "}";
244 | } else {
245 | return names[0];
246 | }
247 | };
248 |
249 |
250 | IntervalSet.prototype.toIndexString = function() {
251 | var names = [];
252 | for (var i = 0; i < this.intervals.length; i++) {
253 | var v = this.intervals[i];
254 | if(v.stop===v.start+1) {
255 | if ( v.start===Token.EOF ) {
256 | names.push("");
257 | } else {
258 | names.push(v.start.toString());
259 | }
260 | } else {
261 | names.push(v.start.toString() + ".." + (v.stop-1).toString());
262 | }
263 | }
264 | if (names.length > 1) {
265 | return "{" + names.join(", ") + "}";
266 | } else {
267 | return names[0];
268 | }
269 | };
270 |
271 |
272 | IntervalSet.prototype.toTokenString = function(literalNames, symbolicNames) {
273 | var names = [];
274 | for (var i = 0; i < this.intervals.length; i++) {
275 | var v = this.intervals[i];
276 | for (var j = v.start; j < v.stop; j++) {
277 | names.push(this.elementName(literalNames, symbolicNames, j));
278 | }
279 | }
280 | if (names.length > 1) {
281 | return "{" + names.join(", ") + "}";
282 | } else {
283 | return names[0];
284 | }
285 | };
286 |
287 | IntervalSet.prototype.elementName = function(literalNames, symbolicNames, a) {
288 | if (a === Token.EOF) {
289 | return "";
290 | } else if (a === Token.EPSILON) {
291 | return "";
292 | } else {
293 | return literalNames[a] || symbolicNames[a];
294 | }
295 | };
296 |
297 | exports.Interval = Interval;
298 | exports.IntervalSet = IntervalSet;
299 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/LL1Analyzer.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | ///
7 |
8 | var Set = require('./Utils').Set;
9 | var BitSet = require('./Utils').BitSet;
10 | var Token = require('./Token').Token;
11 | var ATNConfig = require('./atn/ATNConfig').ATNConfig;
12 | var Interval = require('./IntervalSet').Interval;
13 | var IntervalSet = require('./IntervalSet').IntervalSet;
14 | var RuleStopState = require('./atn/ATNState').RuleStopState;
15 | var RuleTransition = require('./atn/Transition').RuleTransition;
16 | var NotSetTransition = require('./atn/Transition').NotSetTransition;
17 | var WildcardTransition = require('./atn/Transition').WildcardTransition;
18 | var AbstractPredicateTransition = require('./atn/Transition').AbstractPredicateTransition;
19 |
20 | var pc = require('./PredictionContext');
21 | var predictionContextFromRuleContext = pc.predictionContextFromRuleContext;
22 | var PredictionContext = pc.PredictionContext;
23 | var SingletonPredictionContext = pc.SingletonPredictionContext;
24 |
25 | function LL1Analyzer (atn) {
26 | this.atn = atn;
27 | }
28 |
29 | //* Special value added to the lookahead sets to indicate that we hit
30 | // a predicate during analysis if {@code seeThruPreds==false}.
31 | ///
32 | LL1Analyzer.HIT_PRED = Token.INVALID_TYPE;
33 |
34 |
35 | //*
36 | // Calculates the SLL(1) expected lookahead set for each outgoing transition
37 | // of an {@link ATNState}. The returned array has one element for each
38 | // outgoing transition in {@code s}. If the closure from transition
39 | // i leads to a semantic predicate before matching a symbol, the
40 | // element at index i of the result will be {@code null}.
41 | //
42 | // @param s the ATN state
43 | // @return the expected symbols for each outgoing transition of {@code s}.
44 | ///
45 | LL1Analyzer.prototype.getDecisionLookahead = function(s) {
46 | if (s === null) {
47 | return null;
48 | }
49 | var count = s.transitions.length;
50 | var look = [];
51 | for(var alt=0; alt< count; alt++) {
52 | look[alt] = new IntervalSet();
53 | var lookBusy = new Set();
54 | var seeThruPreds = false; // fail to get lookahead upon pred
55 | this._LOOK(s.transition(alt).target, null, PredictionContext.EMPTY,
56 | look[alt], lookBusy, new BitSet(), seeThruPreds, false);
57 | // Wipe out lookahead for this alternative if we found nothing
58 | // or we had a predicate when we !seeThruPreds
59 | if (look[alt].length===0 || look[alt].contains(LL1Analyzer.HIT_PRED)) {
60 | look[alt] = null;
61 | }
62 | }
63 | return look;
64 | };
65 |
66 | //*
67 | // Compute set of tokens that can follow {@code s} in the ATN in the
68 | // specified {@code ctx}.
69 | //
70 | // If {@code ctx} is {@code null} and the end of the rule containing
71 | // {@code s} is reached, {@link Token//EPSILON} is added to the result set.
72 | // If {@code ctx} is not {@code null} and the end of the outermost rule is
73 | // reached, {@link Token//EOF} is added to the result set.
74 | //
75 | // @param s the ATN state
76 | // @param stopState the ATN state to stop at. This can be a
77 | // {@link BlockEndState} to detect epsilon paths through a closure.
78 | // @param ctx the complete parser context, or {@code null} if the context
79 | // should be ignored
80 | //
81 | // @return The set of tokens that can follow {@code s} in the ATN in the
82 | // specified {@code ctx}.
83 | ///
84 | LL1Analyzer.prototype.LOOK = function(s, stopState, ctx) {
85 | var r = new IntervalSet();
86 | var seeThruPreds = true; // ignore preds; get all lookahead
87 | ctx = ctx || null;
88 | var lookContext = ctx!==null ? predictionContextFromRuleContext(s.atn, ctx) : null;
89 | this._LOOK(s, stopState, lookContext, r, new Set(), new BitSet(), seeThruPreds, true);
90 | return r;
91 | };
92 |
93 | //*
94 | // Compute set of tokens that can follow {@code s} in the ATN in the
95 | // specified {@code ctx}.
96 | //
97 | // If {@code ctx} is {@code null} and {@code stopState} or the end of the
98 | // rule containing {@code s} is reached, {@link Token//EPSILON} is added to
99 | // the result set. If {@code ctx} is not {@code null} and {@code addEOF} is
100 | // {@code true} and {@code stopState} or the end of the outermost rule is
101 | // reached, {@link Token//EOF} is added to the result set.
102 | //
103 | // @param s the ATN state.
104 | // @param stopState the ATN state to stop at. This can be a
105 | // {@link BlockEndState} to detect epsilon paths through a closure.
106 | // @param ctx The outer context, or {@code null} if the outer context should
107 | // not be used.
108 | // @param look The result lookahead set.
109 | // @param lookBusy A set used for preventing epsilon closures in the ATN
110 | // from causing a stack overflow. Outside code should pass
111 | // {@code new Set} for this argument.
112 | // @param calledRuleStack A set used for preventing left recursion in the
113 | // ATN from causing a stack overflow. Outside code should pass
114 | // {@code new BitSet()} for this argument.
115 | // @param seeThruPreds {@code true} to true semantic predicates as
116 | // implicitly {@code true} and "see through them", otherwise {@code false}
117 | // to treat semantic predicates as opaque and add {@link //HIT_PRED} to the
118 | // result if one is encountered.
119 | // @param addEOF Add {@link Token//EOF} to the result if the end of the
120 | // outermost context is reached. This parameter has no effect if {@code ctx}
121 | // is {@code null}.
122 | ///
123 | LL1Analyzer.prototype._LOOK = function(s, stopState , ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) {
124 | var c = new ATNConfig({state:s, alt:0, context: ctx}, null);
125 | if (lookBusy.contains(c)) {
126 | return;
127 | }
128 | lookBusy.add(c);
129 | if (s === stopState) {
130 | if (ctx ===null) {
131 | look.addOne(Token.EPSILON);
132 | return;
133 | } else if (ctx.isEmpty() && addEOF) {
134 | look.addOne(Token.EOF);
135 | return;
136 | }
137 | }
138 | if (s instanceof RuleStopState ) {
139 | if (ctx ===null) {
140 | look.addOne(Token.EPSILON);
141 | return;
142 | } else if (ctx.isEmpty() && addEOF) {
143 | look.addOne(Token.EOF);
144 | return;
145 | }
146 | if (ctx !== PredictionContext.EMPTY) {
147 | // run thru all possible stack tops in ctx
148 | for(var i=0; i= this.children.length) {
123 | return null;
124 | }
125 | if (type === null) {
126 | return this.children[i];
127 | } else {
128 | for(var j=0; j= this.children.length) {
145 | return null;
146 | }
147 | for(var j=0; jUsed for XPath and tree pattern compilation.
55 | //
56 | Recognizer.prototype.getRuleIndexMap = function() {
57 | var ruleNames = this.ruleNames;
58 | if (ruleNames===null) {
59 | throw("The current recognizer does not provide a list of rule names.");
60 | }
61 | var result = this.ruleIndexMapCache[ruleNames];
62 | if(result===undefined) {
63 | result = ruleNames.reduce(function(o, k, i) { o[k] = i; });
64 | this.ruleIndexMapCache[ruleNames] = result;
65 | }
66 | return result;
67 | };
68 |
69 | Recognizer.prototype.getTokenType = function(tokenName) {
70 | var ttype = this.getTokenTypeMap()[tokenName];
71 | if (ttype !==undefined) {
72 | return ttype;
73 | } else {
74 | return Token.INVALID_TYPE;
75 | }
76 | };
77 |
78 |
79 | // What is the error header, normally line/character position information?//
80 | Recognizer.prototype.getErrorHeader = function(e) {
81 | var line = e.getOffendingToken().line;
82 | var column = e.getOffendingToken().column;
83 | return "line " + line + ":" + column;
84 | };
85 |
86 |
87 | // How should a token be displayed in an error message? The default
88 | // is to display just the text, but during development you might
89 | // want to have a lot of information spit out. Override in that case
90 | // to use t.toString() (which, for CommonToken, dumps everything about
91 | // the token). This is better than forcing you to override a method in
92 | // your token objects because you don't have to go modify your lexer
93 | // so that it creates a new Java type.
94 | //
95 | // @deprecated This method is not called by the ANTLR 4 Runtime. Specific
96 | // implementations of {@link ANTLRErrorStrategy} may provide a similar
97 | // feature when necessary. For example, see
98 | // {@link DefaultErrorStrategy//getTokenErrorDisplay}.
99 | //
100 | Recognizer.prototype.getTokenErrorDisplay = function(t) {
101 | if (t===null) {
102 | return "";
103 | }
104 | var s = t.text;
105 | if (s===null) {
106 | if (t.type===Token.EOF) {
107 | s = "";
108 | } else {
109 | s = "<" + t.type + ">";
110 | }
111 | }
112 | s = s.replace("\n","\\n").replace("\r","\\r").replace("\t","\\t");
113 | return "'" + s + "'";
114 | };
115 |
116 | Recognizer.prototype.getErrorListenerDispatch = function() {
117 | return new ProxyErrorListener(this._listeners);
118 | };
119 |
120 | // subclass needs to override these if there are sempreds or actions
121 | // that the ATN interp needs to execute
122 | Recognizer.prototype.sempred = function(localctx, ruleIndex, actionIndex) {
123 | return true;
124 | };
125 |
126 | Recognizer.prototype.precpred = function(localctx , precedence) {
127 | return true;
128 | };
129 |
130 | //Indicate that the recognizer has changed internal state that is
131 | //consistent with the ATN state passed in. This way we always know
132 | //where we are in the ATN as the parser goes along. The rule
133 | //context objects form a stack that lets us see the stack of
134 | //invoking rules. Combine this and we have complete ATN
135 | //configuration information.
136 |
137 | Object.defineProperty(Recognizer.prototype, "state", {
138 | get : function() {
139 | return this._stateNumber;
140 | },
141 | set : function(state) {
142 | this._stateNumber = state;
143 | }
144 | });
145 |
146 |
147 | exports.Recognizer = Recognizer;
148 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/RuleContext.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 | ///
6 |
7 | // A rule context is a record of a single rule invocation. It knows
8 | // which context invoked it, if any. If there is no parent context, then
9 | // naturally the invoking state is not valid. The parent link
10 | // provides a chain upwards from the current rule invocation to the root
11 | // of the invocation tree, forming a stack. We actually carry no
12 | // information about the rule associated with this context (except
13 | // when parsing). We keep only the state number of the invoking state from
14 | // the ATN submachine that invoked this. Contrast this with the s
15 | // pointer inside ParserRuleContext that tracks the current state
16 | // being "executed" for the current rule.
17 | //
18 | // The parent contexts are useful for computing lookahead sets and
19 | // getting error information.
20 | //
21 | // These objects are used during parsing and prediction.
22 | // For the special case of parsers, we use the subclass
23 | // ParserRuleContext.
24 | //
25 | // @see ParserRuleContext
26 | ///
27 |
28 | var RuleNode = require('./tree/Tree').RuleNode;
29 | var INVALID_INTERVAL = require('./tree/Tree').INVALID_INTERVAL;
30 | var INVALID_ALT_NUMBER = require('./atn/ATN').INVALID_ALT_NUMBER;
31 |
32 | function RuleContext(parent, invokingState) {
33 | RuleNode.call(this);
34 | // What context invoked this rule?
35 | this.parentCtx = parent || null;
36 | // What state invoked the rule associated with this context?
37 | // The "return address" is the followState of invokingState
38 | // If parent is null, this should be -1.
39 | this.invokingState = invokingState || -1;
40 | return this;
41 | }
42 |
43 | RuleContext.prototype = Object.create(RuleNode.prototype);
44 | RuleContext.prototype.constructor = RuleContext;
45 |
46 | RuleContext.prototype.depth = function() {
47 | var n = 0;
48 | var p = this;
49 | while (p !== null) {
50 | p = p.parentCtx;
51 | n += 1;
52 | }
53 | return n;
54 | };
55 |
56 | // A context is empty if there is no invoking state; meaning nobody call
57 | // current context.
58 | RuleContext.prototype.isEmpty = function() {
59 | return this.invokingState === -1;
60 | };
61 |
62 | // satisfy the ParseTree / SyntaxTree interface
63 |
64 | RuleContext.prototype.getSourceInterval = function() {
65 | return INVALID_INTERVAL;
66 | };
67 |
68 | RuleContext.prototype.getRuleContext = function() {
69 | return this;
70 | };
71 |
72 | RuleContext.prototype.getPayload = function() {
73 | return this;
74 | };
75 |
76 | // Return the combined text of all child nodes. This method only considers
77 | // tokens which have been added to the parse tree.
78 | //
79 | // Since tokens on hidden channels (e.g. whitespace or comments) are not
80 | // added to the parse trees, they will not appear in the output of this
81 | // method.
82 | // /
83 | RuleContext.prototype.getText = function() {
84 | if (this.getChildCount() === 0) {
85 | return "";
86 | } else {
87 | return this.children.map(function(child) {
88 | return child.getText();
89 | }).join(" ");
90 | }
91 | };
92 |
93 | // For rule associated with this parse tree internal node, return
94 | // the outer alternative number used to match the input. Default
95 | // implementation does not compute nor store this alt num. Create
96 | // a subclass of ParserRuleContext with backing field and set
97 | // option contextSuperClass.
98 | // to set it.
99 | RuleContext.prototype.getAltNumber = function() { return INVALID_ALT_NUMBER; }
100 |
101 | // Set the outer alternative number for this context node. Default
102 | // implementation does nothing to avoid backing field overhead for
103 | // trees that don't need it. Create
104 | // a subclass of ParserRuleContext with backing field and set
105 | // option contextSuperClass.
106 | RuleContext.prototype.setAltNumber = function(altNumber) { }
107 |
108 | RuleContext.prototype.getChild = function(i) {
109 | return null;
110 | };
111 |
112 | RuleContext.prototype.getChildCount = function() {
113 | return 0;
114 | };
115 |
116 | RuleContext.prototype.accept = function(visitor) {
117 | return visitor.visitChildren(this);
118 | };
119 |
120 | //need to manage circular dependencies, so export now
121 | exports.RuleContext = RuleContext;
122 | var Trees = require('./tree/Trees').Trees;
123 |
124 |
125 | // Print out a whole tree, not just a node, in LISP format
126 | // (root child1 .. childN). Print just a node if this is a leaf.
127 | //
128 |
129 | RuleContext.prototype.toStringTree = function(ruleNames, recog) {
130 | return Trees.toStringTree(this, ruleNames, recog);
131 | };
132 |
133 | RuleContext.prototype.toString = function(ruleNames, stop) {
134 | ruleNames = ruleNames || null;
135 | stop = stop || null;
136 | var p = this;
137 | var s = "[";
138 | while (p !== null && p !== stop) {
139 | if (ruleNames === null) {
140 | if (!p.isEmpty()) {
141 | s += p.invokingState;
142 | }
143 | } else {
144 | var ri = p.ruleIndex;
145 | var ruleName = (ri >= 0 && ri < ruleNames.length) ? ruleNames[ri]
146 | : "" + ri;
147 | s += ruleName;
148 | }
149 | if (p.parentCtx !== null && (ruleNames !== null || !p.parentCtx.isEmpty())) {
150 | s += " ";
151 | }
152 | p = p.parentCtx;
153 | }
154 | s += "]";
155 | return s;
156 | };
157 |
158 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/Token.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 | //
6 |
7 | // A token has properties: text, type, line, character position in the line
8 | // (so we can ignore tabs), token channel, index, and source from which
9 | // we obtained this token.
10 |
11 | function Token() {
12 | this.source = null;
13 | this.type = null; // token type of the token
14 | this.channel = null; // The parser ignores everything not on DEFAULT_CHANNEL
15 | this.start = null; // optional; return -1 if not implemented.
16 | this.stop = null; // optional; return -1 if not implemented.
17 | this.tokenIndex = null; // from 0..n-1 of the token object in the input stream
18 | this.line = null; // line=1..n of the 1st character
19 | this.column = null; // beginning of the line at which it occurs, 0..n-1
20 | this._text = null; // text of the token.
21 | return this;
22 | }
23 |
24 | Token.INVALID_TYPE = 0;
25 |
26 | // During lookahead operations, this "token" signifies we hit rule end ATN state
27 | // and did not follow it despite needing to.
28 | Token.EPSILON = -2;
29 |
30 | Token.MIN_USER_TOKEN_TYPE = 1;
31 |
32 | Token.EOF = -1;
33 |
34 | // All tokens go to the parser (unless skip() is called in that rule)
35 | // on a particular "channel". The parser tunes to a particular channel
36 | // so that whitespace etc... can go to the parser on a "hidden" channel.
37 |
38 | Token.DEFAULT_CHANNEL = 0;
39 |
40 | // Anything on different channel than DEFAULT_CHANNEL is not parsed
41 | // by parser.
42 |
43 | Token.HIDDEN_CHANNEL = 1;
44 |
45 | // Explicitly set the text for this token. If {code text} is not
46 | // {@code null}, then {@link //getText} will return this value rather than
47 | // extracting the text from the input.
48 | //
49 | // @param text The explicit text of the token, or {@code null} if the text
50 | // should be obtained from the input along with the start and stop indexes
51 | // of the token.
52 |
53 | Object.defineProperty(Token.prototype, "text", {
54 | get : function() {
55 | return this._text;
56 | },
57 | set : function(text) {
58 | this._text = text;
59 | }
60 | });
61 |
62 | Token.prototype.getTokenSource = function() {
63 | return this.source[0];
64 | };
65 |
66 | Token.prototype.getInputStream = function() {
67 | return this.source[1];
68 | };
69 |
70 | function CommonToken(source, type, channel, start, stop) {
71 | Token.call(this);
72 | this.source = source !== undefined ? source : CommonToken.EMPTY_SOURCE;
73 | this.type = type !== undefined ? type : null;
74 | this.channel = channel !== undefined ? channel : Token.DEFAULT_CHANNEL;
75 | this.start = start !== undefined ? start : -1;
76 | this.stop = stop !== undefined ? stop : -1;
77 | this.tokenIndex = -1;
78 | if (this.source[0] !== null) {
79 | this.line = source[0].line;
80 | this.column = source[0].column;
81 | } else {
82 | this.column = -1;
83 | }
84 | return this;
85 | }
86 |
87 | CommonToken.prototype = Object.create(Token.prototype);
88 | CommonToken.prototype.constructor = CommonToken;
89 |
90 | // An empty {@link Pair} which is used as the default value of
91 | // {@link //source} for tokens that do not have a source.
92 | CommonToken.EMPTY_SOURCE = [ null, null ];
93 |
94 | // Constructs a new {@link CommonToken} as a copy of another {@link Token}.
95 | //
96 | //
97 | // If {@code oldToken} is also a {@link CommonToken} instance, the newly
98 | // constructed token will share a reference to the {@link //text} field and
99 | // the {@link Pair} stored in {@link //source}. Otherwise, {@link //text} will
100 | // be assigned the result of calling {@link //getText}, and {@link //source}
101 | // will be constructed from the result of {@link Token//getTokenSource} and
102 | // {@link Token//getInputStream}.
103 | //
104 | // @param oldToken The token to copy.
105 | //
106 | CommonToken.prototype.clone = function() {
107 | var t = new CommonToken(this.source, this.type, this.channel, this.start,
108 | this.stop);
109 | t.tokenIndex = this.tokenIndex;
110 | t.line = this.line;
111 | t.column = this.column;
112 | t.text = this.text;
113 | return t;
114 | };
115 |
116 | Object.defineProperty(CommonToken.prototype, "text", {
117 | get : function() {
118 | if (this._text !== null) {
119 | return this._text;
120 | }
121 | var input = this.getInputStream();
122 | if (input === null) {
123 | return null;
124 | }
125 | var n = input.size;
126 | if (this.start < n && this.stop < n) {
127 | return input.getText(this.start, this.stop);
128 | } else {
129 | return "";
130 | }
131 | },
132 | set : function(text) {
133 | this._text = text;
134 | }
135 | });
136 |
137 | CommonToken.prototype.toString = function() {
138 | var txt = this.text;
139 | if (txt !== null) {
140 | txt = txt.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
141 | } else {
142 | txt = "";
143 | }
144 | return "[@" + this.tokenIndex + "," + this.start + ":" + this.stop + "='" +
145 | txt + "',<" + this.type + ">" +
146 | (this.channel > 0 ? ",channel=" + this.channel : "") + "," +
147 | this.line + ":" + this.column + "]";
148 | };
149 |
150 | exports.Token = Token;
151 | exports.CommonToken = CommonToken;
152 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/ATN.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | var LL1Analyzer = require('./../LL1Analyzer').LL1Analyzer;
7 | var IntervalSet = require('./../IntervalSet').IntervalSet;
8 |
9 | function ATN(grammarType , maxTokenType) {
10 |
11 | // Used for runtime deserialization of ATNs from strings///
12 | // The type of the ATN.
13 | this.grammarType = grammarType;
14 | // The maximum value for any symbol recognized by a transition in the ATN.
15 | this.maxTokenType = maxTokenType;
16 | this.states = [];
17 | // Each subrule/rule is a decision point and we must track them so we
18 | // can go back later and build DFA predictors for them. This includes
19 | // all the rules, subrules, optional blocks, ()+, ()* etc...
20 | this.decisionToState = [];
21 | // Maps from rule index to starting state number.
22 | this.ruleToStartState = [];
23 | // Maps from rule index to stop state number.
24 | this.ruleToStopState = null;
25 | this.modeNameToStartState = {};
26 | // For lexer ATNs, this maps the rule index to the resulting token type.
27 | // For parser ATNs, this maps the rule index to the generated bypass token
28 | // type if the
29 | // {@link ATNDeserializationOptions//isGenerateRuleBypassTransitions}
30 | // deserialization option was specified; otherwise, this is {@code null}.
31 | this.ruleToTokenType = null;
32 | // For lexer ATNs, this is an array of {@link LexerAction} objects which may
33 | // be referenced by action transitions in the ATN.
34 | this.lexerActions = null;
35 | this.modeToStartState = [];
36 |
37 | return this;
38 | }
39 |
40 | // Compute the set of valid tokens that can occur starting in state {@code s}.
41 | // If {@code ctx} is null, the set of tokens will not include what can follow
42 | // the rule surrounding {@code s}. In other words, the set will be
43 | // restricted to tokens reachable staying within {@code s}'s rule.
44 | ATN.prototype.nextTokensInContext = function(s, ctx) {
45 | var anal = new LL1Analyzer(this);
46 | return anal.LOOK(s, null, ctx);
47 | };
48 |
49 | // Compute the set of valid tokens that can occur starting in {@code s} and
50 | // staying in same rule. {@link Token//EPSILON} is in set if we reach end of
51 | // rule.
52 | ATN.prototype.nextTokensNoContext = function(s) {
53 | if (s.nextTokenWithinRule !== null ) {
54 | return s.nextTokenWithinRule;
55 | }
56 | s.nextTokenWithinRule = this.nextTokensInContext(s, null);
57 | s.nextTokenWithinRule.readOnly = true;
58 | return s.nextTokenWithinRule;
59 | };
60 |
61 | ATN.prototype.nextTokens = function(s, ctx) {
62 | if ( ctx===undefined ) {
63 | return this.nextTokensNoContext(s);
64 | } else {
65 | return this.nextTokensInContext(s, ctx);
66 | }
67 | };
68 |
69 | ATN.prototype.addState = function( state) {
70 | if ( state !== null ) {
71 | state.atn = this;
72 | state.stateNumber = this.states.length;
73 | }
74 | this.states.push(state);
75 | };
76 |
77 | ATN.prototype.removeState = function( state) {
78 | this.states[state.stateNumber] = null; // just free mem, don't shift states in list
79 | };
80 |
81 | ATN.prototype.defineDecisionState = function( s) {
82 | this.decisionToState.push(s);
83 | s.decision = this.decisionToState.length-1;
84 | return s.decision;
85 | };
86 |
87 | ATN.prototype.getDecisionState = function( decision) {
88 | if (this.decisionToState.length===0) {
89 | return null;
90 | } else {
91 | return this.decisionToState[decision];
92 | }
93 | };
94 |
95 | // Computes the set of input symbols which could follow ATN state number
96 | // {@code stateNumber} in the specified full {@code context}. This method
97 | // considers the complete parser context, but does not evaluate semantic
98 | // predicates (i.e. all predicates encountered during the calculation are
99 | // assumed true). If a path in the ATN exists from the starting state to the
100 | // {@link RuleStopState} of the outermost context without matching any
101 | // symbols, {@link Token//EOF} is added to the returned set.
102 | //
103 | // If {@code context} is {@code null}, it is treated as
104 | // {@link ParserRuleContext//EMPTY}.
105 | //
106 | // @param stateNumber the ATN state number
107 | // @param context the full parse context
108 | // @return The set of potentially valid input symbols which could follow the
109 | // specified state in the specified context.
110 | // @throws IllegalArgumentException if the ATN does not contain a state with
111 | // number {@code stateNumber}
112 | var Token = require('./../Token').Token;
113 |
114 | ATN.prototype.getExpectedTokens = function( stateNumber, ctx ) {
115 | if ( stateNumber < 0 || stateNumber >= this.states.length ) {
116 | throw("Invalid state number.");
117 | }
118 | var s = this.states[stateNumber];
119 | var following = this.nextTokens(s);
120 | if (!following.contains(Token.EPSILON)) {
121 | return following;
122 | }
123 | var expected = new IntervalSet();
124 | expected.addSet(following);
125 | expected.removeOne(Token.EPSILON);
126 | while (ctx !== null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
127 | var invokingState = this.states[ctx.invokingState];
128 | var rt = invokingState.transitions[0];
129 | following = this.nextTokens(rt.followState);
130 | expected.addSet(following);
131 | expected.removeOne(Token.EPSILON);
132 | ctx = ctx.parentCtx;
133 | }
134 | if (following.contains(Token.EPSILON)) {
135 | expected.addOne(Token.EOF);
136 | }
137 | return expected;
138 | };
139 |
140 | ATN.INVALID_ALT_NUMBER = 0;
141 |
142 | exports.ATN = ATN;
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/ATNConfig.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | ///
7 |
8 | // A tuple: (ATN state, predicted alt, syntactic, semantic context).
9 | // The syntactic context is a graph-structured stack node whose
10 | // path(s) to the root is the rule invocation(s)
11 | // chain used to arrive at the state. The semantic context is
12 | // the tree of semantic predicates encountered before reaching
13 | // an ATN state.
14 | ///
15 |
16 | var DecisionState = require('./ATNState').DecisionState;
17 | var SemanticContext = require('./SemanticContext').SemanticContext;
18 | var Hash = require("../Utils").Hash;
19 |
20 |
21 | function checkParams(params, isCfg) {
22 | if(params===null) {
23 | var result = { state:null, alt:null, context:null, semanticContext:null };
24 | if(isCfg) {
25 | result.reachesIntoOuterContext = 0;
26 | }
27 | return result;
28 | } else {
29 | var props = {};
30 | props.state = params.state || null;
31 | props.alt = (params.alt === undefined) ? null : params.alt;
32 | props.context = params.context || null;
33 | props.semanticContext = params.semanticContext || null;
34 | if(isCfg) {
35 | props.reachesIntoOuterContext = params.reachesIntoOuterContext || 0;
36 | props.precedenceFilterSuppressed = params.precedenceFilterSuppressed || false;
37 | }
38 | return props;
39 | }
40 | }
41 |
42 | function ATNConfig(params, config) {
43 | this.checkContext(params, config);
44 | params = checkParams(params);
45 | config = checkParams(config, true);
46 | // The ATN state associated with this configuration///
47 | this.state = params.state!==null ? params.state : config.state;
48 | // What alt (or lexer rule) is predicted by this configuration///
49 | this.alt = params.alt!==null ? params.alt : config.alt;
50 | // The stack of invoking states leading to the rule/states associated
51 | // with this config. We track only those contexts pushed during
52 | // execution of the ATN simulator.
53 | this.context = params.context!==null ? params.context : config.context;
54 | this.semanticContext = params.semanticContext!==null ? params.semanticContext :
55 | (config.semanticContext!==null ? config.semanticContext : SemanticContext.NONE);
56 | // We cannot execute predicates dependent upon local context unless
57 | // we know for sure we are in the correct context. Because there is
58 | // no way to do this efficiently, we simply cannot evaluate
59 | // dependent predicates unless we are in the rule that initially
60 | // invokes the ATN simulator.
61 | //
62 | // closure() tracks the depth of how far we dip into the
63 | // outer context: depth > 0. Note that it may not be totally
64 | // accurate depth since I don't ever decrement. TODO: make it a boolean then
65 | this.reachesIntoOuterContext = config.reachesIntoOuterContext;
66 | this.precedenceFilterSuppressed = config.precedenceFilterSuppressed;
67 | return this;
68 | }
69 |
70 | ATNConfig.prototype.checkContext = function(params, config) {
71 | if((params.context===null || params.context===undefined) &&
72 | (config===null || config.context===null || config.context===undefined)) {
73 | this.context = null;
74 | }
75 | };
76 |
77 |
78 | ATNConfig.prototype.hashCode = function() {
79 | var hash = new Hash();
80 | this.updateHashCode(hash);
81 | return hash.finish();
82 | };
83 |
84 |
85 | ATNConfig.prototype.updateHashCode = function(hash) {
86 | hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext);
87 | };
88 |
89 | // An ATN configuration is equal to another if both have
90 | // the same state, they predict the same alternative, and
91 | // syntactic/semantic contexts are the same.
92 |
93 | ATNConfig.prototype.equals = function(other) {
94 | if (this === other) {
95 | return true;
96 | } else if (! (other instanceof ATNConfig)) {
97 | return false;
98 | } else {
99 | return this.state.stateNumber===other.state.stateNumber &&
100 | this.alt===other.alt &&
101 | (this.context===null ? other.context===null : this.context.equals(other.context)) &&
102 | this.semanticContext.equals(other.semanticContext) &&
103 | this.precedenceFilterSuppressed===other.precedenceFilterSuppressed;
104 | }
105 | };
106 |
107 |
108 | ATNConfig.prototype.hashCodeForConfigSet = function() {
109 | var hash = new Hash();
110 | hash.update(this.state.stateNumber, this.alt, this.semanticContext);
111 | return hash.finish();
112 | };
113 |
114 |
115 | ATNConfig.prototype.equalsForConfigSet = function(other) {
116 | if (this === other) {
117 | return true;
118 | } else if (! (other instanceof ATNConfig)) {
119 | return false;
120 | } else {
121 | return this.state.stateNumber===other.state.stateNumber &&
122 | this.alt===other.alt &&
123 | this.semanticContext.equals(other.semanticContext);
124 | }
125 | };
126 |
127 |
128 | ATNConfig.prototype.toString = function() {
129 | return "(" + this.state + "," + this.alt +
130 | (this.context!==null ? ",[" + this.context.toString() + "]" : "") +
131 | (this.semanticContext !== SemanticContext.NONE ?
132 | ("," + this.semanticContext.toString())
133 | : "") +
134 | (this.reachesIntoOuterContext>0 ?
135 | (",up=" + this.reachesIntoOuterContext)
136 | : "") + ")";
137 | };
138 |
139 |
140 | function LexerATNConfig(params, config) {
141 | ATNConfig.call(this, params, config);
142 |
143 | // This is the backing field for {@link //getLexerActionExecutor}.
144 | var lexerActionExecutor = params.lexerActionExecutor || null;
145 | this.lexerActionExecutor = lexerActionExecutor || (config!==null ? config.lexerActionExecutor : null);
146 | this.passedThroughNonGreedyDecision = config!==null ? this.checkNonGreedyDecision(config, this.state) : false;
147 | return this;
148 | }
149 |
150 | LexerATNConfig.prototype = Object.create(ATNConfig.prototype);
151 | LexerATNConfig.prototype.constructor = LexerATNConfig;
152 |
153 | LexerATNConfig.prototype.updateHashCode = function(hash) {
154 | hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext, this.passedThroughNonGreedyDecision, this.lexerActionExecutor);
155 | };
156 |
157 | LexerATNConfig.prototype.equals = function(other) {
158 | return this === other ||
159 | (other instanceof LexerATNConfig &&
160 | this.passedThroughNonGreedyDecision == other.passedThroughNonGreedyDecision &&
161 | (this.lexerActionExecutor ? this.lexerActionExecutor.equals(other.lexerActionExecutor) : !other.lexerActionExecutor) &&
162 | ATNConfig.prototype.equals.call(this, other));
163 | };
164 |
165 | LexerATNConfig.prototype.hashCodeForConfigSet = LexerATNConfig.prototype.hashCode;
166 |
167 | LexerATNConfig.prototype.equalsForConfigSet = LexerATNConfig.prototype.equals;
168 |
169 |
170 | LexerATNConfig.prototype.checkNonGreedyDecision = function(source, target) {
171 | return source.passedThroughNonGreedyDecision ||
172 | (target instanceof DecisionState) && target.nonGreedy;
173 | };
174 |
175 | exports.ATNConfig = ATNConfig;
176 | exports.LexerATNConfig = LexerATNConfig;
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/ATNDeserializationOptions.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | function ATNDeserializationOptions(copyFrom) {
7 | if(copyFrom===undefined) {
8 | copyFrom = null;
9 | }
10 | this.readOnly = false;
11 | this.verifyATN = copyFrom===null ? true : copyFrom.verifyATN;
12 | this.generateRuleBypassTransitions = copyFrom===null ? false : copyFrom.generateRuleBypassTransitions;
13 |
14 | return this;
15 | }
16 |
17 | ATNDeserializationOptions.defaultOptions = new ATNDeserializationOptions();
18 | ATNDeserializationOptions.defaultOptions.readOnly = true;
19 |
20 | // def __setattr__(self, key, value):
21 | // if key!="readOnly" and self.readOnly:
22 | // raise Exception("The object is read only.")
23 | // super(type(self), self).__setattr__(key,value)
24 |
25 | exports.ATNDeserializationOptions = ATNDeserializationOptions;
26 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/ATNSimulator.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | ///
7 |
8 | var DFAState = require('./../dfa/DFAState').DFAState;
9 | var ATNConfigSet = require('./ATNConfigSet').ATNConfigSet;
10 | var getCachedPredictionContext = require('./../PredictionContext').getCachedPredictionContext;
11 |
12 | function ATNSimulator(atn, sharedContextCache) {
13 |
14 | // The context cache maps all PredictionContext objects that are ==
15 | // to a single cached copy. This cache is shared across all contexts
16 | // in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet
17 | // to use only cached nodes/graphs in addDFAState(). We don't want to
18 | // fill this during closure() since there are lots of contexts that
19 | // pop up but are not used ever again. It also greatly slows down closure().
20 | //
21 | // This cache makes a huge difference in memory and a little bit in speed.
22 | // For the Java grammar on java.*, it dropped the memory requirements
23 | // at the end from 25M to 16M. We don't store any of the full context
24 | // graphs in the DFA because they are limited to local context only,
25 | // but apparently there's a lot of repetition there as well. We optimize
26 | // the config contexts before storing the config set in the DFA states
27 | // by literally rebuilding them with cached subgraphs only.
28 | //
29 | // I tried a cache for use during closure operations, that was
30 | // whacked after each adaptivePredict(). It cost a little bit
31 | // more time I think and doesn't save on the overall footprint
32 | // so it's not worth the complexity.
33 | ///
34 | this.atn = atn;
35 | this.sharedContextCache = sharedContextCache;
36 | return this;
37 | }
38 |
39 | // Must distinguish between missing edge and edge we know leads nowhere///
40 | ATNSimulator.ERROR = new DFAState(0x7FFFFFFF, new ATNConfigSet());
41 |
42 |
43 | ATNSimulator.prototype.getCachedContext = function(context) {
44 | if (this.sharedContextCache ===null) {
45 | return context;
46 | }
47 | var visited = {};
48 | return getCachedPredictionContext(context, this.sharedContextCache, visited);
49 | };
50 |
51 | exports.ATNSimulator = ATNSimulator;
52 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/ATNType.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 | ///
6 |
7 | // Represents the type of recognizer an ATN applies to.
8 |
9 | function ATNType() {
10 |
11 | }
12 |
13 | ATNType.LEXER = 0;
14 | ATNType.PARSER = 1;
15 |
16 | exports.ATNType = ATNType;
17 |
18 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/LexerActionExecutor.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | ///
7 |
8 | // Represents an executor for a sequence of lexer actions which traversed during
9 | // the matching operation of a lexer rule (token).
10 | //
11 | // The executor tracks position information for position-dependent lexer actions
12 | // efficiently, ensuring that actions appearing only at the end of the rule do
13 | // not cause bloating of the {@link DFA} created for the lexer.
14 |
15 | var hashStuff = require("../Utils").hashStuff;
16 | var LexerIndexedCustomAction = require('./LexerAction').LexerIndexedCustomAction;
17 |
18 | function LexerActionExecutor(lexerActions) {
19 | this.lexerActions = lexerActions === null ? [] : lexerActions;
20 | // Caches the result of {@link //hashCode} since the hash code is an element
21 | // of the performance-critical {@link LexerATNConfig//hashCode} operation.
22 | this.cachedHashCode = hashStuff(lexerActions); // "".join([str(la) for la in
23 | // lexerActions]))
24 | return this;
25 | }
26 |
27 | // Creates a {@link LexerActionExecutor} which executes the actions for
28 | // the input {@code lexerActionExecutor} followed by a specified
29 | // {@code lexerAction}.
30 | //
31 | // @param lexerActionExecutor The executor for actions already traversed by
32 | // the lexer while matching a token within a particular
33 | // {@link LexerATNConfig}. If this is {@code null}, the method behaves as
34 | // though it were an empty executor.
35 | // @param lexerAction The lexer action to execute after the actions
36 | // specified in {@code lexerActionExecutor}.
37 | //
38 | // @return A {@link LexerActionExecutor} for executing the combine actions
39 | // of {@code lexerActionExecutor} and {@code lexerAction}.
40 | LexerActionExecutor.append = function(lexerActionExecutor, lexerAction) {
41 | if (lexerActionExecutor === null) {
42 | return new LexerActionExecutor([ lexerAction ]);
43 | }
44 | var lexerActions = lexerActionExecutor.lexerActions.concat([ lexerAction ]);
45 | return new LexerActionExecutor(lexerActions);
46 | };
47 |
48 | // Creates a {@link LexerActionExecutor} which encodes the current offset
49 | // for position-dependent lexer actions.
50 | //
51 | // Normally, when the executor encounters lexer actions where
52 | // {@link LexerAction//isPositionDependent} returns {@code true}, it calls
53 | // {@link IntStream//seek} on the input {@link CharStream} to set the input
54 | // position to the end of the current token. This behavior provides
55 | // for efficient DFA representation of lexer actions which appear at the end
56 | // of a lexer rule, even when the lexer rule matches a variable number of
57 | // characters.
58 | //
59 | // Prior to traversing a match transition in the ATN, the current offset
60 | // from the token start index is assigned to all position-dependent lexer
61 | // actions which have not already been assigned a fixed offset. By storing
62 | // the offsets relative to the token start index, the DFA representation of
63 | // lexer actions which appear in the middle of tokens remains efficient due
64 | // to sharing among tokens of the same length, regardless of their absolute
65 | // position in the input stream.
66 | //
67 | // If the current executor already has offsets assigned to all
68 | // position-dependent lexer actions, the method returns {@code this}.
69 | //
70 | // @param offset The current offset to assign to all position-dependent
71 | // lexer actions which do not already have offsets assigned.
72 | //
73 | // @return A {@link LexerActionExecutor} which stores input stream offsets
74 | // for all position-dependent lexer actions.
75 | // /
76 | LexerActionExecutor.prototype.fixOffsetBeforeMatch = function(offset) {
77 | var updatedLexerActions = null;
78 | for (var i = 0; i < this.lexerActions.length; i++) {
79 | if (this.lexerActions[i].isPositionDependent &&
80 | !(this.lexerActions[i] instanceof LexerIndexedCustomAction)) {
81 | if (updatedLexerActions === null) {
82 | updatedLexerActions = this.lexerActions.concat([]);
83 | }
84 | updatedLexerActions[i] = new LexerIndexedCustomAction(offset,
85 | this.lexerActions[i]);
86 | }
87 | }
88 | if (updatedLexerActions === null) {
89 | return this;
90 | } else {
91 | return new LexerActionExecutor(updatedLexerActions);
92 | }
93 | };
94 |
95 | // Execute the actions encapsulated by this executor within the context of a
96 | // particular {@link Lexer}.
97 | //
98 | // This method calls {@link IntStream//seek} to set the position of the
99 | // {@code input} {@link CharStream} prior to calling
100 | // {@link LexerAction//execute} on a position-dependent action. Before the
101 | // method returns, the input position will be restored to the same position
102 | // it was in when the method was invoked.
103 | //
104 | // @param lexer The lexer instance.
105 | // @param input The input stream which is the source for the current token.
106 | // When this method is called, the current {@link IntStream//index} for
107 | // {@code input} should be the start of the following token, i.e. 1
108 | // character past the end of the current token.
109 | // @param startIndex The token start index. This value may be passed to
110 | // {@link IntStream//seek} to set the {@code input} position to the beginning
111 | // of the token.
112 | // /
113 | LexerActionExecutor.prototype.execute = function(lexer, input, startIndex) {
114 | var requiresSeek = false;
115 | var stopIndex = input.index;
116 | try {
117 | for (var i = 0; i < this.lexerActions.length; i++) {
118 | var lexerAction = this.lexerActions[i];
119 | if (lexerAction instanceof LexerIndexedCustomAction) {
120 | var offset = lexerAction.offset;
121 | input.seek(startIndex + offset);
122 | lexerAction = lexerAction.action;
123 | requiresSeek = (startIndex + offset) !== stopIndex;
124 | } else if (lexerAction.isPositionDependent) {
125 | input.seek(stopIndex);
126 | requiresSeek = false;
127 | }
128 | lexerAction.execute(lexer);
129 | }
130 | } finally {
131 | if (requiresSeek) {
132 | input.seek(stopIndex);
133 | }
134 | }
135 | };
136 |
137 | LexerActionExecutor.prototype.hashCode = function() {
138 | return this.cachedHashCode;
139 | };
140 |
141 | LexerActionExecutor.prototype.updateHashCode = function(hash) {
142 | hash.update(this.cachedHashCode);
143 | };
144 |
145 |
146 | LexerActionExecutor.prototype.equals = function(other) {
147 | if (this === other) {
148 | return true;
149 | } else if (!(other instanceof LexerActionExecutor)) {
150 | return false;
151 | } else if (this.cachedHashCode != other.cachedHashCode) {
152 | return false;
153 | } else if (this.lexerActions.length != other.lexerActions.length) {
154 | return false;
155 | } else {
156 | var numActions = this.lexerActions.length
157 | for (var idx = 0; idx < numActions; ++idx) {
158 | if (!this.lexerActions[idx].equals(other.lexerActions[idx])) {
159 | return false;
160 | }
161 | }
162 | return true;
163 | }
164 | };
165 |
166 | exports.LexerActionExecutor = LexerActionExecutor;
167 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/atn/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | exports.ATN = require('./ATN').ATN;
7 | exports.ATNDeserializer = require('./ATNDeserializer').ATNDeserializer;
8 | exports.LexerATNSimulator = require('./LexerATNSimulator').LexerATNSimulator;
9 | exports.ParserATNSimulator = require('./ParserATNSimulator').ParserATNSimulator;
10 | exports.PredictionMode = require('./PredictionMode').PredictionMode;
11 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/dfa/DFA.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 |
7 | var Set = require("../Utils").Set;
8 | var DFAState = require('./DFAState').DFAState;
9 | var StarLoopEntryState = require('../atn/ATNState').StarLoopEntryState;
10 | var ATNConfigSet = require('./../atn/ATNConfigSet').ATNConfigSet;
11 | var DFASerializer = require('./DFASerializer').DFASerializer;
12 | var LexerDFASerializer = require('./DFASerializer').LexerDFASerializer;
13 |
14 |
15 |
16 | function DFA(atnStartState, decision) {
17 | if (decision === undefined) {
18 | decision = 0;
19 | }
20 | // From which ATN state did we create this DFA?
21 | this.atnStartState = atnStartState;
22 | this.decision = decision;
23 | // A set of all DFA states. Use {@link Map} so we can get old state back
24 | // ({@link Set} only allows you to see if it's there).
25 | this._states = new Set();
26 | this.s0 = null;
27 | // {@code true} if this DFA is for a precedence decision; otherwise,
28 | // {@code false}. This is the backing field for {@link //isPrecedenceDfa},
29 | // {@link //setPrecedenceDfa}.
30 | this.precedenceDfa = false;
31 | if (atnStartState instanceof StarLoopEntryState)
32 | {
33 | if (atnStartState.isPrecedenceDecision) {
34 | this.precedenceDfa = true;
35 | var precedenceState = new DFAState(null, new ATNConfigSet());
36 | precedenceState.edges = [];
37 | precedenceState.isAcceptState = false;
38 | precedenceState.requiresFullContext = false;
39 | this.s0 = precedenceState;
40 | }
41 | }
42 | return this;
43 | }
44 |
45 | // Get the start state for a specific precedence value.
46 | //
47 | // @param precedence The current precedence.
48 | // @return The start state corresponding to the specified precedence, or
49 | // {@code null} if no start state exists for the specified precedence.
50 | //
51 | // @throws IllegalStateException if this is not a precedence DFA.
52 | // @see //isPrecedenceDfa()
53 |
54 | DFA.prototype.getPrecedenceStartState = function(precedence) {
55 | if (!(this.precedenceDfa)) {
56 | throw ("Only precedence DFAs may contain a precedence start state.");
57 | }
58 | // s0.edges is never null for a precedence DFA
59 | if (precedence < 0 || precedence >= this.s0.edges.length) {
60 | return null;
61 | }
62 | return this.s0.edges[precedence] || null;
63 | };
64 |
65 | // Set the start state for a specific precedence value.
66 | //
67 | // @param precedence The current precedence.
68 | // @param startState The start state corresponding to the specified
69 | // precedence.
70 | //
71 | // @throws IllegalStateException if this is not a precedence DFA.
72 | // @see //isPrecedenceDfa()
73 | //
74 | DFA.prototype.setPrecedenceStartState = function(precedence, startState) {
75 | if (!(this.precedenceDfa)) {
76 | throw ("Only precedence DFAs may contain a precedence start state.");
77 | }
78 | if (precedence < 0) {
79 | return;
80 | }
81 |
82 | // synchronization on s0 here is ok. when the DFA is turned into a
83 | // precedence DFA, s0 will be initialized once and not updated again
84 | // s0.edges is never null for a precedence DFA
85 | this.s0.edges[precedence] = startState;
86 | };
87 |
88 | //
89 | // Sets whether this is a precedence DFA. If the specified value differs
90 | // from the current DFA configuration, the following actions are taken;
91 | // otherwise no changes are made to the current DFA.
92 | //
93 | //
94 | // - The {@link //states} map is cleared
95 | // - If {@code precedenceDfa} is {@code false}, the initial state
96 | // {@link //s0} is set to {@code null}; otherwise, it is initialized to a new
97 | // {@link DFAState} with an empty outgoing {@link DFAState//edges} array to
98 | // store the start states for individual precedence values.
99 | // - The {@link //precedenceDfa} field is updated
100 | //
101 | //
102 | // @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
103 | // {@code false}
104 |
105 | DFA.prototype.setPrecedenceDfa = function(precedenceDfa) {
106 | if (this.precedenceDfa!==precedenceDfa) {
107 | this._states = new DFAStatesSet();
108 | if (precedenceDfa) {
109 | var precedenceState = new DFAState(null, new ATNConfigSet());
110 | precedenceState.edges = [];
111 | precedenceState.isAcceptState = false;
112 | precedenceState.requiresFullContext = false;
113 | this.s0 = precedenceState;
114 | } else {
115 | this.s0 = null;
116 | }
117 | this.precedenceDfa = precedenceDfa;
118 | }
119 | };
120 |
121 | Object.defineProperty(DFA.prototype, "states", {
122 | get : function() {
123 | return this._states;
124 | }
125 | });
126 |
127 | // Return a list of all states in this DFA, ordered by state number.
128 | DFA.prototype.sortedStates = function() {
129 | var list = this._states.values();
130 | return list.sort(function(a, b) {
131 | return a.stateNumber - b.stateNumber;
132 | });
133 | };
134 |
135 | DFA.prototype.toString = function(literalNames, symbolicNames) {
136 | literalNames = literalNames || null;
137 | symbolicNames = symbolicNames || null;
138 | if (this.s0 === null) {
139 | return "";
140 | }
141 | var serializer = new DFASerializer(this, literalNames, symbolicNames);
142 | return serializer.toString();
143 | };
144 |
145 | DFA.prototype.toLexerString = function() {
146 | if (this.s0 === null) {
147 | return "";
148 | }
149 | var serializer = new LexerDFASerializer(this);
150 | return serializer.toString();
151 | };
152 |
153 | exports.DFA = DFA;
154 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/dfa/DFASerializer.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | // A DFA walker that knows how to dump them to serialized strings.#/
7 |
8 |
9 | function DFASerializer(dfa, literalNames, symbolicNames) {
10 | this.dfa = dfa;
11 | this.literalNames = literalNames || [];
12 | this.symbolicNames = symbolicNames || [];
13 | return this;
14 | }
15 |
16 | DFASerializer.prototype.toString = function() {
17 | if(this.dfa.s0 === null) {
18 | return null;
19 | }
20 | var buf = "";
21 | var states = this.dfa.sortedStates();
22 | for(var i=0;i");
33 | buf = buf.concat(this.getStateString(t));
34 | buf = buf.concat('\n');
35 | }
36 | }
37 | }
38 | }
39 | return buf.length===0 ? null : buf;
40 | };
41 |
42 | DFASerializer.prototype.getEdgeLabel = function(i) {
43 | if (i===0) {
44 | return "EOF";
45 | } else if(this.literalNames !==null || this.symbolicNames!==null) {
46 | return this.literalNames[i-1] || this.symbolicNames[i-1];
47 | } else {
48 | return String.fromCharCode(i-1);
49 | }
50 | };
51 |
52 | DFASerializer.prototype.getStateString = function(s) {
53 | var baseStateStr = ( s.isAcceptState ? ":" : "") + "s" + s.stateNumber + ( s.requiresFullContext ? "^" : "");
54 | if(s.isAcceptState) {
55 | if (s.predicates !== null) {
56 | return baseStateStr + "=>" + s.predicates.toString();
57 | } else {
58 | return baseStateStr + "=>" + s.prediction.toString();
59 | }
60 | } else {
61 | return baseStateStr;
62 | }
63 | };
64 |
65 | function LexerDFASerializer(dfa) {
66 | DFASerializer.call(this, dfa, null);
67 | return this;
68 | }
69 |
70 | LexerDFASerializer.prototype = Object.create(DFASerializer.prototype);
71 | LexerDFASerializer.prototype.constructor = LexerDFASerializer;
72 |
73 | LexerDFASerializer.prototype.getEdgeLabel = function(i) {
74 | return "'" + String.fromCharCode(i) + "'";
75 | };
76 |
77 | exports.DFASerializer = DFASerializer;
78 | exports.LexerDFASerializer = LexerDFASerializer;
79 |
80 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/dfa/DFAState.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | ///
7 |
8 | var ATNConfigSet = require('./../atn/ATNConfigSet').ATNConfigSet;
9 | var Utils = require('./../Utils');
10 | var Hash = Utils.Hash;
11 | var Set = Utils.Set;
12 |
13 | // Map a predicate to a predicted alternative.///
14 |
15 | function PredPrediction(pred, alt) {
16 | this.alt = alt;
17 | this.pred = pred;
18 | return this;
19 | }
20 |
21 | PredPrediction.prototype.toString = function() {
22 | return "(" + this.pred + ", " + this.alt + ")";
23 | };
24 |
25 | // A DFA state represents a set of possible ATN configurations.
26 | // As Aho, Sethi, Ullman p. 117 says "The DFA uses its state
27 | // to keep track of all possible states the ATN can be in after
28 | // reading each input symbol. That is to say, after reading
29 | // input a1a2..an, the DFA is in a state that represents the
30 | // subset T of the states of the ATN that are reachable from the
31 | // ATN's start state along some path labeled a1a2..an."
32 | // In conventional NFA→DFA conversion, therefore, the subset T
33 | // would be a bitset representing the set of states the
34 | // ATN could be in. We need to track the alt predicted by each
35 | // state as well, however. More importantly, we need to maintain
36 | // a stack of states, tracking the closure operations as they
37 | // jump from rule to rule, emulating rule invocations (method calls).
38 | // I have to add a stack to simulate the proper lookahead sequences for
39 | // the underlying LL grammar from which the ATN was derived.
40 | //
41 | // I use a set of ATNConfig objects not simple states. An ATNConfig
42 | // is both a state (ala normal conversion) and a RuleContext describing
43 | // the chain of rules (if any) followed to arrive at that state.
44 | //
45 | // A DFA state may have multiple references to a particular state,
46 | // but with different ATN contexts (with same or different alts)
47 | // meaning that state was reached via a different set of rule invocations.
48 | // /
49 |
50 | function DFAState(stateNumber, configs) {
51 | if (stateNumber === null) {
52 | stateNumber = -1;
53 | }
54 | if (configs === null) {
55 | configs = new ATNConfigSet();
56 | }
57 | this.stateNumber = stateNumber;
58 | this.configs = configs;
59 | // {@code edges[symbol]} points to target of symbol. Shift up by 1 so (-1)
60 | // {@link Token//EOF} maps to {@code edges[0]}.
61 | this.edges = null;
62 | this.isAcceptState = false;
63 | // if accept state, what ttype do we match or alt do we predict?
64 | // This is set to {@link ATN//INVALID_ALT_NUMBER} when {@link
65 | // //predicates}{@code !=null} or
66 | // {@link //requiresFullContext}.
67 | this.prediction = 0;
68 | this.lexerActionExecutor = null;
69 | // Indicates that this state was created during SLL prediction that
70 | // discovered a conflict between the configurations in the state. Future
71 | // {@link ParserATNSimulator//execATN} invocations immediately jumped doing
72 | // full context prediction if this field is true.
73 | this.requiresFullContext = false;
74 | // During SLL parsing, this is a list of predicates associated with the
75 | // ATN configurations of the DFA state. When we have predicates,
76 | // {@link //requiresFullContext} is {@code false} since full context
77 | // prediction evaluates predicates
78 | // on-the-fly. If this is not null, then {@link //prediction} is
79 | // {@link ATN//INVALID_ALT_NUMBER}.
80 | //
81 | // We only use these for non-{@link //requiresFullContext} but
82 | // conflicting states. That
83 | // means we know from the context (it's $ or we don't dip into outer
84 | // context) that it's an ambiguity not a conflict.
85 | //
86 | // This list is computed by {@link
87 | // ParserATNSimulator//predicateDFAState}.
88 | this.predicates = null;
89 | return this;
90 | }
91 |
92 | // Get the set of all alts mentioned by all ATN configurations in this
93 | // DFA state.
94 | DFAState.prototype.getAltSet = function() {
95 | var alts = new Set();
96 | if (this.configs !== null) {
97 | for (var i = 0; i < this.configs.length; i++) {
98 | var c = this.configs[i];
99 | alts.add(c.alt);
100 | }
101 | }
102 | if (alts.length === 0) {
103 | return null;
104 | } else {
105 | return alts;
106 | }
107 | };
108 |
109 | // Two {@link DFAState} instances are equal if their ATN configuration sets
110 | // are the same. This method is used to see if a state already exists.
111 | //
112 | // Because the number of alternatives and number of ATN configurations are
113 | // finite, there is a finite number of DFA states that can be processed.
114 | // This is necessary to show that the algorithm terminates.
115 | //
116 | // Cannot test the DFA state numbers here because in
117 | // {@link ParserATNSimulator//addDFAState} we need to know if any other state
118 | // exists that has this exact set of ATN configurations. The
119 | // {@link //stateNumber} is irrelevant.
120 | DFAState.prototype.equals = function(other) {
121 | // compare set of ATN configurations in this set with other
122 | return this === other ||
123 | (other instanceof DFAState &&
124 | this.configs.equals(other.configs));
125 | };
126 |
127 | DFAState.prototype.toString = function() {
128 | var s = "" + this.stateNumber + ":" + this.configs;
129 | if(this.isAcceptState) {
130 | s = s + "=>";
131 | if (this.predicates !== null)
132 | s = s + this.predicates;
133 | else
134 | s = s + this.prediction;
135 | }
136 | return s;
137 | };
138 |
139 | DFAState.prototype.hashCode = function() {
140 | var hash = new Hash();
141 | hash.update(this.configs);
142 | if(this.isAcceptState) {
143 | if (this.predicates !== null)
144 | hash.update(this.predicates);
145 | else
146 | hash.update(this.prediction);
147 | }
148 | return hash.finish();
149 | };
150 |
151 | exports.DFAState = DFAState;
152 | exports.PredPrediction = PredPrediction;
153 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/dfa/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | exports.DFA = require('./DFA').DFA;
7 | exports.DFASerializer = require('./DFASerializer').DFASerializer;
8 | exports.LexerDFASerializer = require('./DFASerializer').LexerDFASerializer;
9 | exports.PredPrediction = require('./DFAState').PredPrediction;
10 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/error/DiagnosticErrorListener.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 | //
7 |
8 | //
9 | // This implementation of {@link ANTLRErrorListener} can be used to identify
10 | // certain potential correctness and performance problems in grammars. "Reports"
11 | // are made by calling {@link Parser//notifyErrorListeners} with the appropriate
12 | // message.
13 | //
14 | //
15 | // - Ambiguities: These are cases where more than one path through the
16 | // grammar can match the input.
17 | // - Weak context sensitivity: These are cases where full-context
18 | // prediction resolved an SLL conflict to a unique alternative which equaled the
19 | // minimum alternative of the SLL conflict.
20 | // - Strong (forced) context sensitivity: These are cases where the
21 | // full-context prediction resolved an SLL conflict to a unique alternative,
22 | // and the minimum alternative of the SLL conflict was found to not be
23 | // a truly viable alternative. Two-stage parsing cannot be used for inputs where
24 | // this situation occurs.
25 | //
26 |
27 | var BitSet = require('./../Utils').BitSet;
28 | var ErrorListener = require('./ErrorListener').ErrorListener;
29 | var Interval = require('./../IntervalSet').Interval;
30 |
31 | function DiagnosticErrorListener(exactOnly) {
32 | ErrorListener.call(this);
33 | exactOnly = exactOnly || true;
34 | // whether all ambiguities or only exact ambiguities are reported.
35 | this.exactOnly = exactOnly;
36 | return this;
37 | }
38 |
39 | DiagnosticErrorListener.prototype = Object.create(ErrorListener.prototype);
40 | DiagnosticErrorListener.prototype.constructor = DiagnosticErrorListener;
41 |
42 | DiagnosticErrorListener.prototype.reportAmbiguity = function(recognizer, dfa,
43 | startIndex, stopIndex, exact, ambigAlts, configs) {
44 | if (this.exactOnly && !exact) {
45 | return;
46 | }
47 | var msg = "reportAmbiguity d=" +
48 | this.getDecisionDescription(recognizer, dfa) +
49 | ": ambigAlts=" +
50 | this.getConflictingAlts(ambigAlts, configs) +
51 | ", input='" +
52 | recognizer.getTokenStream().getText(new Interval(startIndex, stopIndex)) + "'";
53 | recognizer.notifyErrorListeners(msg);
54 | };
55 |
56 | DiagnosticErrorListener.prototype.reportAttemptingFullContext = function(
57 | recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) {
58 | var msg = "reportAttemptingFullContext d=" +
59 | this.getDecisionDescription(recognizer, dfa) +
60 | ", input='" +
61 | recognizer.getTokenStream().getText(new Interval(startIndex, stopIndex)) + "'";
62 | recognizer.notifyErrorListeners(msg);
63 | };
64 |
65 | DiagnosticErrorListener.prototype.reportContextSensitivity = function(
66 | recognizer, dfa, startIndex, stopIndex, prediction, configs) {
67 | var msg = "reportContextSensitivity d=" +
68 | this.getDecisionDescription(recognizer, dfa) +
69 | ", input='" +
70 | recognizer.getTokenStream().getText(new Interval(startIndex, stopIndex)) + "'";
71 | recognizer.notifyErrorListeners(msg);
72 | };
73 |
74 | DiagnosticErrorListener.prototype.getDecisionDescription = function(recognizer, dfa) {
75 | var decision = dfa.decision;
76 | var ruleIndex = dfa.atnStartState.ruleIndex;
77 |
78 | var ruleNames = recognizer.ruleNames;
79 | if (ruleIndex < 0 || ruleIndex >= ruleNames.length) {
80 | return "" + decision;
81 | }
82 | var ruleName = ruleNames[ruleIndex] || null;
83 | if (ruleName === null || ruleName.length === 0) {
84 | return "" + decision;
85 | }
86 | return "" + decision + " (" + ruleName + ")";
87 | };
88 |
89 | //
90 | // Computes the set of conflicting or ambiguous alternatives from a
91 | // configuration set, if that information was not already provided by the
92 | // parser.
93 | //
94 | // @param reportedAlts The set of conflicting or ambiguous alternatives, as
95 | // reported by the parser.
96 | // @param configs The conflicting or ambiguous configuration set.
97 | // @return Returns {@code reportedAlts} if it is not {@code null}, otherwise
98 | // returns the set of alternatives represented in {@code configs}.
99 | //
100 | DiagnosticErrorListener.prototype.getConflictingAlts = function(reportedAlts, configs) {
101 | if (reportedAlts !== null) {
102 | return reportedAlts;
103 | }
104 | var result = new BitSet();
105 | for (var i = 0; i < configs.items.length; i++) {
106 | result.add(configs.items[i].alt);
107 | }
108 | return "{" + result.values().join(", ") + "}";
109 | };
110 |
111 | exports.DiagnosticErrorListener = DiagnosticErrorListener;
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/error/ErrorListener.js:
--------------------------------------------------------------------------------
1 | //
2 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
3 | * Use of this file is governed by the BSD 3-clause license that
4 | * can be found in the LICENSE.txt file in the project root.
5 | */
6 |
7 | // Provides an empty default implementation of {@link ANTLRErrorListener}. The
8 | // default implementation of each method does nothing, but can be overridden as
9 | // necessary.
10 |
11 | function ErrorListener() {
12 | return this;
13 | }
14 |
15 | ErrorListener.prototype.syntaxError = function(recognizer, offendingSymbol, line, column, msg, e) {
16 | };
17 |
18 | ErrorListener.prototype.reportAmbiguity = function(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) {
19 | };
20 |
21 | ErrorListener.prototype.reportAttemptingFullContext = function(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) {
22 | };
23 |
24 | ErrorListener.prototype.reportContextSensitivity = function(recognizer, dfa, startIndex, stopIndex, prediction, configs) {
25 | };
26 |
27 | function ConsoleErrorListener() {
28 | ErrorListener.call(this);
29 | return this;
30 | }
31 |
32 | ConsoleErrorListener.prototype = Object.create(ErrorListener.prototype);
33 | ConsoleErrorListener.prototype.constructor = ConsoleErrorListener;
34 |
35 | //
36 | // Provides a default instance of {@link ConsoleErrorListener}.
37 | //
38 | ConsoleErrorListener.INSTANCE = new ConsoleErrorListener();
39 |
40 | //
41 | // {@inheritDoc}
42 | //
43 | //
44 | // This implementation prints messages to {@link System//err} containing the
45 | // values of {@code line}, {@code charPositionInLine}, and {@code msg} using
46 | // the following format.
47 | //
48 | //
49 | // line line:charPositionInLine msg
50 | //
51 | //
52 | ConsoleErrorListener.prototype.syntaxError = function(recognizer, offendingSymbol, line, column, msg, e) {
53 | console.error("line " + line + ":" + column + " " + msg);
54 | };
55 |
56 | function ProxyErrorListener(delegates) {
57 | ErrorListener.call(this);
58 | if (delegates===null) {
59 | throw "delegates";
60 | }
61 | this.delegates = delegates;
62 | return this;
63 | }
64 |
65 | ProxyErrorListener.prototype = Object.create(ErrorListener.prototype);
66 | ProxyErrorListener.prototype.constructor = ProxyErrorListener;
67 |
68 | ProxyErrorListener.prototype.syntaxError = function(recognizer, offendingSymbol, line, column, msg, e) {
69 | this.delegates.map(function(d) { d.syntaxError(recognizer, offendingSymbol, line, column, msg, e); });
70 | };
71 |
72 | ProxyErrorListener.prototype.reportAmbiguity = function(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) {
73 | this.delegates.map(function(d) { d.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs); });
74 | };
75 |
76 | ProxyErrorListener.prototype.reportAttemptingFullContext = function(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) {
77 | this.delegates.map(function(d) { d.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs); });
78 | };
79 |
80 | ProxyErrorListener.prototype.reportContextSensitivity = function(recognizer, dfa, startIndex, stopIndex, prediction, configs) {
81 | this.delegates.map(function(d) { d.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs); });
82 | };
83 |
84 | exports.ErrorListener = ErrorListener;
85 | exports.ConsoleErrorListener = ConsoleErrorListener;
86 | exports.ProxyErrorListener = ProxyErrorListener;
87 |
88 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/error/Errors.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | // The root of the ANTLR exception hierarchy. In general, ANTLR tracks just
7 | // 3 kinds of errors: prediction errors, failed predicate errors, and
8 | // mismatched input errors. In each case, the parser knows where it is
9 | // in the input, where it is in the ATN, the rule invocation stack,
10 | // and what kind of problem occurred.
11 |
12 | var PredicateTransition = require('./../atn/Transition').PredicateTransition;
13 |
14 | function RecognitionException(params) {
15 | Error.call(this);
16 | if (!!Error.captureStackTrace) {
17 | Error.captureStackTrace(this, RecognitionException);
18 | } else {
19 | var stack = new Error().stack;
20 | }
21 | this.message = params.message;
22 | this.recognizer = params.recognizer;
23 | this.input = params.input;
24 | this.ctx = params.ctx;
25 | // The current {@link Token} when an error occurred. Since not all streams
26 | // support accessing symbols by index, we have to track the {@link Token}
27 | // instance itself.
28 | this.offendingToken = null;
29 | // Get the ATN state number the parser was in at the time the error
30 | // occurred. For {@link NoViableAltException} and
31 | // {@link LexerNoViableAltException} exceptions, this is the
32 | // {@link DecisionState} number. For others, it is the state whose outgoing
33 | // edge we couldn't match.
34 | this.offendingState = -1;
35 | if (this.recognizer!==null) {
36 | this.offendingState = this.recognizer.state;
37 | }
38 | return this;
39 | }
40 |
41 | RecognitionException.prototype = Object.create(Error.prototype);
42 | RecognitionException.prototype.constructor = RecognitionException;
43 |
44 | // If the state number is not known, this method returns -1.
45 |
46 | //
47 | // Gets the set of input symbols which could potentially follow the
48 | // previously matched symbol at the time this exception was thrown.
49 | //
50 | // If the set of expected tokens is not known and could not be computed,
51 | // this method returns {@code null}.
52 | //
53 | // @return The set of token types that could potentially follow the current
54 | // state in the ATN, or {@code null} if the information is not available.
55 | // /
56 | RecognitionException.prototype.getExpectedTokens = function() {
57 | if (this.recognizer!==null) {
58 | return this.recognizer.atn.getExpectedTokens(this.offendingState, this.ctx);
59 | } else {
60 | return null;
61 | }
62 | };
63 |
64 | RecognitionException.prototype.toString = function() {
65 | return this.message;
66 | };
67 |
68 | function LexerNoViableAltException(lexer, input, startIndex, deadEndConfigs) {
69 | RecognitionException.call(this, {message:"", recognizer:lexer, input:input, ctx:null});
70 | this.startIndex = startIndex;
71 | this.deadEndConfigs = deadEndConfigs;
72 | return this;
73 | }
74 |
75 | LexerNoViableAltException.prototype = Object.create(RecognitionException.prototype);
76 | LexerNoViableAltException.prototype.constructor = LexerNoViableAltException;
77 |
78 | LexerNoViableAltException.prototype.toString = function() {
79 | var symbol = "";
80 | if (this.startIndex >= 0 && this.startIndex < this.input.size) {
81 | symbol = this.input.getText((this.startIndex,this.startIndex));
82 | }
83 | return "LexerNoViableAltException" + symbol;
84 | };
85 |
86 | // Indicates that the parser could not decide which of two or more paths
87 | // to take based upon the remaining input. It tracks the starting token
88 | // of the offending input and also knows where the parser was
89 | // in the various paths when the error. Reported by reportNoViableAlternative()
90 | //
91 | function NoViableAltException(recognizer, input, startToken, offendingToken, deadEndConfigs, ctx) {
92 | ctx = ctx || recognizer._ctx;
93 | offendingToken = offendingToken || recognizer.getCurrentToken();
94 | startToken = startToken || recognizer.getCurrentToken();
95 | input = input || recognizer.getInputStream();
96 | RecognitionException.call(this, {message:"", recognizer:recognizer, input:input, ctx:ctx});
97 | // Which configurations did we try at input.index() that couldn't match
98 | // input.LT(1)?//
99 | this.deadEndConfigs = deadEndConfigs;
100 | // The token object at the start index; the input stream might
101 | // not be buffering tokens so get a reference to it. (At the
102 | // time the error occurred, of course the stream needs to keep a
103 | // buffer all of the tokens but later we might not have access to those.)
104 | this.startToken = startToken;
105 | this.offendingToken = offendingToken;
106 | }
107 |
108 | NoViableAltException.prototype = Object.create(RecognitionException.prototype);
109 | NoViableAltException.prototype.constructor = NoViableAltException;
110 |
111 | // This signifies any kind of mismatched input exceptions such as
112 | // when the current input does not match the expected token.
113 | //
114 | function InputMismatchException(recognizer) {
115 | RecognitionException.call(this, {message:"", recognizer:recognizer, input:recognizer.getInputStream(), ctx:recognizer._ctx});
116 | this.offendingToken = recognizer.getCurrentToken();
117 | }
118 |
119 | InputMismatchException.prototype = Object.create(RecognitionException.prototype);
120 | InputMismatchException.prototype.constructor = InputMismatchException;
121 |
122 | // A semantic predicate failed during validation. Validation of predicates
123 | // occurs when normally parsing the alternative just like matching a token.
124 | // Disambiguating predicate evaluation occurs when we test a predicate during
125 | // prediction.
126 |
127 | function FailedPredicateException(recognizer, predicate, message) {
128 | RecognitionException.call(this, {message:this.formatMessage(predicate,message || null), recognizer:recognizer,
129 | input:recognizer.getInputStream(), ctx:recognizer._ctx});
130 | var s = recognizer._interp.atn.states[recognizer.state];
131 | var trans = s.transitions[0];
132 | if (trans instanceof PredicateTransition) {
133 | this.ruleIndex = trans.ruleIndex;
134 | this.predicateIndex = trans.predIndex;
135 | } else {
136 | this.ruleIndex = 0;
137 | this.predicateIndex = 0;
138 | }
139 | this.predicate = predicate;
140 | this.offendingToken = recognizer.getCurrentToken();
141 | return this;
142 | }
143 |
144 | FailedPredicateException.prototype = Object.create(RecognitionException.prototype);
145 | FailedPredicateException.prototype.constructor = FailedPredicateException;
146 |
147 | FailedPredicateException.prototype.formatMessage = function(predicate, message) {
148 | if (message !==null) {
149 | return message;
150 | } else {
151 | return "failed predicate: {" + predicate + "}?";
152 | }
153 | };
154 |
155 | function ParseCancellationException() {
156 | Error.call(this);
157 | Error.captureStackTrace(this, ParseCancellationException);
158 | return this;
159 | }
160 |
161 | ParseCancellationException.prototype = Object.create(Error.prototype);
162 | ParseCancellationException.prototype.constructor = ParseCancellationException;
163 |
164 | exports.RecognitionException = RecognitionException;
165 | exports.NoViableAltException = NoViableAltException;
166 | exports.LexerNoViableAltException = LexerNoViableAltException;
167 | exports.InputMismatchException = InputMismatchException;
168 | exports.FailedPredicateException = FailedPredicateException;
169 | exports.ParseCancellationException = ParseCancellationException;
170 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/error/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | exports.RecognitionException = require('./Errors').RecognitionException;
7 | exports.NoViableAltException = require('./Errors').NoViableAltException;
8 | exports.LexerNoViableAltException = require('./Errors').LexerNoViableAltException;
9 | exports.InputMismatchException = require('./Errors').InputMismatchException;
10 | exports.FailedPredicateException = require('./Errors').FailedPredicateException;
11 | exports.DiagnosticErrorListener = require('./DiagnosticErrorListener').DiagnosticErrorListener;
12 | exports.BailErrorStrategy = require('./ErrorStrategy').BailErrorStrategy;
13 | exports.ErrorListener = require('./ErrorListener').ErrorListener;
14 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 | exports.atn = require('./atn/index');
6 | exports.codepointat = require('./polyfills/codepointat');
7 | exports.dfa = require('./dfa/index');
8 | exports.fromcodepoint = require('./polyfills/fromcodepoint');
9 | exports.tree = require('./tree/index');
10 | exports.error = require('./error/index');
11 | exports.Token = require('./Token').Token;
12 | exports.CharStreams = require('./CharStreams').CharStreams;
13 | exports.CommonToken = require('./Token').CommonToken;
14 | exports.InputStream = require('./InputStream').InputStream;
15 | exports.FileStream = require('./FileStream').FileStream;
16 | exports.CommonTokenStream = require('./CommonTokenStream').CommonTokenStream;
17 | exports.Lexer = require('./Lexer').Lexer;
18 | exports.Parser = require('./Parser').Parser;
19 | var pc = require('./PredictionContext');
20 | exports.PredictionContextCache = pc.PredictionContextCache;
21 | exports.ParserRuleContext = require('./ParserRuleContext').ParserRuleContext;
22 | exports.Interval = require('./IntervalSet').Interval;
23 | exports.Utils = require('./Utils');
24 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "antlr4",
3 | "version": "4.7.0",
4 | "description": "JavaScript runtime for ANTLR4",
5 | "main": "src/antlr4/index.js",
6 | "repository": "antlr/antlr4.git",
7 | "keywords": [
8 | "lexer",
9 | "parser",
10 | "antlr",
11 | "antlr4",
12 | "grammar"
13 | ],
14 | "license": "BSD",
15 | "bugs": {
16 | "url": "https://github.com/antlr/antlr4/issues"
17 | },
18 | "homepage": "https://github.com/antlr/antlr4"
19 | }
20 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/polyfills/codepointat.js:
--------------------------------------------------------------------------------
1 | /*! https://mths.be/codepointat v0.2.0 by @mathias */
2 | if (!String.prototype.codePointAt) {
3 | (function() {
4 | 'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
5 | var defineProperty = (function() {
6 | // IE 8 only supports `Object.defineProperty` on DOM elements
7 | try {
8 | var object = {};
9 | var $defineProperty = Object.defineProperty;
10 | var result = $defineProperty(object, object, object) && $defineProperty;
11 | } catch(error) {}
12 | return result;
13 | }());
14 | var codePointAt = function(position) {
15 | if (this == null) {
16 | throw TypeError();
17 | }
18 | var string = String(this);
19 | var size = string.length;
20 | // `ToInteger`
21 | var index = position ? Number(position) : 0;
22 | if (index != index) { // better `isNaN`
23 | index = 0;
24 | }
25 | // Account for out-of-bounds indices:
26 | if (index < 0 || index >= size) {
27 | return undefined;
28 | }
29 | // Get the first code unit
30 | var first = string.charCodeAt(index);
31 | var second;
32 | if ( // check if it’s the start of a surrogate pair
33 | first >= 0xD800 && first <= 0xDBFF && // high surrogate
34 | size > index + 1 // there is a next code unit
35 | ) {
36 | second = string.charCodeAt(index + 1);
37 | if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
38 | // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
39 | return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
40 | }
41 | }
42 | return first;
43 | };
44 | if (defineProperty) {
45 | defineProperty(String.prototype, 'codePointAt', {
46 | 'value': codePointAt,
47 | 'configurable': true,
48 | 'writable': true
49 | });
50 | } else {
51 | String.prototype.codePointAt = codePointAt;
52 | }
53 | }());
54 | }
55 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/polyfills/fromcodepoint.js:
--------------------------------------------------------------------------------
1 | /*! https://mths.be/fromcodepoint v0.2.1 by @mathias */
2 | if (!String.fromCodePoint) {
3 | (function() {
4 | var defineProperty = (function() {
5 | // IE 8 only supports `Object.defineProperty` on DOM elements
6 | try {
7 | var object = {};
8 | var $defineProperty = Object.defineProperty;
9 | var result = $defineProperty(object, object, object) && $defineProperty;
10 | } catch(error) {}
11 | return result;
12 | }());
13 | var stringFromCharCode = String.fromCharCode;
14 | var floor = Math.floor;
15 | var fromCodePoint = function(_) {
16 | var MAX_SIZE = 0x4000;
17 | var codeUnits = [];
18 | var highSurrogate;
19 | var lowSurrogate;
20 | var index = -1;
21 | var length = arguments.length;
22 | if (!length) {
23 | return '';
24 | }
25 | var result = '';
26 | while (++index < length) {
27 | var codePoint = Number(arguments[index]);
28 | if (
29 | !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
30 | codePoint < 0 || // not a valid Unicode code point
31 | codePoint > 0x10FFFF || // not a valid Unicode code point
32 | floor(codePoint) != codePoint // not an integer
33 | ) {
34 | throw RangeError('Invalid code point: ' + codePoint);
35 | }
36 | if (codePoint <= 0xFFFF) { // BMP code point
37 | codeUnits.push(codePoint);
38 | } else { // Astral code point; split in surrogate halves
39 | // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
40 | codePoint -= 0x10000;
41 | highSurrogate = (codePoint >> 10) + 0xD800;
42 | lowSurrogate = (codePoint % 0x400) + 0xDC00;
43 | codeUnits.push(highSurrogate, lowSurrogate);
44 | }
45 | if (index + 1 == length || codeUnits.length > MAX_SIZE) {
46 | result += stringFromCharCode.apply(null, codeUnits);
47 | codeUnits.length = 0;
48 | }
49 | }
50 | return result;
51 | };
52 | if (defineProperty) {
53 | defineProperty(String, 'fromCodePoint', {
54 | 'value': fromCodePoint,
55 | 'configurable': true,
56 | 'writable': true
57 | });
58 | } else {
59 | String.fromCodePoint = fromCodePoint;
60 | }
61 | }());
62 | }
63 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/tree/Tree.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 | ///
6 |
7 | // The basic notion of a tree has a parent, a payload, and a list of children.
8 | // It is the most abstract interface for all the trees used by ANTLR.
9 | ///
10 |
11 | var Token = require('./../Token').Token;
12 | var Interval = require('./../IntervalSet').Interval;
13 | var INVALID_INTERVAL = new Interval(-1, -2);
14 | var Utils = require('../Utils.js');
15 |
16 |
17 | function Tree() {
18 | return this;
19 | }
20 |
21 | function SyntaxTree() {
22 | Tree.call(this);
23 | return this;
24 | }
25 |
26 | SyntaxTree.prototype = Object.create(Tree.prototype);
27 | SyntaxTree.prototype.constructor = SyntaxTree;
28 |
29 | function ParseTree() {
30 | SyntaxTree.call(this);
31 | return this;
32 | }
33 |
34 | ParseTree.prototype = Object.create(SyntaxTree.prototype);
35 | ParseTree.prototype.constructor = ParseTree;
36 |
37 | function RuleNode() {
38 | ParseTree.call(this);
39 | return this;
40 | }
41 |
42 | RuleNode.prototype = Object.create(ParseTree.prototype);
43 | RuleNode.prototype.constructor = RuleNode;
44 |
45 | function TerminalNode() {
46 | ParseTree.call(this);
47 | return this;
48 | }
49 |
50 | TerminalNode.prototype = Object.create(ParseTree.prototype);
51 | TerminalNode.prototype.constructor = TerminalNode;
52 |
53 | function ErrorNode() {
54 | TerminalNode.call(this);
55 | return this;
56 | }
57 |
58 | ErrorNode.prototype = Object.create(TerminalNode.prototype);
59 | ErrorNode.prototype.constructor = ErrorNode;
60 |
61 | function ParseTreeVisitor() {
62 | return this;
63 | }
64 |
65 | ParseTreeVisitor.prototype.visit = function(ctx) {
66 | if (Array.isArray(ctx)) {
67 | return ctx.map(function(child) {
68 | return child.accept(this);
69 | }, this);
70 | } else {
71 | return ctx.accept(this);
72 | }
73 | };
74 |
75 | ParseTreeVisitor.prototype.visitChildren = function(ctx) {
76 | return this.visit(ctx.children);
77 | }
78 |
79 | ParseTreeVisitor.prototype.visitTerminal = function(node) {
80 | };
81 |
82 | ParseTreeVisitor.prototype.visitErrorNode = function(node) {
83 | };
84 |
85 |
86 | function ParseTreeListener() {
87 | return this;
88 | }
89 |
90 | ParseTreeListener.prototype.visitTerminal = function(node) {
91 | };
92 |
93 | ParseTreeListener.prototype.visitErrorNode = function(node) {
94 | };
95 |
96 | ParseTreeListener.prototype.enterEveryRule = function(node) {
97 | };
98 |
99 | ParseTreeListener.prototype.exitEveryRule = function(node) {
100 | };
101 |
102 | function TerminalNodeImpl(symbol) {
103 | TerminalNode.call(this);
104 | this.parentCtx = null;
105 | this.symbol = symbol;
106 | return this;
107 | }
108 |
109 | TerminalNodeImpl.prototype = Object.create(TerminalNode.prototype);
110 | TerminalNodeImpl.prototype.constructor = TerminalNodeImpl;
111 |
112 | TerminalNodeImpl.prototype.getChild = function(i) {
113 | return null;
114 | };
115 |
116 | TerminalNodeImpl.prototype.getSymbol = function() {
117 | return this.symbol;
118 | };
119 |
120 | TerminalNodeImpl.prototype.getParent = function() {
121 | return this.parentCtx;
122 | };
123 |
124 | TerminalNodeImpl.prototype.getPayload = function() {
125 | return this.symbol;
126 | };
127 |
128 | TerminalNodeImpl.prototype.getSourceInterval = function() {
129 | if (this.symbol === null) {
130 | return INVALID_INTERVAL;
131 | }
132 | var tokenIndex = this.symbol.tokenIndex;
133 | return new Interval(tokenIndex, tokenIndex);
134 | };
135 |
136 | TerminalNodeImpl.prototype.getChildCount = function() {
137 | return 0;
138 | };
139 |
140 | TerminalNodeImpl.prototype.accept = function(visitor) {
141 | return visitor.visitTerminal(this);
142 | };
143 |
144 | TerminalNodeImpl.prototype.getText = function() {
145 | return this.symbol.text;
146 | };
147 |
148 | TerminalNodeImpl.prototype.toString = function() {
149 | if (this.symbol.type === Token.EOF) {
150 | return "";
151 | } else {
152 | return this.symbol.text;
153 | }
154 | };
155 |
156 | // Represents a token that was consumed during resynchronization
157 | // rather than during a valid match operation. For example,
158 | // we will create this kind of a node during single token insertion
159 | // and deletion as well as during "consume until error recovery set"
160 | // upon no viable alternative exceptions.
161 |
162 | function ErrorNodeImpl(token) {
163 | TerminalNodeImpl.call(this, token);
164 | return this;
165 | }
166 |
167 | ErrorNodeImpl.prototype = Object.create(TerminalNodeImpl.prototype);
168 | ErrorNodeImpl.prototype.constructor = ErrorNodeImpl;
169 |
170 | ErrorNodeImpl.prototype.isErrorNode = function() {
171 | return true;
172 | };
173 |
174 | ErrorNodeImpl.prototype.accept = function(visitor) {
175 | return visitor.visitErrorNode(this);
176 | };
177 |
178 | function ParseTreeWalker() {
179 | return this;
180 | }
181 |
182 | ParseTreeWalker.prototype.walk = function(listener, t) {
183 | var errorNode = t instanceof ErrorNode ||
184 | (t.isErrorNode !== undefined && t.isErrorNode());
185 | if (errorNode) {
186 | listener.visitErrorNode(t);
187 | } else if (t instanceof TerminalNode) {
188 | listener.visitTerminal(t);
189 | } else {
190 | this.enterRule(listener, t);
191 | for (var i = 0; i < t.getChildCount(); i++) {
192 | var child = t.getChild(i);
193 | this.walk(listener, child);
194 | }
195 | this.exitRule(listener, t);
196 | }
197 | };
198 | //
199 | // The discovery of a rule node, involves sending two events: the generic
200 | // {@link ParseTreeListener//enterEveryRule} and a
201 | // {@link RuleContext}-specific event. First we trigger the generic and then
202 | // the rule specific. We to them in reverse order upon finishing the node.
203 | //
204 | ParseTreeWalker.prototype.enterRule = function(listener, r) {
205 | var ctx = r.getRuleContext();
206 | listener.enterEveryRule(ctx);
207 | ctx.enterRule(listener);
208 | };
209 |
210 | ParseTreeWalker.prototype.exitRule = function(listener, r) {
211 | var ctx = r.getRuleContext();
212 | ctx.exitRule(listener);
213 | listener.exitEveryRule(ctx);
214 | };
215 |
216 | ParseTreeWalker.DEFAULT = new ParseTreeWalker();
217 |
218 | exports.RuleNode = RuleNode;
219 | exports.ErrorNode = ErrorNode;
220 | exports.TerminalNode = TerminalNode;
221 | exports.ErrorNodeImpl = ErrorNodeImpl;
222 | exports.TerminalNodeImpl = TerminalNodeImpl;
223 | exports.ParseTreeListener = ParseTreeListener;
224 | exports.ParseTreeVisitor = ParseTreeVisitor;
225 | exports.ParseTreeWalker = ParseTreeWalker;
226 | exports.INVALID_INTERVAL = INVALID_INTERVAL;
227 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/antlr4/tree/Trees.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 |
6 | var Utils = require('./../Utils');
7 | var Token = require('./../Token').Token;
8 | var RuleNode = require('./Tree').RuleNode;
9 | var ErrorNode = require('./Tree').ErrorNode;
10 | var TerminalNode = require('./Tree').TerminalNode;
11 | var ParserRuleContext = require('./../ParserRuleContext').ParserRuleContext;
12 | var RuleContext = require('./../RuleContext').RuleContext;
13 | var INVALID_ALT_NUMBER = require('./../atn/ATN').INVALID_ALT_NUMBER;
14 |
15 |
16 | /** A set of utility routines useful for all kinds of ANTLR trees. */
17 | function Trees() {
18 | }
19 |
20 | // Print out a whole tree in LISP form. {@link //getNodeText} is used on the
21 | // node payloads to get the text for the nodes. Detect
22 | // parse trees and extract data appropriately.
23 | Trees.toStringTree = function(tree, ruleNames, recog) {
24 | ruleNames = ruleNames || null;
25 | recog = recog || null;
26 | if(recog!==null) {
27 | ruleNames = recog.ruleNames;
28 | }
29 | var s = Trees.getNodeText(tree, ruleNames);
30 | s = Utils.escapeWhitespace(s, false);
31 | var c = tree.getChildCount();
32 | if(c===0) {
33 | return s;
34 | }
35 | var res = "(" + s + ' ';
36 | if(c>0) {
37 | s = Trees.toStringTree(tree.getChild(0), ruleNames);
38 | res = res.concat(s);
39 | }
40 | for(var i=1;i visit(child, visitor))
86 | }
87 |
88 | if (!_isASTNode(node)) return
89 |
90 | let cont = true
91 |
92 | if (visitor[node.type]) {
93 | cont = visitor[node.type](node)
94 | }
95 |
96 | if (cont === false) return
97 |
98 | for (const prop in node) {
99 | if (node.hasOwnProperty(prop)) {
100 | visit(node[prop], visitor)
101 | }
102 | }
103 |
104 | const selector = node.type + ':exit'
105 | if (visitor[selector]) {
106 | visitor[selector](node)
107 | }
108 | }
109 |
110 | exports.tokenize = tokenize
111 | exports.parse = parse
112 | exports.visit = visit
113 | exports.ParserError = ParserError
114 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/lib/Solidity.tokens:
--------------------------------------------------------------------------------
1 | T__0=1
2 | T__1=2
3 | T__2=3
4 | T__3=4
5 | T__4=5
6 | T__5=6
7 | T__6=7
8 | T__7=8
9 | T__8=9
10 | T__9=10
11 | T__10=11
12 | T__11=12
13 | T__12=13
14 | T__13=14
15 | T__14=15
16 | T__15=16
17 | T__16=17
18 | T__17=18
19 | T__18=19
20 | T__19=20
21 | T__20=21
22 | T__21=22
23 | T__22=23
24 | T__23=24
25 | T__24=25
26 | T__25=26
27 | T__26=27
28 | T__27=28
29 | T__28=29
30 | T__29=30
31 | T__30=31
32 | T__31=32
33 | T__32=33
34 | T__33=34
35 | T__34=35
36 | T__35=36
37 | T__36=37
38 | T__37=38
39 | T__38=39
40 | T__39=40
41 | T__40=41
42 | T__41=42
43 | T__42=43
44 | T__43=44
45 | T__44=45
46 | T__45=46
47 | T__46=47
48 | T__47=48
49 | T__48=49
50 | T__49=50
51 | T__50=51
52 | T__51=52
53 | T__52=53
54 | T__53=54
55 | T__54=55
56 | T__55=56
57 | T__56=57
58 | T__57=58
59 | T__58=59
60 | T__59=60
61 | T__60=61
62 | T__61=62
63 | T__62=63
64 | T__63=64
65 | T__64=65
66 | T__65=66
67 | T__66=67
68 | T__67=68
69 | T__68=69
70 | T__69=70
71 | T__70=71
72 | T__71=72
73 | T__72=73
74 | T__73=74
75 | T__74=75
76 | T__75=76
77 | T__76=77
78 | T__77=78
79 | T__78=79
80 | T__79=80
81 | T__80=81
82 | T__81=82
83 | T__82=83
84 | T__83=84
85 | T__84=85
86 | T__85=86
87 | T__86=87
88 | T__87=88
89 | T__88=89
90 | T__89=90
91 | Int=91
92 | Uint=92
93 | Byte=93
94 | Fixed=94
95 | Ufixed=95
96 | VersionLiteral=96
97 | BooleanLiteral=97
98 | DecimalNumber=98
99 | HexNumber=99
100 | NumberUnit=100
101 | HexLiteral=101
102 | ReservedKeyword=102
103 | AnonymousKeyword=103
104 | BreakKeyword=104
105 | ConstantKeyword=105
106 | ContinueKeyword=106
107 | ExternalKeyword=107
108 | IndexedKeyword=108
109 | InternalKeyword=109
110 | PayableKeyword=110
111 | PrivateKeyword=111
112 | PublicKeyword=112
113 | PureKeyword=113
114 | ViewKeyword=114
115 | Identifier=115
116 | StringLiteral=116
117 | WS=117
118 | COMMENT=118
119 | LINE_COMMENT=119
120 | 'pragma'=1
121 | ';'=2
122 | '^'=3
123 | '~'=4
124 | '>='=5
125 | '>'=6
126 | '<'=7
127 | '<='=8
128 | '='=9
129 | 'as'=10
130 | 'import'=11
131 | '*'=12
132 | 'from'=13
133 | '{'=14
134 | ','=15
135 | '}'=16
136 | 'contract'=17
137 | 'interface'=18
138 | 'library'=19
139 | 'is'=20
140 | '('=21
141 | ')'=22
142 | 'using'=23
143 | 'for'=24
144 | 'struct'=25
145 | 'constructor'=26
146 | 'modifier'=27
147 | 'function'=28
148 | 'returns'=29
149 | 'event'=30
150 | 'enum'=31
151 | '['=32
152 | ']'=33
153 | '.'=34
154 | 'mapping'=35
155 | '=>'=36
156 | 'memory'=37
157 | 'storage'=38
158 | 'calldata'=39
159 | 'if'=40
160 | 'else'=41
161 | 'while'=42
162 | 'assembly'=43
163 | 'do'=44
164 | 'return'=45
165 | 'throw'=46
166 | 'emit'=47
167 | 'var'=48
168 | 'address'=49
169 | 'bool'=50
170 | 'string'=51
171 | 'byte'=52
172 | '++'=53
173 | '--'=54
174 | 'new'=55
175 | '+'=56
176 | '-'=57
177 | 'after'=58
178 | 'delete'=59
179 | '!'=60
180 | '**'=61
181 | '/'=62
182 | '%'=63
183 | '<<'=64
184 | '>>'=65
185 | '&'=66
186 | '|'=67
187 | '=='=68
188 | '!='=69
189 | '&&'=70
190 | '||'=71
191 | '?'=72
192 | ':'=73
193 | '|='=74
194 | '^='=75
195 | '&='=76
196 | '<<='=77
197 | '>>='=78
198 | '+='=79
199 | '-='=80
200 | '*='=81
201 | '/='=82
202 | '%='=83
203 | 'let'=84
204 | ':='=85
205 | '=:'=86
206 | 'switch'=87
207 | 'case'=88
208 | 'default'=89
209 | '->'=90
210 | 'anonymous'=103
211 | 'break'=104
212 | 'constant'=105
213 | 'continue'=106
214 | 'external'=107
215 | 'indexed'=108
216 | 'internal'=109
217 | 'payable'=110
218 | 'private'=111
219 | 'public'=112
220 | 'pure'=113
221 | 'view'=114
222 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/lib/SolidityLexer.tokens:
--------------------------------------------------------------------------------
1 | T__0=1
2 | T__1=2
3 | T__2=3
4 | T__3=4
5 | T__4=5
6 | T__5=6
7 | T__6=7
8 | T__7=8
9 | T__8=9
10 | T__9=10
11 | T__10=11
12 | T__11=12
13 | T__12=13
14 | T__13=14
15 | T__14=15
16 | T__15=16
17 | T__16=17
18 | T__17=18
19 | T__18=19
20 | T__19=20
21 | T__20=21
22 | T__21=22
23 | T__22=23
24 | T__23=24
25 | T__24=25
26 | T__25=26
27 | T__26=27
28 | T__27=28
29 | T__28=29
30 | T__29=30
31 | T__30=31
32 | T__31=32
33 | T__32=33
34 | T__33=34
35 | T__34=35
36 | T__35=36
37 | T__36=37
38 | T__37=38
39 | T__38=39
40 | T__39=40
41 | T__40=41
42 | T__41=42
43 | T__42=43
44 | T__43=44
45 | T__44=45
46 | T__45=46
47 | T__46=47
48 | T__47=48
49 | T__48=49
50 | T__49=50
51 | T__50=51
52 | T__51=52
53 | T__52=53
54 | T__53=54
55 | T__54=55
56 | T__55=56
57 | T__56=57
58 | T__57=58
59 | T__58=59
60 | T__59=60
61 | T__60=61
62 | T__61=62
63 | T__62=63
64 | T__63=64
65 | T__64=65
66 | T__65=66
67 | T__66=67
68 | T__67=68
69 | T__68=69
70 | T__69=70
71 | T__70=71
72 | T__71=72
73 | T__72=73
74 | T__73=74
75 | T__74=75
76 | T__75=76
77 | T__76=77
78 | T__77=78
79 | T__78=79
80 | T__79=80
81 | T__80=81
82 | T__81=82
83 | T__82=83
84 | T__83=84
85 | T__84=85
86 | T__85=86
87 | T__86=87
88 | T__87=88
89 | T__88=89
90 | T__89=90
91 | Int=91
92 | Uint=92
93 | Byte=93
94 | Fixed=94
95 | Ufixed=95
96 | VersionLiteral=96
97 | BooleanLiteral=97
98 | DecimalNumber=98
99 | HexNumber=99
100 | NumberUnit=100
101 | HexLiteral=101
102 | ReservedKeyword=102
103 | AnonymousKeyword=103
104 | BreakKeyword=104
105 | ConstantKeyword=105
106 | ContinueKeyword=106
107 | ExternalKeyword=107
108 | IndexedKeyword=108
109 | InternalKeyword=109
110 | PayableKeyword=110
111 | PrivateKeyword=111
112 | PublicKeyword=112
113 | PureKeyword=113
114 | ViewKeyword=114
115 | Identifier=115
116 | StringLiteral=116
117 | WS=117
118 | COMMENT=118
119 | LINE_COMMENT=119
120 | 'pragma'=1
121 | ';'=2
122 | '^'=3
123 | '~'=4
124 | '>='=5
125 | '>'=6
126 | '<'=7
127 | '<='=8
128 | '='=9
129 | 'as'=10
130 | 'import'=11
131 | '*'=12
132 | 'from'=13
133 | '{'=14
134 | ','=15
135 | '}'=16
136 | 'contract'=17
137 | 'interface'=18
138 | 'library'=19
139 | 'is'=20
140 | '('=21
141 | ')'=22
142 | 'using'=23
143 | 'for'=24
144 | 'struct'=25
145 | 'constructor'=26
146 | 'modifier'=27
147 | 'function'=28
148 | 'returns'=29
149 | 'event'=30
150 | 'enum'=31
151 | '['=32
152 | ']'=33
153 | '.'=34
154 | 'mapping'=35
155 | '=>'=36
156 | 'memory'=37
157 | 'storage'=38
158 | 'calldata'=39
159 | 'if'=40
160 | 'else'=41
161 | 'while'=42
162 | 'assembly'=43
163 | 'do'=44
164 | 'return'=45
165 | 'throw'=46
166 | 'emit'=47
167 | 'var'=48
168 | 'address'=49
169 | 'bool'=50
170 | 'string'=51
171 | 'byte'=52
172 | '++'=53
173 | '--'=54
174 | 'new'=55
175 | '+'=56
176 | '-'=57
177 | 'after'=58
178 | 'delete'=59
179 | '!'=60
180 | '**'=61
181 | '/'=62
182 | '%'=63
183 | '<<'=64
184 | '>>'=65
185 | '&'=66
186 | '|'=67
187 | '=='=68
188 | '!='=69
189 | '&&'=70
190 | '||'=71
191 | '?'=72
192 | ':'=73
193 | '|='=74
194 | '^='=75
195 | '&='=76
196 | '<<='=77
197 | '>>='=78
198 | '+='=79
199 | '-='=80
200 | '*='=81
201 | '/='=82
202 | '%='=83
203 | 'let'=84
204 | ':='=85
205 | '=:'=86
206 | 'switch'=87
207 | 'case'=88
208 | 'default'=89
209 | '->'=90
210 | 'anonymous'=103
211 | 'break'=104
212 | 'constant'=105
213 | 'continue'=106
214 | 'external'=107
215 | 'indexed'=108
216 | 'internal'=109
217 | 'payable'=110
218 | 'private'=111
219 | 'public'=112
220 | 'pure'=113
221 | 'view'=114
222 |
--------------------------------------------------------------------------------
/packages/sooho-parser/src/tokens.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | const TYPE_TOKENS = [
5 | 'var',
6 | 'bool',
7 | 'address',
8 | 'string',
9 | 'Int',
10 | 'Uint',
11 | 'Byte',
12 | 'Fixed',
13 | 'UFixed'
14 | ]
15 |
16 | function rsplit(str, value) {
17 | const index = str.lastIndexOf(value)
18 | return [str.substring(0, index), str.substring(index + 1, str.length)]
19 | }
20 |
21 | function normalizeTokenType(value) {
22 | if (value.endsWith("'")) {
23 | value = value.substring(0, value.length - 1)
24 | }
25 | if (value.startsWith("'")) {
26 | value = value.substring(1, value.length)
27 | }
28 | return value
29 | }
30 |
31 | function getTokenType(value) {
32 | if (value === 'Identifier' || value === 'from') {
33 | return 'Identifier'
34 | } else if (value === 'TrueLiteral' || value === 'FalseLiteral') {
35 | return 'Boolean'
36 | } else if (value === 'VersionLiteral') {
37 | return 'Version'
38 | } else if (value === 'StringLiteral') {
39 | return 'String'
40 | } else if (TYPE_TOKENS.includes(value)) {
41 | return 'Type'
42 | } else if (value === 'NumberUnit') {
43 | return 'Subdenomination'
44 | } else if (value === 'DecimalNumber') {
45 | return 'Numeric'
46 | } else if (value === 'HexLiteral') {
47 | return 'Hex'
48 | } else if (value === 'ReservedKeyword') {
49 | return 'Reserved'
50 | } else if (/^\W+$/.test(value)) {
51 | return 'Punctuator'
52 | } else {
53 | return 'Keyword'
54 | }
55 | }
56 |
57 | function getTokenTypeMap() {
58 | const filePath = path.join(__dirname, './lib/Solidity.tokens')
59 |
60 | return fs
61 | .readFileSync(filePath)
62 | .toString('utf-8')
63 | .split('\n')
64 | .map(line => rsplit(line, '='))
65 | .reduce((acum, [value, key]) => {
66 | acum[parseInt(key, 10)] = normalizeTokenType(value)
67 | return acum
68 | }, {})
69 | }
70 |
71 | function buildTokenList(tokens, options) {
72 | const tokenTypes = getTokenTypeMap()
73 |
74 | return tokens.map(token => {
75 | const type = getTokenType(tokenTypes[token.type])
76 | const node = { type, value: token.text }
77 | if (options.range) {
78 | node.range = [token.start, token.stop + 1]
79 | }
80 | if (options.loc) {
81 | node.loc = {
82 | start: { line: token.line, column: token.column },
83 | end: { line: token.line, column: token.column + token.text.length }
84 | }
85 | }
86 | return node
87 | })
88 | }
89 |
90 | exports.buildTokenList = buildTokenList
91 |
--------------------------------------------------------------------------------
/packages/sooho-parser/test/index.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs")
2 | var { assert } = require('chai')
3 | var parser = require("../src/index")
4 | var { parseNode, parseStatement } = require('./utils')
5 |
6 | describe("#parse", () => {
7 |
8 | it("parses test file correctly", () => {
9 | var content = fs.readFileSync(__dirname + "/test.sol")
10 | parser.parse(content.toString())
11 | })
12 |
13 | it("throws ParserError on syntax error", () => {
14 | var source = "not good"
15 | assert.throws(() => {
16 | parser.parse(source)
17 | }, parser.ParseError)
18 | })
19 |
20 | it("supports tolerant mode", () => {
21 | var source = "not good"
22 | var root = parser.parse(source, { tolerant: true })
23 | assert.equal(root.errors.length, 1)
24 | })
25 |
26 | it("supports loc", () => {
27 | var source = "contract test { uint a; }"
28 | var root = parser.parse(source, { loc: true })
29 | assert.isOk(root.hasOwnProperty('loc'))
30 | })
31 |
32 | it("supports range", () => {
33 | var source = "contract test { uint a; }"
34 | var root = parser.parse(source, { range: true })
35 | assert.isOk(root.hasOwnProperty('range'))
36 | })
37 |
38 | it('can build ast with tolerant mode errors', () => {
39 | // TODO: just a few examples here, more should be added
40 | var cases = [
41 | 'contract { function a() return bool {} }',
42 | 'contract test { function () { 2 + + 2; } }',
43 | 'contract test { uint ; }',
44 | 'contract test { modifier { } }'
45 | ]
46 |
47 | for (var c of cases) {
48 | parser.parse(c, { tolerant: true })
49 | }
50 | })
51 |
52 |
53 | describe("node meta", () => {
54 |
55 | it("adds meta to VariableDeclaration inside StateVariableDeclaration", () => {
56 | var ast = parseNode("uint public a;", { loc: true })
57 | assert.isOk(ast.variables[0].loc)
58 | })
59 |
60 | it("adds meta to VariableDeclaration inside VariableDeclarationStatement", () => {
61 | var ast = parseStatement("uint a;", { loc: true })
62 | assert.isOk(ast.variables[0].loc)
63 | })
64 |
65 | it("adds meta to VariableDeclaration inside EventDefinition", () => {
66 | var ast = parseNode("event Foo(address bar);", { loc: true })
67 | assert.isOk(ast.parameters.parameters[0].loc)
68 | })
69 |
70 | })
71 | })
72 |
73 | describe("#visit", () => {
74 |
75 | it("walks visitor through AST", () => {
76 | var source = "contract test { uint a; }"
77 | var ast = parser.parse(source)
78 | parser.visit(ast, {
79 | ContractDefinition: (node) => {
80 | assert.equal(node.type, 'ContractDefinition')
81 | },
82 |
83 | 'ContractDefinition:exit': (node) => {
84 | assert.equal(node.type, 'ContractDefinition')
85 | }
86 | })
87 | })
88 |
89 | it("can stop visiting inner nodes by returning false", () => {
90 | var source = "contract test { uint a; }"
91 | var ast = parser.parse(source)
92 | parser.visit(ast, {
93 | ContractDefinition: (node) => {
94 | return false
95 | },
96 |
97 | 'ContractDefinition:exit': (node) => {
98 | assert.fail('should not reach here')
99 | }
100 | })
101 | })
102 |
103 | it("shouldn't print anything if the lexer fails", () => {
104 | const originalConsoleError = console.error
105 | let called = false
106 | console.error = () => called = true
107 |
108 | var ast = parser.parse('"', {tolerant: true})
109 |
110 | console.error = originalConsoleError
111 |
112 | assert.isFalse(called, "Should not call console.error on lexer errors")
113 | });
114 |
115 | })
116 |
--------------------------------------------------------------------------------
/packages/sooho-parser/test/utils.js:
--------------------------------------------------------------------------------
1 | const { assert } = require('chai')
2 | const parser = require('../src/index')
3 |
4 | function print(obj) {
5 | console.log(JSON.stringify(obj, null, 2))
6 | }
7 |
8 | function parseContract(source, options = {}) {
9 | var ast = parser.parse(source, options)
10 | assert.isOk(ast.children[0])
11 | return ast.children[0]
12 | }
13 |
14 | function parseNode(source, options = {}) {
15 | var contract = parseContract("contract test { " + source + " }", options)
16 | assert.isOk(contract.subNodes[0])
17 | return contract.subNodes[0]
18 | }
19 |
20 | function parseStatement(source, options = {}) {
21 | var ast = parseNode("function () { " + source + " }", options)
22 | assert.isOk(ast.body.statements[0])
23 | return ast.body.statements[0]
24 | }
25 |
26 | function parseExpression(source, options = {}) {
27 | var ast = parseNode("function () { " + source + "; }", options)
28 | assert.isOk(ast.body.statements[0].expression)
29 | return ast.body.statements[0].expression
30 | }
31 |
32 | function parseAssembly(source, options = {}) {
33 | var ast = parseNode("function () { assembly { " + source + " } }", options)
34 | assert.isOk(ast.body.statements[0].body.operations[0])
35 | return ast.body.statements[0].body.operations[0]
36 | }
37 |
38 | module.exports = {
39 | parseAssembly,
40 | parseContract,
41 | parseExpression,
42 | parseNode,
43 | parseStatement,
44 | print
45 | }
46 |
--------------------------------------------------------------------------------