Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
0a2a6c4db6 | |||
6e143cd4d0 | |||
f094584dee | |||
c01c04699a | |||
e6fea932d8 | |||
e90524e367 | |||
c117337883 | |||
da08fb3979 | |||
a15429d964 | |||
36ed3328d1 | |||
f8083b26d2 | |||
beff450c58 | |||
bf8d0f99d2 | |||
518e8ecbed | |||
61d30947ce | |||
bef076239e | |||
d7d48785aa | |||
ed83e649fb | |||
19a479562c | |||
bfd36c5344 |
@@ -2,4 +2,8 @@ node_modules/**
|
||||
client/node_modules/**
|
||||
client/out/**
|
||||
server/node_modules/**
|
||||
server/out/**
|
||||
server/out/**
|
||||
|
||||
server/dist/**
|
||||
client/dist/**
|
||||
client/src/generated/**
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
test.bf
|
||||
out
|
||||
dist
|
||||
node_modules
|
||||
client/server
|
||||
.vscode-test
|
||||
|
@@ -1,14 +1,23 @@
|
||||
**/out
|
||||
*.bf
|
||||
client/**
|
||||
server/**
|
||||
|
||||
node_modules
|
||||
!client/dist
|
||||
!server/dist
|
||||
|
||||
**/*.md
|
||||
!README.md
|
||||
*.vsix
|
||||
.vscode/**
|
||||
**/*.ts
|
||||
**/*.map
|
||||
.gitignore
|
||||
**/.gitignore
|
||||
**/.eslintrc.json
|
||||
**/.eslintignore
|
||||
**/tsconfig.json
|
||||
**/tsconfig.base.json
|
||||
contributing.md
|
||||
# contributing.md
|
||||
.travis.yml
|
||||
client/node_modules/**
|
||||
!client/node_modules/vscode-jsonrpc/**
|
||||
!client/node_modules/vscode-languageclient/**
|
||||
!client/node_modules/vscode-languageserver-protocol/**
|
||||
!client/node_modules/vscode-languageserver-types/**
|
||||
!client/node_modules/semver/**
|
||||
# client/node_modules/**
|
||||
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Atreya Bain
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
58
README.md
58
README.md
@@ -1,37 +1,39 @@
|
||||
# BF extension
|
||||
|
||||
A simple language server for the ~~Brainfuck~~ ~~Branflakes~~ BF language.
|
||||
A simple language server based VSCode Extension for the (Branflakes?) (BrainFuck?) BF language. You can also execute your code and see its output.
|
||||
|
||||

|
||||
|
||||

|
||||
## Functionality
|
||||
|
||||
- [X] Syntax
|
||||
- [X] Bracket matching
|
||||
- [X] Autocomplete suggestions
|
||||
- [ ] Extension icon
|
||||
- Syntax Highlighting
|
||||
- Execution
|
||||
- Autocomplete suggestions
|
||||
|
||||
<!--
|
||||
## Structure
|
||||
|
||||
```
|
||||
.
|
||||
├── client // Language Client
|
||||
│ ├── src
|
||||
│ │ ├── test // End to End tests for Language Client / Server
|
||||
│ │ └── extension.ts // Language Client entry point
|
||||
├── package.json // The extension manifest.
|
||||
└── server // Language Server
|
||||
└── src
|
||||
└── server.ts // Language Server entry point
|
||||
```
|
||||
### Execution
|
||||
|
||||
## Running the Sample
|
||||
Use the command to execute the code.
|
||||
Issue is, because BF is a **turing complete** language, there is no way to know if the program will terminate or not. Hence for now, the command may lead to infinite execution.
|
||||
If the program requires input, it will be requested as a prompt.
|
||||
|
||||
- Run `npm install` in this folder. This installs all necessary npm modules in both the client and server folder
|
||||
- Open VS Code on this folder.
|
||||
- Press Ctrl+Shift+B to compile the client and server.
|
||||
- Switch to the Debug viewlet.
|
||||
- Select `Launch Client` from the drop down.
|
||||
- Run the launch config.
|
||||
- If you want to debug the server as well use the launch configuration `Attach to Server`
|
||||
-->
|
||||
TODO: Implement a timeout.
|
||||
|
||||
### Changelog
|
||||
|
||||
#### 0.2.0
|
||||
|
||||
- Cycle input pointer on overflow/underflow
|
||||
- Refactoring code
|
||||
|
||||
#### 0.1.0
|
||||
|
||||
- Request input as required during execution
|
||||
- Using array-based indexing. This implies that only positive indices upto 30k are supported.
|
||||
|
||||
|
||||
### Building it
|
||||
|
||||
1. `npm i` - Install all dependencies
|
||||
2. `npm i -g @vscode/vsce` - Install VSCode Command line CLI
|
||||
3. `vsce package` - Package to VSIX
|
BIN
assets/128.png
Normal file
BIN
assets/128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
assets/screenshot.png
Normal file
BIN
assets/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
49
client/bf.g4
Normal file
49
client/bf.g4
Normal file
@@ -0,0 +1,49 @@
|
||||
grammar bf;
|
||||
|
||||
program
|
||||
: statements EOF;
|
||||
|
||||
statements
|
||||
: eligibleStmt*;
|
||||
|
||||
eligibleStmt
|
||||
: stmt
|
||||
| numberedStmt
|
||||
;
|
||||
|
||||
numberedStmt
|
||||
: stmt NUMBER
|
||||
;
|
||||
|
||||
stmt
|
||||
: basicStmt
|
||||
| loopStmt
|
||||
;
|
||||
|
||||
|
||||
loopStmt
|
||||
: LOOPSTART statements LOOPEND
|
||||
;
|
||||
|
||||
basicStmt
|
||||
: INC # ptrIncr
|
||||
| DEC # ptrDecr
|
||||
| LEFT # ptrLeft
|
||||
| RIGHT # ptrRight
|
||||
| INPUT # inputStmt
|
||||
| OUTPUT # outputStmt
|
||||
;
|
||||
|
||||
|
||||
LOOPSTART: '[';
|
||||
LOOPEND:']';
|
||||
NUMBER: [0-9]+;
|
||||
INPUT: ',';
|
||||
OUTPUT: '.';
|
||||
DEC: '-';
|
||||
INC: '+';
|
||||
LEFT: '<';
|
||||
RIGHT: '>';
|
||||
EVERYTHING_ELSE: . ->channel(HIDDEN);
|
||||
WS: [ \r\n] -> skip;
|
||||
|
2359
client/package-lock.json
generated
2359
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,19 @@
|
||||
"vscode": "^1.43.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"antlr4ts": "^0.5.0-alpha.4",
|
||||
"vscode-languageclient": "^6.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "1.43.0",
|
||||
"vscode-test": "^1.3.0"
|
||||
"vscode-test": "^1.3.0",
|
||||
"webpack": "^5.33.2",
|
||||
"webpack-cli": "^4.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"regen": "antlr4ts bf.g4 -no-listener -visitor -o src/generated/",
|
||||
"webpack": "webpack --mode development",
|
||||
"webpack-prod":"webpack --mode production",
|
||||
"webpack-dev": "webpack --mode development --watch"
|
||||
}
|
||||
}
|
||||
|
140
client/src/BranFlakesExecutorVisitor.ts
Normal file
140
client/src/BranFlakesExecutorVisitor.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor';
|
||||
import { LoopStmtContext } from './generated/bfParser';
|
||||
import { bfVisitor } from './generated/bfVisitor';
|
||||
import { DiagnosticSeverity } from 'vscode-languageclient';
|
||||
import { getTree } from './BranFlakesParseRunner';
|
||||
import { RuleNode } from 'antlr4ts/tree/RuleNode';
|
||||
import InputStrategy from './input/InputStrategy';
|
||||
|
||||
export default class BranFlakesExecutorVisitor
|
||||
extends AbstractParseTreeVisitor<Promise<void>>
|
||||
implements bfVisitor<Promise<void>>
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param input Input string
|
||||
* @param inputPtr Input pointer to start from
|
||||
*/
|
||||
constructor(
|
||||
private inputStrategy: InputStrategy,
|
||||
private logger: (val: string) => Thenable<string>,
|
||||
private inputPtr: number = 0
|
||||
) {
|
||||
super();
|
||||
}
|
||||
// /**
|
||||
// * The memory cells (Can work with negative cells this way)
|
||||
// */
|
||||
// private cells: Map<number, number> = new Map();
|
||||
|
||||
private byteArraySize: number = 30000;
|
||||
private byteArray: Int8Array = new Int8Array(this.byteArraySize);
|
||||
/**
|
||||
* Pointer
|
||||
*/
|
||||
private ptr: number = 0;
|
||||
/** Output string */
|
||||
private outputStr: string = '';
|
||||
|
||||
|
||||
|
||||
defaultResult() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
/**
|
||||
* Run a file
|
||||
* @param text
|
||||
* @param fn
|
||||
* @param inputStrategy
|
||||
* @returns
|
||||
*/
|
||||
static async run(
|
||||
text: string,
|
||||
fn: string,
|
||||
inputStrategy: InputStrategy,
|
||||
logger: (str: string) => Thenable<string>
|
||||
) {
|
||||
//get tree and issues
|
||||
const { tree, issues } = getTree(text, fn);
|
||||
|
||||
//get only errors
|
||||
const x = issues.filter(e => e.type === DiagnosticSeverity.Error);
|
||||
//if any error, drop
|
||||
if (x.length > 0) {
|
||||
throw Error('Errors exist');
|
||||
}
|
||||
// make visitor
|
||||
const vis = new BranFlakesExecutorVisitor(inputStrategy, logger);
|
||||
//visit the tree
|
||||
await vis.visit(tree);
|
||||
|
||||
//get output
|
||||
return vis.outputStr;
|
||||
}
|
||||
|
||||
getCell(pointerIndex: number) {
|
||||
return this.byteArray[pointerIndex];
|
||||
}
|
||||
setCell(pointerIndex: number, value: number): void {
|
||||
this.byteArray[pointerIndex] = value;
|
||||
}
|
||||
|
||||
async visitLoopStmt(ctx: LoopStmtContext) {
|
||||
while ((this.getCell(this.ptr) ?? 0) !== 0) {
|
||||
await this.visitChildren(ctx);
|
||||
}
|
||||
}
|
||||
async visitPtrLeft() {
|
||||
this.ptr = (this.ptr + this.byteArraySize - 1) % this.byteArraySize;
|
||||
}
|
||||
async visitPtrRight() {
|
||||
this.ptr = (this.ptr + this.byteArraySize + 1) % this.byteArraySize;
|
||||
}
|
||||
async visitPtrIncr() {
|
||||
const val = this.getCell(this.ptr);
|
||||
this.setCell(this.ptr, (val + 1) % 256);
|
||||
}
|
||||
async visitPtrDecr() {
|
||||
const val = this.getCell(this.ptr);
|
||||
this.setCell(this.ptr, (val + 255) % 256);
|
||||
}
|
||||
async visitOutputStmt() {
|
||||
const val = this.getCell(this.ptr) ?? 0;
|
||||
const str = String.fromCharCode(val);
|
||||
|
||||
this.outputStr += str;
|
||||
}
|
||||
|
||||
async visitInputStmt() {
|
||||
//get char
|
||||
const char = (await this.inputStrategy.getInput()) ?? 0;
|
||||
//increment the input pointer after this
|
||||
this.inputPtr++;
|
||||
this.setCell(this.ptr, char);
|
||||
}
|
||||
|
||||
// override for maintaining async
|
||||
async visitChildren(node: RuleNode): Promise<void> {
|
||||
let result = this.defaultResult();
|
||||
await result;
|
||||
let n = node.childCount;
|
||||
for (let i = 0; i < n; i++) {
|
||||
if (!this.shouldVisitNextChild(node, result)) {
|
||||
break;
|
||||
}
|
||||
let c = node.getChild(i);
|
||||
let childResult = c.accept(this);
|
||||
result = this.aggregateResult(result, childResult);
|
||||
await result;
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
// override for maintaining async
|
||||
protected async aggregateResult(
|
||||
aggregate: Promise<void>,
|
||||
nextResult: Promise<void>
|
||||
): Promise<void> {
|
||||
await aggregate;
|
||||
return nextResult;
|
||||
}
|
||||
}
|
56
client/src/BranFlakesParseRunner.ts
Normal file
56
client/src/BranFlakesParseRunner.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { CharStreams, CommonTokenStream, RecognitionException } from 'antlr4ts';
|
||||
import { DiagnosticSeverity } from 'vscode-languageserver-types';
|
||||
import { bfLexer } from './generated/bfLexer';
|
||||
import { bfParser } from './generated/bfParser';
|
||||
|
||||
|
||||
export interface TranslationError {
|
||||
line: number;
|
||||
charPositionInLine: number;
|
||||
msg: string;
|
||||
source?: any;
|
||||
type: DiagnosticSeverity;
|
||||
error?: RecognitionException;
|
||||
}
|
||||
|
||||
export function getTree(str: string, fn: string) {
|
||||
const charStreams = CharStreams.fromString(str, fn);
|
||||
const lexer = new bfLexer(charStreams);
|
||||
const issues: TranslationError[] = [];
|
||||
// remove the error listener. We want to put our own
|
||||
|
||||
lexer.removeErrorListeners();
|
||||
lexer.addErrorListener({
|
||||
syntaxError(source, o, line, charPositionInLine, msg, error) {
|
||||
issues.push({
|
||||
line,
|
||||
charPositionInLine,
|
||||
msg,
|
||||
type: DiagnosticSeverity.Error,
|
||||
source,
|
||||
error,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const tokenStreams = new CommonTokenStream(lexer);
|
||||
const parser = new bfParser(tokenStreams);
|
||||
|
||||
// remove the error listener. We want to put our own
|
||||
parser.removeErrorListeners();
|
||||
parser.addErrorListener({
|
||||
syntaxError(source, o, line, charPositionInLine, msg, error) {
|
||||
issues.push({
|
||||
line,
|
||||
charPositionInLine,
|
||||
msg,
|
||||
type: DiagnosticSeverity.Error,
|
||||
source,
|
||||
error,
|
||||
});
|
||||
},
|
||||
});
|
||||
const tree = parser.program();
|
||||
|
||||
return { tree, issues, tokenStreams, charStreams };
|
||||
}
|
5
client/src/command/Command.ts
Normal file
5
client/src/command/Command.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
export interface Command{
|
||||
getCommandName():string;
|
||||
getCommandHandler():(...args:any)=>Promise<any>;
|
||||
}
|
26
client/src/command/CompileCommand.ts
Normal file
26
client/src/command/CompileCommand.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { window } from 'vscode';
|
||||
import { Command as BranFlakesCommand } from './Command';
|
||||
import { VSCodePromptInputStrategy } from '../input/VSCodePromptInputStrategy';
|
||||
import BranFlakesExecutorVisitor from '../BranFlakesExecutorVisitor';
|
||||
|
||||
export class CompileBranFlakesCommand implements BranFlakesCommand {
|
||||
getCommandName() {
|
||||
return 'bf.execute';
|
||||
}
|
||||
getCommandHandler() {
|
||||
return async () => {
|
||||
const text = window.activeTextEditor.document.getText();
|
||||
const fn = window.activeTextEditor.document.fileName;
|
||||
const inputStrategy = new VSCodePromptInputStrategy(
|
||||
window.showInputBox
|
||||
);
|
||||
const output = await BranFlakesExecutorVisitor.run(
|
||||
text,
|
||||
fn,
|
||||
inputStrategy,
|
||||
window.showInformationMessage
|
||||
);
|
||||
await window.showInformationMessage(`Output: ${output}`);
|
||||
};
|
||||
}
|
||||
}
|
@@ -4,60 +4,68 @@
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as path from 'path';
|
||||
import { workspace, ExtensionContext,commands, window } from 'vscode';
|
||||
|
||||
import { ExtensionContext, commands, window } from 'vscode';
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind,
|
||||
} from 'vscode-languageclient';
|
||||
|
||||
import { CompileBranFlakesCommand } from './command/CompileCommand';
|
||||
|
||||
let client: LanguageClient;
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
// The server is implemented in node
|
||||
let serverModule = context.asAbsolutePath(
|
||||
path.join('server', 'out', 'server.js')
|
||||
);
|
||||
// The debug options for the server
|
||||
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
|
||||
let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
|
||||
// The server is implemented in node
|
||||
let serverModule = context.asAbsolutePath(
|
||||
path.join('server', 'dist', 'server.js')
|
||||
);
|
||||
// The debug options for the server
|
||||
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
|
||||
let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
|
||||
|
||||
// If the extension is launched in debug mode then the debug server options are used
|
||||
// Otherwise the run options are used
|
||||
let serverOptions: ServerOptions = {
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
debug: {
|
||||
module: serverModule,
|
||||
transport: TransportKind.ipc,
|
||||
options: debugOptions
|
||||
}
|
||||
};
|
||||
// If the extension is launched in debug mode then the debug server options are used
|
||||
// Otherwise the run options are used
|
||||
let serverOptions: ServerOptions = {
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
debug: {
|
||||
module: serverModule,
|
||||
transport: TransportKind.ipc,
|
||||
options: debugOptions,
|
||||
},
|
||||
};
|
||||
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
// Register the server for plain text documents
|
||||
documentSelector: [{ scheme: 'file', language: 'bf' }]
|
||||
};
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
// Register the server for plain text documents
|
||||
documentSelector: [{ scheme: 'file', language: 'bf' }],
|
||||
};
|
||||
|
||||
const branFlakesCommands = [new CompileBranFlakesCommand()];
|
||||
for (let branFlakesCommand of branFlakesCommands) {
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand(
|
||||
branFlakesCommand.getCommandName(),
|
||||
branFlakesCommand.getCommandHandler()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Create the language client and start the client.
|
||||
client = new LanguageClient(
|
||||
'brainfucklanguageserver',
|
||||
'Brainfuck Language Server',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
// Create the language client and start the client.
|
||||
client = new LanguageClient(
|
||||
'brainfucklanguageserver',
|
||||
'Brainfuck Language Server',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
|
||||
// Start the client. This will also launch the server
|
||||
client.start();
|
||||
// Start the client. This will also launch the server
|
||||
client.start();
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> | undefined {
|
||||
if (!client) {
|
||||
return undefined;
|
||||
}
|
||||
return client.stop();
|
||||
if (!client) {
|
||||
return undefined;
|
||||
}
|
||||
return client.stop();
|
||||
}
|
||||
|
40
client/src/generated/bf.interp
Normal file
40
client/src/generated/bf.interp
Normal file
@@ -0,0 +1,40 @@
|
||||
token literal names:
|
||||
null
|
||||
'['
|
||||
']'
|
||||
null
|
||||
','
|
||||
'.'
|
||||
'-'
|
||||
'+'
|
||||
'<'
|
||||
'>'
|
||||
null
|
||||
null
|
||||
|
||||
token symbolic names:
|
||||
null
|
||||
LOOPSTART
|
||||
LOOPEND
|
||||
NUMBER
|
||||
INPUT
|
||||
OUTPUT
|
||||
DEC
|
||||
INC
|
||||
LEFT
|
||||
RIGHT
|
||||
EVERYTHING_ELSE
|
||||
WS
|
||||
|
||||
rule names:
|
||||
program
|
||||
statements
|
||||
eligibleStmt
|
||||
numberedStmt
|
||||
stmt
|
||||
loopStmt
|
||||
basicStmt
|
||||
|
||||
|
||||
atn:
|
||||
[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 3, 13, 49, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 3, 2, 3, 2, 3, 2, 3, 3, 7, 3, 21, 10, 3, 12, 3, 14, 3, 24, 11, 3, 3, 4, 3, 4, 5, 4, 28, 10, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 5, 6, 35, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 5, 8, 47, 10, 8, 3, 8, 2, 2, 2, 9, 2, 2, 4, 2, 6, 2, 8, 2, 10, 2, 12, 2, 14, 2, 2, 2, 2, 49, 2, 16, 3, 2, 2, 2, 4, 22, 3, 2, 2, 2, 6, 27, 3, 2, 2, 2, 8, 29, 3, 2, 2, 2, 10, 34, 3, 2, 2, 2, 12, 36, 3, 2, 2, 2, 14, 46, 3, 2, 2, 2, 16, 17, 5, 4, 3, 2, 17, 18, 7, 2, 2, 3, 18, 3, 3, 2, 2, 2, 19, 21, 5, 6, 4, 2, 20, 19, 3, 2, 2, 2, 21, 24, 3, 2, 2, 2, 22, 20, 3, 2, 2, 2, 22, 23, 3, 2, 2, 2, 23, 5, 3, 2, 2, 2, 24, 22, 3, 2, 2, 2, 25, 28, 5, 10, 6, 2, 26, 28, 5, 8, 5, 2, 27, 25, 3, 2, 2, 2, 27, 26, 3, 2, 2, 2, 28, 7, 3, 2, 2, 2, 29, 30, 5, 10, 6, 2, 30, 31, 7, 5, 2, 2, 31, 9, 3, 2, 2, 2, 32, 35, 5, 14, 8, 2, 33, 35, 5, 12, 7, 2, 34, 32, 3, 2, 2, 2, 34, 33, 3, 2, 2, 2, 35, 11, 3, 2, 2, 2, 36, 37, 7, 3, 2, 2, 37, 38, 5, 4, 3, 2, 38, 39, 7, 4, 2, 2, 39, 13, 3, 2, 2, 2, 40, 47, 7, 9, 2, 2, 41, 47, 7, 8, 2, 2, 42, 47, 7, 10, 2, 2, 43, 47, 7, 11, 2, 2, 44, 47, 7, 6, 2, 2, 45, 47, 7, 7, 2, 2, 46, 40, 3, 2, 2, 2, 46, 41, 3, 2, 2, 2, 46, 42, 3, 2, 2, 2, 46, 43, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 45, 3, 2, 2, 2, 47, 15, 3, 2, 2, 2, 6, 22, 27, 34, 46]
|
19
client/src/generated/bf.tokens
Normal file
19
client/src/generated/bf.tokens
Normal file
@@ -0,0 +1,19 @@
|
||||
LOOPSTART=1
|
||||
LOOPEND=2
|
||||
NUMBER=3
|
||||
INPUT=4
|
||||
OUTPUT=5
|
||||
DEC=6
|
||||
INC=7
|
||||
LEFT=8
|
||||
RIGHT=9
|
||||
EVERYTHING_ELSE=10
|
||||
WS=11
|
||||
'['=1
|
||||
']'=2
|
||||
','=4
|
||||
'.'=5
|
||||
'-'=6
|
||||
'+'=7
|
||||
'<'=8
|
||||
'>'=9
|
50
client/src/generated/bfLexer.interp
Normal file
50
client/src/generated/bfLexer.interp
Normal file
@@ -0,0 +1,50 @@
|
||||
token literal names:
|
||||
null
|
||||
'['
|
||||
']'
|
||||
null
|
||||
','
|
||||
'.'
|
||||
'-'
|
||||
'+'
|
||||
'<'
|
||||
'>'
|
||||
null
|
||||
null
|
||||
|
||||
token symbolic names:
|
||||
null
|
||||
LOOPSTART
|
||||
LOOPEND
|
||||
NUMBER
|
||||
INPUT
|
||||
OUTPUT
|
||||
DEC
|
||||
INC
|
||||
LEFT
|
||||
RIGHT
|
||||
EVERYTHING_ELSE
|
||||
WS
|
||||
|
||||
rule names:
|
||||
LOOPSTART
|
||||
LOOPEND
|
||||
NUMBER
|
||||
INPUT
|
||||
OUTPUT
|
||||
DEC
|
||||
INC
|
||||
LEFT
|
||||
RIGHT
|
||||
EVERYTHING_ELSE
|
||||
WS
|
||||
|
||||
channel names:
|
||||
DEFAULT_TOKEN_CHANNEL
|
||||
HIDDEN
|
||||
|
||||
mode names:
|
||||
DEFAULT_MODE
|
||||
|
||||
atn:
|
||||
[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 2, 13, 54, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 6, 4, 31, 10, 4, 13, 4, 14, 4, 32, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 2, 2, 2, 13, 3, 2, 3, 5, 2, 4, 7, 2, 5, 9, 2, 6, 11, 2, 7, 13, 2, 8, 15, 2, 9, 17, 2, 10, 19, 2, 11, 21, 2, 12, 23, 2, 13, 3, 2, 4, 3, 2, 50, 59, 5, 2, 12, 12, 15, 15, 34, 34, 2, 54, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 3, 25, 3, 2, 2, 2, 5, 27, 3, 2, 2, 2, 7, 30, 3, 2, 2, 2, 9, 34, 3, 2, 2, 2, 11, 36, 3, 2, 2, 2, 13, 38, 3, 2, 2, 2, 15, 40, 3, 2, 2, 2, 17, 42, 3, 2, 2, 2, 19, 44, 3, 2, 2, 2, 21, 46, 3, 2, 2, 2, 23, 50, 3, 2, 2, 2, 25, 26, 7, 93, 2, 2, 26, 4, 3, 2, 2, 2, 27, 28, 7, 95, 2, 2, 28, 6, 3, 2, 2, 2, 29, 31, 9, 2, 2, 2, 30, 29, 3, 2, 2, 2, 31, 32, 3, 2, 2, 2, 32, 30, 3, 2, 2, 2, 32, 33, 3, 2, 2, 2, 33, 8, 3, 2, 2, 2, 34, 35, 7, 46, 2, 2, 35, 10, 3, 2, 2, 2, 36, 37, 7, 48, 2, 2, 37, 12, 3, 2, 2, 2, 38, 39, 7, 47, 2, 2, 39, 14, 3, 2, 2, 2, 40, 41, 7, 45, 2, 2, 41, 16, 3, 2, 2, 2, 42, 43, 7, 62, 2, 2, 43, 18, 3, 2, 2, 2, 44, 45, 7, 64, 2, 2, 45, 20, 3, 2, 2, 2, 46, 47, 11, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 49, 8, 11, 2, 2, 49, 22, 3, 2, 2, 2, 50, 51, 9, 3, 2, 2, 51, 52, 3, 2, 2, 2, 52, 53, 8, 12, 3, 2, 53, 24, 3, 2, 2, 2, 4, 2, 32, 4, 2, 3, 2, 8, 2, 2]
|
19
client/src/generated/bfLexer.tokens
Normal file
19
client/src/generated/bfLexer.tokens
Normal file
@@ -0,0 +1,19 @@
|
||||
LOOPSTART=1
|
||||
LOOPEND=2
|
||||
NUMBER=3
|
||||
INPUT=4
|
||||
OUTPUT=5
|
||||
DEC=6
|
||||
INC=7
|
||||
LEFT=8
|
||||
RIGHT=9
|
||||
EVERYTHING_ELSE=10
|
||||
WS=11
|
||||
'['=1
|
||||
']'=2
|
||||
','=4
|
||||
'.'=5
|
||||
'-'=6
|
||||
'+'=7
|
||||
'<'=8
|
||||
'>'=9
|
119
client/src/generated/bfLexer.ts
Normal file
119
client/src/generated/bfLexer.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
// Generated from bf.g4 by ANTLR 4.9.0-SNAPSHOT
|
||||
|
||||
|
||||
import { ATN } from "antlr4ts/atn/ATN";
|
||||
import { ATNDeserializer } from "antlr4ts/atn/ATNDeserializer";
|
||||
import { CharStream } from "antlr4ts/CharStream";
|
||||
import { Lexer } from "antlr4ts/Lexer";
|
||||
import { LexerATNSimulator } from "antlr4ts/atn/LexerATNSimulator";
|
||||
import { NotNull } from "antlr4ts/Decorators";
|
||||
import { Override } from "antlr4ts/Decorators";
|
||||
import { RuleContext } from "antlr4ts/RuleContext";
|
||||
import { Vocabulary } from "antlr4ts/Vocabulary";
|
||||
import { VocabularyImpl } from "antlr4ts/VocabularyImpl";
|
||||
|
||||
import * as Utils from "antlr4ts/misc/Utils";
|
||||
|
||||
|
||||
export class bfLexer extends Lexer {
|
||||
public static readonly LOOPSTART = 1;
|
||||
public static readonly LOOPEND = 2;
|
||||
public static readonly NUMBER = 3;
|
||||
public static readonly INPUT = 4;
|
||||
public static readonly OUTPUT = 5;
|
||||
public static readonly DEC = 6;
|
||||
public static readonly INC = 7;
|
||||
public static readonly LEFT = 8;
|
||||
public static readonly RIGHT = 9;
|
||||
public static readonly EVERYTHING_ELSE = 10;
|
||||
public static readonly WS = 11;
|
||||
|
||||
// tslint:disable:no-trailing-whitespace
|
||||
public static readonly channelNames: string[] = [
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
|
||||
];
|
||||
|
||||
// tslint:disable:no-trailing-whitespace
|
||||
public static readonly modeNames: string[] = [
|
||||
"DEFAULT_MODE",
|
||||
];
|
||||
|
||||
public static readonly ruleNames: string[] = [
|
||||
"LOOPSTART", "LOOPEND", "NUMBER", "INPUT", "OUTPUT", "DEC", "INC", "LEFT",
|
||||
"RIGHT", "EVERYTHING_ELSE", "WS",
|
||||
];
|
||||
|
||||
private static readonly _LITERAL_NAMES: Array<string | undefined> = [
|
||||
undefined, "'['", "']'", undefined, "','", "'.'", "'-'", "'+'", "'<'",
|
||||
"'>'",
|
||||
];
|
||||
private static readonly _SYMBOLIC_NAMES: Array<string | undefined> = [
|
||||
undefined, "LOOPSTART", "LOOPEND", "NUMBER", "INPUT", "OUTPUT", "DEC",
|
||||
"INC", "LEFT", "RIGHT", "EVERYTHING_ELSE", "WS",
|
||||
];
|
||||
public static readonly VOCABULARY: Vocabulary = new VocabularyImpl(bfLexer._LITERAL_NAMES, bfLexer._SYMBOLIC_NAMES, []);
|
||||
|
||||
// @Override
|
||||
// @NotNull
|
||||
public get vocabulary(): Vocabulary {
|
||||
return bfLexer.VOCABULARY;
|
||||
}
|
||||
// tslint:enable:no-trailing-whitespace
|
||||
|
||||
|
||||
constructor(input: CharStream) {
|
||||
super(input);
|
||||
this._interp = new LexerATNSimulator(bfLexer._ATN, this);
|
||||
}
|
||||
|
||||
// @Override
|
||||
public get grammarFileName(): string { return "bf.g4"; }
|
||||
|
||||
// @Override
|
||||
public get ruleNames(): string[] { return bfLexer.ruleNames; }
|
||||
|
||||
// @Override
|
||||
public get serializedATN(): string { return bfLexer._serializedATN; }
|
||||
|
||||
// @Override
|
||||
public get channelNames(): string[] { return bfLexer.channelNames; }
|
||||
|
||||
// @Override
|
||||
public get modeNames(): string[] { return bfLexer.modeNames; }
|
||||
|
||||
public static readonly _serializedATN: string =
|
||||
"\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x02\r6\b\x01\x04" +
|
||||
"\x02\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04" +
|
||||
"\x07\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f\t\f\x03\x02\x03" +
|
||||
"\x02\x03\x03\x03\x03\x03\x04\x06\x04\x1F\n\x04\r\x04\x0E\x04 \x03\x05" +
|
||||
"\x03\x05\x03\x06\x03\x06\x03\x07\x03\x07\x03\b\x03\b\x03\t\x03\t\x03\n" +
|
||||
"\x03\n\x03\v\x03\v\x03\v\x03\v\x03\f\x03\f\x03\f\x03\f\x02\x02\x02\r\x03" +
|
||||
"\x02\x03\x05\x02\x04\x07\x02\x05\t\x02\x06\v\x02\x07\r\x02\b\x0F\x02\t" +
|
||||
"\x11\x02\n\x13\x02\v\x15\x02\f\x17\x02\r\x03\x02\x04\x03\x022;\x05\x02" +
|
||||
"\f\f\x0F\x0F\"\"\x026\x02\x03\x03\x02\x02\x02\x02\x05\x03\x02\x02\x02" +
|
||||
"\x02\x07\x03\x02\x02\x02\x02\t\x03\x02\x02\x02\x02\v\x03\x02\x02\x02\x02" +
|
||||
"\r\x03\x02\x02\x02\x02\x0F\x03\x02\x02\x02\x02\x11\x03\x02\x02\x02\x02" +
|
||||
"\x13\x03\x02\x02\x02\x02\x15\x03\x02\x02\x02\x02\x17\x03\x02\x02\x02\x03" +
|
||||
"\x19\x03\x02\x02\x02\x05\x1B\x03\x02\x02\x02\x07\x1E\x03\x02\x02\x02\t" +
|
||||
"\"\x03\x02\x02\x02\v$\x03\x02\x02\x02\r&\x03\x02\x02\x02\x0F(\x03\x02" +
|
||||
"\x02\x02\x11*\x03\x02\x02\x02\x13,\x03\x02\x02\x02\x15.\x03\x02\x02\x02" +
|
||||
"\x172\x03\x02\x02\x02\x19\x1A\x07]\x02\x02\x1A\x04\x03\x02\x02\x02\x1B" +
|
||||
"\x1C\x07_\x02\x02\x1C\x06\x03\x02\x02\x02\x1D\x1F\t\x02\x02\x02\x1E\x1D" +
|
||||
"\x03\x02\x02\x02\x1F \x03\x02\x02\x02 \x1E\x03\x02\x02\x02 !\x03\x02\x02" +
|
||||
"\x02!\b\x03\x02\x02\x02\"#\x07.\x02\x02#\n\x03\x02\x02\x02$%\x070\x02" +
|
||||
"\x02%\f\x03\x02\x02\x02&\'\x07/\x02\x02\'\x0E\x03\x02\x02\x02()\x07-\x02" +
|
||||
"\x02)\x10\x03\x02\x02\x02*+\x07>\x02\x02+\x12\x03\x02\x02\x02,-\x07@\x02" +
|
||||
"\x02-\x14\x03\x02\x02\x02./\v\x02\x02\x02/0\x03\x02\x02\x0201\b\v\x02" +
|
||||
"\x021\x16\x03\x02\x02\x0223\t\x03\x02\x0234\x03\x02\x02\x0245\b\f\x03" +
|
||||
"\x025\x18\x03\x02\x02\x02\x04\x02 \x04\x02\x03\x02\b\x02\x02";
|
||||
public static __ATN: ATN;
|
||||
public static get _ATN(): ATN {
|
||||
if (!bfLexer.__ATN) {
|
||||
bfLexer.__ATN = new ATNDeserializer().deserialize(Utils.toCharArray(bfLexer._serializedATN));
|
||||
}
|
||||
|
||||
return bfLexer.__ATN;
|
||||
}
|
||||
|
||||
}
|
||||
|
638
client/src/generated/bfParser.ts
Normal file
638
client/src/generated/bfParser.ts
Normal file
@@ -0,0 +1,638 @@
|
||||
// Generated from bf.g4 by ANTLR 4.9.0-SNAPSHOT
|
||||
|
||||
|
||||
import { ATN } from "antlr4ts/atn/ATN";
|
||||
import { ATNDeserializer } from "antlr4ts/atn/ATNDeserializer";
|
||||
import { FailedPredicateException } from "antlr4ts/FailedPredicateException";
|
||||
import { NotNull } from "antlr4ts/Decorators";
|
||||
import { NoViableAltException } from "antlr4ts/NoViableAltException";
|
||||
import { Override } from "antlr4ts/Decorators";
|
||||
import { Parser } from "antlr4ts/Parser";
|
||||
import { ParserRuleContext } from "antlr4ts/ParserRuleContext";
|
||||
import { ParserATNSimulator } from "antlr4ts/atn/ParserATNSimulator";
|
||||
import { ParseTreeListener } from "antlr4ts/tree/ParseTreeListener";
|
||||
import { ParseTreeVisitor } from "antlr4ts/tree/ParseTreeVisitor";
|
||||
import { RecognitionException } from "antlr4ts/RecognitionException";
|
||||
import { RuleContext } from "antlr4ts/RuleContext";
|
||||
//import { RuleVersion } from "antlr4ts/RuleVersion";
|
||||
import { TerminalNode } from "antlr4ts/tree/TerminalNode";
|
||||
import { Token } from "antlr4ts/Token";
|
||||
import { TokenStream } from "antlr4ts/TokenStream";
|
||||
import { Vocabulary } from "antlr4ts/Vocabulary";
|
||||
import { VocabularyImpl } from "antlr4ts/VocabularyImpl";
|
||||
|
||||
import * as Utils from "antlr4ts/misc/Utils";
|
||||
|
||||
import { bfVisitor } from "./bfVisitor";
|
||||
|
||||
|
||||
export class bfParser extends Parser {
|
||||
public static readonly LOOPSTART = 1;
|
||||
public static readonly LOOPEND = 2;
|
||||
public static readonly NUMBER = 3;
|
||||
public static readonly INPUT = 4;
|
||||
public static readonly OUTPUT = 5;
|
||||
public static readonly DEC = 6;
|
||||
public static readonly INC = 7;
|
||||
public static readonly LEFT = 8;
|
||||
public static readonly RIGHT = 9;
|
||||
public static readonly EVERYTHING_ELSE = 10;
|
||||
public static readonly WS = 11;
|
||||
public static readonly RULE_program = 0;
|
||||
public static readonly RULE_statements = 1;
|
||||
public static readonly RULE_eligibleStmt = 2;
|
||||
public static readonly RULE_numberedStmt = 3;
|
||||
public static readonly RULE_stmt = 4;
|
||||
public static readonly RULE_loopStmt = 5;
|
||||
public static readonly RULE_basicStmt = 6;
|
||||
// tslint:disable:no-trailing-whitespace
|
||||
public static readonly ruleNames: string[] = [
|
||||
"program", "statements", "eligibleStmt", "numberedStmt", "stmt", "loopStmt",
|
||||
"basicStmt",
|
||||
];
|
||||
|
||||
private static readonly _LITERAL_NAMES: Array<string | undefined> = [
|
||||
undefined, "'['", "']'", undefined, "','", "'.'", "'-'", "'+'", "'<'",
|
||||
"'>'",
|
||||
];
|
||||
private static readonly _SYMBOLIC_NAMES: Array<string | undefined> = [
|
||||
undefined, "LOOPSTART", "LOOPEND", "NUMBER", "INPUT", "OUTPUT", "DEC",
|
||||
"INC", "LEFT", "RIGHT", "EVERYTHING_ELSE", "WS",
|
||||
];
|
||||
public static readonly VOCABULARY: Vocabulary = new VocabularyImpl(bfParser._LITERAL_NAMES, bfParser._SYMBOLIC_NAMES, []);
|
||||
|
||||
// @Override
|
||||
// @NotNull
|
||||
public get vocabulary(): Vocabulary {
|
||||
return bfParser.VOCABULARY;
|
||||
}
|
||||
// tslint:enable:no-trailing-whitespace
|
||||
|
||||
// @Override
|
||||
public get grammarFileName(): string { return "bf.g4"; }
|
||||
|
||||
// @Override
|
||||
public get ruleNames(): string[] { return bfParser.ruleNames; }
|
||||
|
||||
// @Override
|
||||
public get serializedATN(): string { return bfParser._serializedATN; }
|
||||
|
||||
protected createFailedPredicateException(predicate?: string, message?: string): FailedPredicateException {
|
||||
return new FailedPredicateException(this, predicate, message);
|
||||
}
|
||||
|
||||
constructor(input: TokenStream) {
|
||||
super(input);
|
||||
this._interp = new ParserATNSimulator(bfParser._ATN, this);
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public program(): ProgramContext {
|
||||
let _localctx: ProgramContext = new ProgramContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 0, bfParser.RULE_program);
|
||||
try {
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 14;
|
||||
this.statements();
|
||||
this.state = 15;
|
||||
this.match(bfParser.EOF);
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public statements(): StatementsContext {
|
||||
let _localctx: StatementsContext = new StatementsContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 2, bfParser.RULE_statements);
|
||||
let _la: number;
|
||||
try {
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 20;
|
||||
this._errHandler.sync(this);
|
||||
_la = this._input.LA(1);
|
||||
while ((((_la) & ~0x1F) === 0 && ((1 << _la) & ((1 << bfParser.LOOPSTART) | (1 << bfParser.INPUT) | (1 << bfParser.OUTPUT) | (1 << bfParser.DEC) | (1 << bfParser.INC) | (1 << bfParser.LEFT) | (1 << bfParser.RIGHT))) !== 0)) {
|
||||
{
|
||||
{
|
||||
this.state = 17;
|
||||
this.eligibleStmt();
|
||||
}
|
||||
}
|
||||
this.state = 22;
|
||||
this._errHandler.sync(this);
|
||||
_la = this._input.LA(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public eligibleStmt(): EligibleStmtContext {
|
||||
let _localctx: EligibleStmtContext = new EligibleStmtContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 4, bfParser.RULE_eligibleStmt);
|
||||
try {
|
||||
this.state = 25;
|
||||
this._errHandler.sync(this);
|
||||
switch ( this.interpreter.adaptivePredict(this._input, 1, this._ctx) ) {
|
||||
case 1:
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 23;
|
||||
this.stmt();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this.enterOuterAlt(_localctx, 2);
|
||||
{
|
||||
this.state = 24;
|
||||
this.numberedStmt();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public numberedStmt(): NumberedStmtContext {
|
||||
let _localctx: NumberedStmtContext = new NumberedStmtContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 6, bfParser.RULE_numberedStmt);
|
||||
try {
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 27;
|
||||
this.stmt();
|
||||
this.state = 28;
|
||||
this.match(bfParser.NUMBER);
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public stmt(): StmtContext {
|
||||
let _localctx: StmtContext = new StmtContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 8, bfParser.RULE_stmt);
|
||||
try {
|
||||
this.state = 32;
|
||||
this._errHandler.sync(this);
|
||||
switch (this._input.LA(1)) {
|
||||
case bfParser.INPUT:
|
||||
case bfParser.OUTPUT:
|
||||
case bfParser.DEC:
|
||||
case bfParser.INC:
|
||||
case bfParser.LEFT:
|
||||
case bfParser.RIGHT:
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 30;
|
||||
this.basicStmt();
|
||||
}
|
||||
break;
|
||||
case bfParser.LOOPSTART:
|
||||
this.enterOuterAlt(_localctx, 2);
|
||||
{
|
||||
this.state = 31;
|
||||
this.loopStmt();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NoViableAltException(this);
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public loopStmt(): LoopStmtContext {
|
||||
let _localctx: LoopStmtContext = new LoopStmtContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 10, bfParser.RULE_loopStmt);
|
||||
try {
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 34;
|
||||
this.match(bfParser.LOOPSTART);
|
||||
this.state = 35;
|
||||
this.statements();
|
||||
this.state = 36;
|
||||
this.match(bfParser.LOOPEND);
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
// @RuleVersion(0)
|
||||
public basicStmt(): BasicStmtContext {
|
||||
let _localctx: BasicStmtContext = new BasicStmtContext(this._ctx, this.state);
|
||||
this.enterRule(_localctx, 12, bfParser.RULE_basicStmt);
|
||||
try {
|
||||
this.state = 44;
|
||||
this._errHandler.sync(this);
|
||||
switch (this._input.LA(1)) {
|
||||
case bfParser.INC:
|
||||
_localctx = new PtrIncrContext(_localctx);
|
||||
this.enterOuterAlt(_localctx, 1);
|
||||
{
|
||||
this.state = 38;
|
||||
this.match(bfParser.INC);
|
||||
}
|
||||
break;
|
||||
case bfParser.DEC:
|
||||
_localctx = new PtrDecrContext(_localctx);
|
||||
this.enterOuterAlt(_localctx, 2);
|
||||
{
|
||||
this.state = 39;
|
||||
this.match(bfParser.DEC);
|
||||
}
|
||||
break;
|
||||
case bfParser.LEFT:
|
||||
_localctx = new PtrLeftContext(_localctx);
|
||||
this.enterOuterAlt(_localctx, 3);
|
||||
{
|
||||
this.state = 40;
|
||||
this.match(bfParser.LEFT);
|
||||
}
|
||||
break;
|
||||
case bfParser.RIGHT:
|
||||
_localctx = new PtrRightContext(_localctx);
|
||||
this.enterOuterAlt(_localctx, 4);
|
||||
{
|
||||
this.state = 41;
|
||||
this.match(bfParser.RIGHT);
|
||||
}
|
||||
break;
|
||||
case bfParser.INPUT:
|
||||
_localctx = new InputStmtContext(_localctx);
|
||||
this.enterOuterAlt(_localctx, 5);
|
||||
{
|
||||
this.state = 42;
|
||||
this.match(bfParser.INPUT);
|
||||
}
|
||||
break;
|
||||
case bfParser.OUTPUT:
|
||||
_localctx = new OutputStmtContext(_localctx);
|
||||
this.enterOuterAlt(_localctx, 6);
|
||||
{
|
||||
this.state = 43;
|
||||
this.match(bfParser.OUTPUT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NoViableAltException(this);
|
||||
}
|
||||
}
|
||||
catch (re) {
|
||||
if (re instanceof RecognitionException) {
|
||||
_localctx.exception = re;
|
||||
this._errHandler.reportError(this, re);
|
||||
this._errHandler.recover(this, re);
|
||||
} else {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
public static readonly _serializedATN: string =
|
||||
"\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x03\r1\x04\x02\t" +
|
||||
"\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04\x07\t" +
|
||||
"\x07\x04\b\t\b\x03\x02\x03\x02\x03\x02\x03\x03\x07\x03\x15\n\x03\f\x03" +
|
||||
"\x0E\x03\x18\v\x03\x03\x04\x03\x04\x05\x04\x1C\n\x04\x03\x05\x03\x05\x03" +
|
||||
"\x05\x03\x06\x03\x06\x05\x06#\n\x06\x03\x07\x03\x07\x03\x07\x03\x07\x03" +
|
||||
"\b\x03\b\x03\b\x03\b\x03\b\x03\b\x05\b/\n\b\x03\b\x02\x02\x02\t\x02\x02" +
|
||||
"\x04\x02\x06\x02\b\x02\n\x02\f\x02\x0E\x02\x02\x02\x021\x02\x10\x03\x02" +
|
||||
"\x02\x02\x04\x16\x03\x02\x02\x02\x06\x1B\x03\x02\x02\x02\b\x1D\x03\x02" +
|
||||
"\x02\x02\n\"\x03\x02\x02\x02\f$\x03\x02\x02\x02\x0E.\x03\x02\x02\x02\x10" +
|
||||
"\x11\x05\x04\x03\x02\x11\x12\x07\x02\x02\x03\x12\x03\x03\x02\x02\x02\x13" +
|
||||
"\x15\x05\x06\x04\x02\x14\x13\x03\x02\x02\x02\x15\x18\x03\x02\x02\x02\x16" +
|
||||
"\x14\x03\x02\x02\x02\x16\x17\x03\x02\x02\x02\x17\x05\x03\x02\x02\x02\x18" +
|
||||
"\x16\x03\x02\x02\x02\x19\x1C\x05\n\x06\x02\x1A\x1C\x05\b\x05\x02\x1B\x19" +
|
||||
"\x03\x02\x02\x02\x1B\x1A\x03\x02\x02\x02\x1C\x07\x03\x02\x02\x02\x1D\x1E" +
|
||||
"\x05\n\x06\x02\x1E\x1F\x07\x05\x02\x02\x1F\t\x03\x02\x02\x02 #\x05\x0E" +
|
||||
"\b\x02!#\x05\f\x07\x02\" \x03\x02\x02\x02\"!\x03\x02\x02\x02#\v\x03\x02" +
|
||||
"\x02\x02$%\x07\x03\x02\x02%&\x05\x04\x03\x02&\'\x07\x04\x02\x02\'\r\x03" +
|
||||
"\x02\x02\x02(/\x07\t\x02\x02)/\x07\b\x02\x02*/\x07\n\x02\x02+/\x07\v\x02" +
|
||||
"\x02,/\x07\x06\x02\x02-/\x07\x07\x02\x02.(\x03\x02\x02\x02.)\x03\x02\x02" +
|
||||
"\x02.*\x03\x02\x02\x02.+\x03\x02\x02\x02.,\x03\x02\x02\x02.-\x03\x02\x02" +
|
||||
"\x02/\x0F\x03\x02\x02\x02\x06\x16\x1B\".";
|
||||
public static __ATN: ATN;
|
||||
public static get _ATN(): ATN {
|
||||
if (!bfParser.__ATN) {
|
||||
bfParser.__ATN = new ATNDeserializer().deserialize(Utils.toCharArray(bfParser._serializedATN));
|
||||
}
|
||||
|
||||
return bfParser.__ATN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ProgramContext extends ParserRuleContext {
|
||||
public statements(): StatementsContext {
|
||||
return this.getRuleContext(0, StatementsContext);
|
||||
}
|
||||
public EOF(): TerminalNode { return this.getToken(bfParser.EOF, 0); }
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_program; }
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitProgram) {
|
||||
return visitor.visitProgram(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class StatementsContext extends ParserRuleContext {
|
||||
public eligibleStmt(): EligibleStmtContext[];
|
||||
public eligibleStmt(i: number): EligibleStmtContext;
|
||||
public eligibleStmt(i?: number): EligibleStmtContext | EligibleStmtContext[] {
|
||||
if (i === undefined) {
|
||||
return this.getRuleContexts(EligibleStmtContext);
|
||||
} else {
|
||||
return this.getRuleContext(i, EligibleStmtContext);
|
||||
}
|
||||
}
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_statements; }
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitStatements) {
|
||||
return visitor.visitStatements(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class EligibleStmtContext extends ParserRuleContext {
|
||||
public stmt(): StmtContext | undefined {
|
||||
return this.tryGetRuleContext(0, StmtContext);
|
||||
}
|
||||
public numberedStmt(): NumberedStmtContext | undefined {
|
||||
return this.tryGetRuleContext(0, NumberedStmtContext);
|
||||
}
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_eligibleStmt; }
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitEligibleStmt) {
|
||||
return visitor.visitEligibleStmt(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class NumberedStmtContext extends ParserRuleContext {
|
||||
public stmt(): StmtContext {
|
||||
return this.getRuleContext(0, StmtContext);
|
||||
}
|
||||
public NUMBER(): TerminalNode { return this.getToken(bfParser.NUMBER, 0); }
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_numberedStmt; }
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitNumberedStmt) {
|
||||
return visitor.visitNumberedStmt(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class StmtContext extends ParserRuleContext {
|
||||
public basicStmt(): BasicStmtContext | undefined {
|
||||
return this.tryGetRuleContext(0, BasicStmtContext);
|
||||
}
|
||||
public loopStmt(): LoopStmtContext | undefined {
|
||||
return this.tryGetRuleContext(0, LoopStmtContext);
|
||||
}
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_stmt; }
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitStmt) {
|
||||
return visitor.visitStmt(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class LoopStmtContext extends ParserRuleContext {
|
||||
public LOOPSTART(): TerminalNode { return this.getToken(bfParser.LOOPSTART, 0); }
|
||||
public statements(): StatementsContext {
|
||||
return this.getRuleContext(0, StatementsContext);
|
||||
}
|
||||
public LOOPEND(): TerminalNode { return this.getToken(bfParser.LOOPEND, 0); }
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_loopStmt; }
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitLoopStmt) {
|
||||
return visitor.visitLoopStmt(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class BasicStmtContext extends ParserRuleContext {
|
||||
constructor(parent: ParserRuleContext | undefined, invokingState: number) {
|
||||
super(parent, invokingState);
|
||||
}
|
||||
// @Override
|
||||
public get ruleIndex(): number { return bfParser.RULE_basicStmt; }
|
||||
public copyFrom(ctx: BasicStmtContext): void {
|
||||
super.copyFrom(ctx);
|
||||
}
|
||||
}
|
||||
export class PtrIncrContext extends BasicStmtContext {
|
||||
public INC(): TerminalNode { return this.getToken(bfParser.INC, 0); }
|
||||
constructor(ctx: BasicStmtContext) {
|
||||
super(ctx.parent, ctx.invokingState);
|
||||
this.copyFrom(ctx);
|
||||
}
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitPtrIncr) {
|
||||
return visitor.visitPtrIncr(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class PtrDecrContext extends BasicStmtContext {
|
||||
public DEC(): TerminalNode { return this.getToken(bfParser.DEC, 0); }
|
||||
constructor(ctx: BasicStmtContext) {
|
||||
super(ctx.parent, ctx.invokingState);
|
||||
this.copyFrom(ctx);
|
||||
}
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitPtrDecr) {
|
||||
return visitor.visitPtrDecr(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class PtrLeftContext extends BasicStmtContext {
|
||||
public LEFT(): TerminalNode { return this.getToken(bfParser.LEFT, 0); }
|
||||
constructor(ctx: BasicStmtContext) {
|
||||
super(ctx.parent, ctx.invokingState);
|
||||
this.copyFrom(ctx);
|
||||
}
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitPtrLeft) {
|
||||
return visitor.visitPtrLeft(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class PtrRightContext extends BasicStmtContext {
|
||||
public RIGHT(): TerminalNode { return this.getToken(bfParser.RIGHT, 0); }
|
||||
constructor(ctx: BasicStmtContext) {
|
||||
super(ctx.parent, ctx.invokingState);
|
||||
this.copyFrom(ctx);
|
||||
}
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitPtrRight) {
|
||||
return visitor.visitPtrRight(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class InputStmtContext extends BasicStmtContext {
|
||||
public INPUT(): TerminalNode { return this.getToken(bfParser.INPUT, 0); }
|
||||
constructor(ctx: BasicStmtContext) {
|
||||
super(ctx.parent, ctx.invokingState);
|
||||
this.copyFrom(ctx);
|
||||
}
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitInputStmt) {
|
||||
return visitor.visitInputStmt(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class OutputStmtContext extends BasicStmtContext {
|
||||
public OUTPUT(): TerminalNode { return this.getToken(bfParser.OUTPUT, 0); }
|
||||
constructor(ctx: BasicStmtContext) {
|
||||
super(ctx.parent, ctx.invokingState);
|
||||
this.copyFrom(ctx);
|
||||
}
|
||||
// @Override
|
||||
public accept<Result>(visitor: bfVisitor<Result>): Result {
|
||||
if (visitor.visitOutputStmt) {
|
||||
return visitor.visitOutputStmt(this);
|
||||
} else {
|
||||
return visitor.visitChildren(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
126
client/src/generated/bfVisitor.ts
Normal file
126
client/src/generated/bfVisitor.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
// Generated from bf.g4 by ANTLR 4.9.0-SNAPSHOT
|
||||
|
||||
|
||||
import { ParseTreeVisitor } from "antlr4ts/tree/ParseTreeVisitor";
|
||||
|
||||
import { PtrIncrContext } from "./bfParser";
|
||||
import { PtrDecrContext } from "./bfParser";
|
||||
import { PtrLeftContext } from "./bfParser";
|
||||
import { PtrRightContext } from "./bfParser";
|
||||
import { InputStmtContext } from "./bfParser";
|
||||
import { OutputStmtContext } from "./bfParser";
|
||||
import { ProgramContext } from "./bfParser";
|
||||
import { StatementsContext } from "./bfParser";
|
||||
import { EligibleStmtContext } from "./bfParser";
|
||||
import { NumberedStmtContext } from "./bfParser";
|
||||
import { StmtContext } from "./bfParser";
|
||||
import { LoopStmtContext } from "./bfParser";
|
||||
import { BasicStmtContext } from "./bfParser";
|
||||
|
||||
|
||||
/**
|
||||
* This interface defines a complete generic visitor for a parse tree produced
|
||||
* by `bfParser`.
|
||||
*
|
||||
* @param <Result> The return type of the visit operation. Use `void` for
|
||||
* operations with no return type.
|
||||
*/
|
||||
export interface bfVisitor<Result> extends ParseTreeVisitor<Result> {
|
||||
/**
|
||||
* Visit a parse tree produced by the `ptrIncr`
|
||||
* labeled alternative in `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitPtrIncr?: (ctx: PtrIncrContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by the `ptrDecr`
|
||||
* labeled alternative in `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitPtrDecr?: (ctx: PtrDecrContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by the `ptrLeft`
|
||||
* labeled alternative in `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitPtrLeft?: (ctx: PtrLeftContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by the `ptrRight`
|
||||
* labeled alternative in `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitPtrRight?: (ctx: PtrRightContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by the `inputStmt`
|
||||
* labeled alternative in `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitInputStmt?: (ctx: InputStmtContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by the `outputStmt`
|
||||
* labeled alternative in `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitOutputStmt?: (ctx: OutputStmtContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.program`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitProgram?: (ctx: ProgramContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.statements`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitStatements?: (ctx: StatementsContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.eligibleStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitEligibleStmt?: (ctx: EligibleStmtContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.numberedStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitNumberedStmt?: (ctx: NumberedStmtContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.stmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitStmt?: (ctx: StmtContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.loopStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitLoopStmt?: (ctx: LoopStmtContext) => Result;
|
||||
|
||||
/**
|
||||
* Visit a parse tree produced by `bfParser.basicStmt`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitBasicStmt?: (ctx: BasicStmtContext) => Result;
|
||||
}
|
||||
|
4
client/src/input/InputStrategy.ts
Normal file
4
client/src/input/InputStrategy.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
export default interface InputStrategy {
|
||||
getInput(): Promise<number>;
|
||||
}
|
28
client/src/input/VSCodePromptInputStrategy.ts
Normal file
28
client/src/input/VSCodePromptInputStrategy.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { CancellationToken, InputBoxOptions } from 'vscode';
|
||||
import InputStrategy from './InputStrategy';
|
||||
|
||||
export class VSCodePromptInputStrategy implements InputStrategy {
|
||||
private inputQueue: string = '';
|
||||
constructor(
|
||||
private requestor: (
|
||||
promptOptions?: InputBoxOptions,
|
||||
cancelToken?: CancellationToken
|
||||
) => Thenable<string>
|
||||
) {}
|
||||
|
||||
async getInput(): Promise<number> {
|
||||
while (this.inputQueue.length == 0) {
|
||||
await this.requestInputFromPrompt();
|
||||
}
|
||||
const character = this.inputQueue.charCodeAt(0);
|
||||
this.inputQueue = this.inputQueue.substring(1);
|
||||
|
||||
return character;
|
||||
}
|
||||
private async requestInputFromPrompt() {
|
||||
const inputPrompt = await this.requestor({
|
||||
prompt: 'More input is required. Please provide input:',
|
||||
});
|
||||
this.inputQueue += inputPrompt;
|
||||
}
|
||||
}
|
56
client/webpack.config.js
Normal file
56
client/webpack.config.js
Normal file
@@ -0,0 +1,56 @@
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
// const {} = require('webpack');
|
||||
/**@type {import('webpack').Configuration}*/
|
||||
const config = {
|
||||
target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
|
||||
entry: {
|
||||
extension:path.join(__dirname,'src','extension.ts'),
|
||||
}, // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
devtoolModuleFilenameTemplate: '../[resource-path]'
|
||||
},
|
||||
// devtool: 'source-map',
|
||||
externals: {
|
||||
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||
},
|
||||
optimization:{
|
||||
minimize:true,
|
||||
innerGraph:true,
|
||||
usedExports:true
|
||||
},
|
||||
resolve: {
|
||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||
extensions: ['.ts', '.js'],
|
||||
plugins:[]
|
||||
},
|
||||
// stats:'minimal',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options:{
|
||||
configFile : 'tsconfig.json'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
};
|
||||
module.exports = config;
|
3884
package-lock.json
generated
3884
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
35
package.json
35
package.json
@@ -1,18 +1,19 @@
|
||||
{
|
||||
"name": "bfc-server",
|
||||
"displayName": "BF Language",
|
||||
"description": "Brainfuck",
|
||||
"author": "Rose",
|
||||
"description": "BF Syntax Support",
|
||||
"author": "Atreya Bain",
|
||||
"license": "MIT",
|
||||
"publisher": "Rose",
|
||||
"version": "0.0.1",
|
||||
"publisher": "atreyabain",
|
||||
"version": "0.2.0",
|
||||
"icon": "assets/128.png",
|
||||
"categories": [],
|
||||
"keywords": [
|
||||
"multi-root ready",
|
||||
"brainfuck",
|
||||
"branflakes"
|
||||
],
|
||||
"prettier":{
|
||||
"prettier": {
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"arrowParens": "avoid",
|
||||
@@ -26,9 +27,9 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url":"https://github.com/chrisvrose/bf-server"
|
||||
"url": "https://github.com/chrisvrose/bf-server"
|
||||
},
|
||||
"main": "./client/out/extension",
|
||||
"main": "./client/dist/extension",
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
@@ -54,7 +55,14 @@
|
||||
"path": "./syntaxes/bf.tmLanguage.json"
|
||||
}
|
||||
],
|
||||
"commands": [],
|
||||
"commands": [
|
||||
{
|
||||
"command": "bf.execute",
|
||||
"title": "BF: Execute",
|
||||
"when": "editorLangId == bf",
|
||||
"enablement": "editorLangId == bf"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Configurable properties",
|
||||
@@ -81,7 +89,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -b",
|
||||
"compile": "concurrently \"npm run webpack-prod --prefix client\" \"npm run webpack-prod --prefix server \"",
|
||||
"_compile": "tsc -b",
|
||||
"watch": "tsc -b -w",
|
||||
"postinstall": "cd client && npm install && cd ../server && npm install && cd .."
|
||||
},
|
||||
@@ -92,6 +101,12 @@
|
||||
"@typescript-eslint/parser": "^2.33.0",
|
||||
"eslint": "^6.4.0",
|
||||
"mocha": "^6.2.2",
|
||||
"typescript": "^3.9.2"
|
||||
"ts-loader": "^8.1.0",
|
||||
"typescript": "^3.9.2",
|
||||
"webpack": "^5.33.2",
|
||||
"webpack-cli": "^4.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"concurrently": "^6.0.2"
|
||||
}
|
||||
}
|
||||
|
2348
server/package-lock.json
generated
2348
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,5 +15,13 @@
|
||||
"vscode-languageserver": "^6.1.1",
|
||||
"vscode-languageserver-textdocument": "^1.0.1"
|
||||
},
|
||||
"scripts": {}
|
||||
"scripts": {
|
||||
"webpack-prod":"webpack --mode production",
|
||||
"webpack": "webpack --mode development",
|
||||
"webpack-dev": "webpack --mode development --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^5.33.2",
|
||||
"webpack-cli": "^4.6.0"
|
||||
}
|
||||
}
|
||||
|
@@ -18,10 +18,11 @@ import {
|
||||
Position,
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
// import * as path from 'path';
|
||||
|
||||
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
|
||||
|
||||
// Create a connection for the server. The connection uses Node's IPC as a transport.
|
||||
// Also include all preview / proposed LSP features.
|
||||
let connection = createConnection(ProposedFeatures.all);
|
||||
@@ -149,19 +150,19 @@ documents.onDidSave(change => {
|
||||
|
||||
const validateBrackets = (text: string) => {
|
||||
let count = 0, lp: number[] = [],issues:number[]=[];
|
||||
const textsplit = text.split(``);
|
||||
const textsplit = text.split('');
|
||||
textsplit.forEach((x, i) => {
|
||||
if (x == '[' || x == ']') {
|
||||
if (x === '[' || x === ']') {
|
||||
|
||||
if (x == '[') lp.push(i);
|
||||
if (x == ']') {if(lp.length==0) issues.push(i);lp.pop();}
|
||||
if (x === '[') {lp.push(i);}
|
||||
if (x === ']') {if(lp.length===0) {issues.push(i);}lp.pop();}
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return [...lp,...issues]
|
||||
return [...lp,...issues];
|
||||
};
|
||||
|
||||
async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
@@ -174,15 +175,15 @@ async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
const issues = validateBrackets(text);
|
||||
|
||||
diagnostics.push(...issues.map<Diagnostic>(e => ({
|
||||
message: 'Brackets unmatched',
|
||||
range:{
|
||||
start: textDocument.positionAt(e),
|
||||
end: textDocument.positionAt(e+1),
|
||||
},
|
||||
severity:DiagnosticSeverity.Error,
|
||||
code:'[ and ]',
|
||||
})));
|
||||
diagnostics.push(...issues.map<Diagnostic>(e => ({
|
||||
message: 'Brackets unmatched',
|
||||
range:{
|
||||
start: textDocument.positionAt(e),
|
||||
end: textDocument.positionAt(e+1),
|
||||
},
|
||||
severity:DiagnosticSeverity.Error,
|
||||
code:'[ and ]',
|
||||
})));
|
||||
|
||||
// diagnostics.push({
|
||||
// message: 'Brackets not matched',
|
||||
|
55
server/webpack.config.js
Normal file
55
server/webpack.config.js
Normal file
@@ -0,0 +1,55 @@
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
/**@type {import('webpack').Configuration}*/
|
||||
const config = {
|
||||
target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
|
||||
entry: {
|
||||
server:path.join(__dirname,'src','server.ts'),
|
||||
}, // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
devtoolModuleFilenameTemplate: '../[resource-path]'
|
||||
},
|
||||
// stats:'minimal',
|
||||
// devtool: 'source-map',
|
||||
externals: {
|
||||
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||
},
|
||||
optimization:{
|
||||
minimize:true,
|
||||
innerGraph:true,
|
||||
usedExports:true
|
||||
},
|
||||
resolve: {
|
||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||
extensions: ['.ts', '.js'],
|
||||
plugins:[]
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options:{
|
||||
configFile : 'tsconfig.json'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
};
|
||||
module.exports = config;
|
Reference in New Issue
Block a user