├── .github
└── workflows
│ ├── ci.yaml
│ └── master_smallbasic-publicwebsite-code.yml
├── .gitignore
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── SmallBasic.sln
├── Source
├── Directory.Build.props
├── SmallBasic.Analyzers
│ ├── DoNotUseAsserts.cs
│ ├── SmallBasic.Analyzers.csproj
│ └── UseIsDefaultHelper.cs
├── SmallBasic.Bridge
│ ├── Bridge.Generated.cs
│ ├── FileBridge.cs
│ ├── NetworkBridge.cs
│ ├── ProcessBridge.cs
│ ├── Program.cs
│ └── SmallBasic.Bridge.csproj
├── SmallBasic.Client
│ ├── Bridge
│ │ └── Bridge.Generated.ts
│ ├── Entries
│ │ ├── Electron.ts
│ │ ├── Renderer.ts
│ │ ├── Styles.scss
│ │ ├── Template.html
│ │ └── Web.ts
│ ├── Images
│ │ ├── Actions
│ │ │ ├── Back.svg
│ │ │ ├── Continue.svg
│ │ │ ├── Copy.svg
│ │ │ ├── Cut.svg
│ │ │ ├── Debug.svg
│ │ │ ├── Import.svg
│ │ │ ├── New.svg
│ │ │ ├── NextLine.svg
│ │ │ ├── Open.svg
│ │ │ ├── Paste.svg
│ │ │ ├── Pause.svg
│ │ │ ├── Publish.svg
│ │ │ ├── Redo.svg
│ │ │ ├── Run.svg
│ │ │ ├── Save.svg
│ │ │ └── Undo.svg
│ │ ├── Caret.svg
│ │ ├── EditPage
│ │ │ ├── Error.svg
│ │ │ └── LibraryExplorer.svg
│ │ ├── MemoryExplorer
│ │ │ ├── ArrayType.svg
│ │ │ ├── CallStack.svg
│ │ │ ├── MemoryExplorer.svg
│ │ │ ├── NumberType.svg
│ │ │ ├── ProgramEnded.svg
│ │ │ ├── ProgramRunning.svg
│ │ │ ├── StringType.svg
│ │ │ └── Variables.svg
│ │ ├── Turtle.svg
│ │ ├── favicon.ico
│ │ └── logo.svg
│ ├── Interop
│ │ ├── CSInterop.Generated.ts
│ │ ├── JSInterop.Generated.ts
│ │ ├── LayoutInterop.ts
│ │ └── MonacoInterop.ts
│ ├── SmallBasic.Client.csproj
│ ├── Utility
│ │ ├── GraphicsDisplay.ts
│ │ ├── SetupAppInsights.ts
│ │ └── SetupMonacoEnvironment.ts
│ ├── package.json
│ ├── tsconfig.json
│ ├── tslint.json
│ ├── webpack.config.ts
│ └── yarn.lock
├── SmallBasic.Compiler
│ ├── Binding
│ │ ├── BaseBoundNode.cs
│ │ ├── Binder.cs
│ │ ├── BoundNodes.Generated.cs
│ │ └── Visitors
│ │ │ ├── GoToUndefinedLabelChecker.cs
│ │ │ ├── LabelDefinitionsCollector.cs
│ │ │ ├── RuntimeAnalysis.cs
│ │ │ └── VariablesAndSubModulesCollector.cs
│ ├── Diagnostics
│ │ ├── Diagnostic.cs
│ │ ├── DiagnosticBag.Generated.cs
│ │ └── DiagnosticCode.Generated.cs
│ ├── Parsing
│ │ ├── BaseSyntaxNode.cs
│ │ ├── Parser.cs
│ │ ├── SyntaxNodes.Generated.cs
│ │ └── Visitors
│ │ │ └── SubModuleNamesCollector.cs
│ ├── Runtime
│ │ ├── DebuggerSnapshot.cs
│ │ ├── Frame.cs
│ │ ├── Instructions
│ │ │ ├── BaseInstructions.cs
│ │ │ ├── ChangingStateInstructions.cs
│ │ │ ├── JumpInstructions.cs
│ │ │ ├── MemoryInstructions.cs
│ │ │ ├── OperatorInstructions.cs
│ │ │ └── OtherInstructions.cs
│ │ ├── Libraries
│ │ │ ├── Libraries.Generated.cs
│ │ │ └── Libraries.Interfaces.Generated.cs
│ │ ├── ModuleEmitter.cs
│ │ ├── RuntimeModule.cs
│ │ └── Values
│ │ │ ├── ArrayValue.cs
│ │ │ ├── BaseValue.cs
│ │ │ ├── BooleanValue.cs
│ │ │ ├── NumberValue.cs
│ │ │ └── StringValue.cs
│ ├── Scanning
│ │ ├── Scanner.cs
│ │ ├── TextPosition.cs
│ │ ├── TextRange.cs
│ │ ├── Token.cs
│ │ └── TokenKind.Generated.cs
│ ├── Services
│ │ ├── CompletionItemProvider.cs
│ │ ├── HoverProvider.cs
│ │ └── MonacoTypes.cs
│ ├── SmallBasic.Compiler.csproj
│ ├── SmallBasicCompilation.cs
│ └── SmallBasicEngine.cs
├── SmallBasic.Editor
│ ├── Bridge
│ │ └── Bridge.Generated.cs
│ ├── Components
│ │ ├── Display
│ │ │ ├── EngineDisplay.cs
│ │ │ ├── EngineDisplay.scss
│ │ │ ├── GraphicsDisplay.cs
│ │ │ ├── GraphicsDisplay.scss
│ │ │ ├── TextDisplay.cs
│ │ │ └── TextDisplay.scss
│ │ ├── Layout
│ │ │ ├── App.cs
│ │ │ ├── MainLayout.cs
│ │ │ ├── MainLayout.scss
│ │ │ └── SmallBasicComponent.cs
│ │ ├── Pages
│ │ │ ├── Debug
│ │ │ │ ├── DebugPage.cs
│ │ │ │ ├── DebugPage.scss
│ │ │ │ ├── MemoryExplorer.cs
│ │ │ │ └── MemoryExplorer.scss
│ │ │ ├── Edit
│ │ │ │ ├── EditPage.cs
│ │ │ │ ├── EditPage.scss
│ │ │ │ ├── ErrorsSpace.cs
│ │ │ │ ├── ErrorsSpace.scss
│ │ │ │ ├── LibraryBody.cs
│ │ │ │ ├── LibraryBody.scss
│ │ │ │ ├── LibraryExplorer.cs
│ │ │ │ └── LibraryExplorer.scss
│ │ │ ├── IndexPage.cs
│ │ │ └── Run
│ │ │ │ ├── RunPage.cs
│ │ │ │ └── RunPage.scss
│ │ ├── Toolbox
│ │ │ ├── ActionsRow.cs
│ │ │ ├── ActionsRow.scss
│ │ │ ├── Micro.cs
│ │ │ ├── MonacoEditor.cs
│ │ │ └── MonacoEditor.scss
│ │ └── TreeComposer.cs
│ ├── Interop
│ │ ├── CSInterop.Generated.cs
│ │ ├── GraphicsDisplayInterop.cs
│ │ ├── JSInterop.Generated.cs
│ │ └── MonacoInterop.cs
│ ├── Libraries
│ │ ├── ArrayLibrary.cs
│ │ ├── ClockLibrary.cs
│ │ ├── Controls
│ │ │ ├── BaseControl.cs
│ │ │ ├── ButtonControl.cs
│ │ │ ├── MultilineTextBoxControl.cs
│ │ │ └── TextBoxControl.cs
│ │ ├── ControlsLibrary.cs
│ │ ├── DesktopLibrary.cs
│ │ ├── DictionaryLibrary.cs
│ │ ├── FileLibrary.cs
│ │ ├── FlickrLibrary.cs
│ │ ├── Graphics
│ │ │ ├── BaseGraphicsObject.cs
│ │ │ ├── EllipseGraphicsObject.cs
│ │ │ ├── ImageGraphicsObject.cs
│ │ │ ├── LineGraphicsObject.cs
│ │ │ ├── RectangleGraphicsObject.cs
│ │ │ ├── TextGraphicsObject.cs
│ │ │ ├── TriangleGraphicsObject.cs
│ │ │ └── TurtleGraphicsObject.cs
│ │ ├── GraphicsWindowLibrary.cs
│ │ ├── ImageListLibrary.cs
│ │ ├── LibrariesCollection.cs
│ │ ├── MathLibrary.cs
│ │ ├── MouseLibrary.cs
│ │ ├── NetworkLibrary.cs
│ │ ├── ProgramLibrary.cs
│ │ ├── Shapes
│ │ │ ├── BaseShape.cs
│ │ │ ├── EllipseShape.cs
│ │ │ ├── ImageShape.cs
│ │ │ ├── LineShape.cs
│ │ │ ├── RectangleShape.cs
│ │ │ ├── TextShape.cs
│ │ │ ├── TriangleShape.cs
│ │ │ └── TurtleShape.cs
│ │ ├── ShapesLibrary.cs
│ │ ├── SoundLibrary.cs
│ │ ├── StackLibrary.cs
│ │ ├── TextLibrary.cs
│ │ ├── TextWindowLibrary.cs
│ │ ├── TimerLibrary.cs
│ │ ├── TurtleLibrary.cs
│ │ └── Utilities
│ │ │ ├── AsyncEngine.cs
│ │ │ ├── GraphicsWindowStyles.cs
│ │ │ ├── NamedCounter.cs
│ │ │ └── PredefinedColors.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── SmallBasic.Editor.csproj
│ └── Store
│ │ ├── CompilationStore.cs
│ │ ├── GraphicsDisplayStore.cs
│ │ ├── NavigationStore.cs
│ │ └── TextDisplayStore.cs
├── SmallBasic.Generators
│ ├── BaseConverterTask.cs
│ ├── BaseTask.cs
│ ├── Binding
│ │ ├── BoundNodes.xml
│ │ ├── GenerateBoundNodes.cs
│ │ └── Models.cs
│ ├── Bridge
│ │ ├── BridgeTypes.xml
│ │ ├── GenerateBridgeExecution.cs
│ │ ├── GenerateClientBridge.cs
│ │ ├── GenerateEditorBridge.cs
│ │ └── Models.cs
│ ├── Diagnostics
│ │ ├── Diagnostics.xml
│ │ ├── GenerateDiagnosticBag.cs
│ │ ├── GenerateDiagnosticCode.cs
│ │ └── Models.cs
│ ├── Interop
│ │ ├── CSInteropTypes.xml
│ │ ├── GenerateCSClientInterop.cs
│ │ ├── GenerateCSEditorInterop.cs
│ │ ├── GenerateJSClientInterop.cs
│ │ ├── GenerateJSEditorInterop.cs
│ │ ├── JSInteropTypes.xml
│ │ └── Models.cs
│ ├── Libraries
│ │ ├── GenerateLibraries.cs
│ │ ├── GenerateLibraryInterfaces.cs
│ │ ├── GenerateLoggingTestLibraries.cs
│ │ ├── Libraries.xml
│ │ └── Models.cs
│ ├── Parsing
│ │ ├── GenerateSyntaxNodes.cs
│ │ ├── Models.cs
│ │ └── SyntaxNodes.xml
│ ├── Program.cs
│ ├── Scanning
│ │ ├── GenerateTokenKinds.cs
│ │ ├── Models.cs
│ │ └── TokenKinds.xml
│ └── SmallBasic.Generators.csproj
├── SmallBasic.Server
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ └── SmallBasic.Server.csproj
├── SmallBasic.Tests
│ ├── Compiler
│ │ ├── BindingTests.cs
│ │ ├── ParsingTests.cs
│ │ └── ScanningTests.cs
│ ├── CultureFixture.cs
│ ├── LoggingTestLibraries.Generated.cs
│ ├── Runtime
│ │ ├── ExpressionTests.cs
│ │ ├── LibrariesTests.cs
│ │ ├── OperatorTests.cs
│ │ ├── RuntimeAnalysisTests.cs
│ │ └── StatementsTests.cs
│ ├── Services
│ │ ├── CompletionItemProviderTests.cs
│ │ └── HoverProviderTests.cs
│ ├── SmallBasic.Tests.csproj
│ └── TestExtensions.cs
├── SmallBasic.Utilities
│ ├── Bridge
│ │ ├── FileBridgeModels.cs
│ │ └── ImageListBridgeModels.cs
│ ├── ExceptionUtilities.cs
│ ├── Extensions
│ │ ├── ObjectExtensions.cs
│ │ └── StringExtensions.cs
│ ├── Resources
│ │ ├── DiagnosticsResources.Designer.cs
│ │ ├── DiagnosticsResources.resx
│ │ ├── EditorResources.Designer.cs
│ │ ├── EditorResources.resx
│ │ ├── LibrariesResources.Designer.cs
│ │ ├── LibrariesResources.resx
│ │ ├── TokenKindsResources.Designer.cs
│ │ └── TokenKindsResources.resx
│ └── SmallBasic.Utilities.csproj
└── stylecop.json
└── global.json
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | pull_request:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | strategy:
10 | matrix:
11 | configuration: ["Debug", "Release"]
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v1
15 | with:
16 | node-version: 16.11.1
17 | - uses: actions/setup-dotnet@v1.7.2
18 | with:
19 | dotnet-version: 2.1.816
20 | - run: yarn --ci
21 | working-directory: ./Source/SmallBasic.Client
22 | - run: dotnet restore
23 | - run: dotnet build ./SmallBasic.sln /p:TreatWarningsAsErrors=True /p:Configuration=${{matrix.configuration}}
24 | - run: dotnet test ./Source/SmallBasic.Tests /p:Configuration=${{matrix.configuration}}
25 |
--------------------------------------------------------------------------------
/.github/workflows/master_smallbasic-publicwebsite-code.yml:
--------------------------------------------------------------------------------
1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
2 | # More GitHub Actions for Azure: https://github.com/Azure/actions
3 |
4 | name: Build and deploy to Caseysc`s Azure Web App - smallbasic-publicwebsite-code
5 |
6 | on:
7 | push:
8 | branches:
9 | - master
10 | workflow_dispatch:
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v2
17 | - uses: actions/setup-node@v1
18 | with:
19 | node-version: 16.11.1
20 | - uses: actions/setup-dotnet@v1.7.2
21 | with:
22 | dotnet-version: 2.1.816
23 | - run: yarn --ci
24 | working-directory: ./Source/SmallBasic.Client
25 | - run: dotnet restore
26 | - run: dotnet build ./SmallBasic.sln /p:TreatWarningsAsErrors=True /p:Configuration=Release
27 | - run: dotnet publish ./Source/SmallBasic.Editor/SmallBasic.Editor.csproj --no-build /p:TreatWarningsAsErrors=True /p:Configuration=Release
28 | - uses: actions/upload-artifact@v3.1.0
29 | with:
30 | path: /home/runner/work/smallbasic-editor/smallbasic-editor/Source/SmallBasic.Editor/bin/Release/netstandard2.0/publish/
31 | if-no-files-found: error
32 |
33 | deploy:
34 | runs-on: windows-latest
35 | needs: build
36 | environment:
37 | name: 'Production'
38 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
39 |
40 | steps:
41 | - name: Download artifact from build job
42 | uses: actions/download-artifact@v2
43 | with:
44 | name: artifact
45 |
46 | - name: Deploy to Azure Web App
47 | id: deploy-to-webapp
48 | uses: azure/webapps-deploy@v2
49 | with:
50 | app-name: 'smallbasic-publicwebsite-code'
51 | slot-name: 'Production'
52 | publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_CC78D407C64043A1978FBF8A5FEDA312 }}
53 | package: .
54 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # VS files
2 | .vs/
3 | *.csproj.user
4 |
5 | # Output files
6 | bin
7 | obj
8 | node_modules
9 | wwwroot
10 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [
7 | ]
8 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dotnet-test-explorer.testProjectPath": "./Source/Tests"
3 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | ]
5 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SmallBasic
2 |
3 | [](https://github.com/sb/smallbasic-editor/actions/workflows/ci.yaml)
4 |
5 | This is home to the new SmallBasic editor. It has the following projects:
6 | * **SmallBasic.Analyzers**: a set of C# analyzers to help maintain the quality of the codebase.
7 | * **SmallBasic.Client**: a webpack project to bundle client typescript, sass, and image resources.
8 | * **SmallBasic.Compiler**: the compiler/main engine used to run programs.
9 | * **SmallBasic.Editor**: a blazor application that renders editor UI components.
10 | * **SmallBasic.Generators**: a collection of scripts to automatically generate thousands of C#/typescript lines used throughout the codebase.
11 | * **SmallBasic.Server**: an ASP server used to serve/deploy the editor.
12 | * **SmallBasic.Tests**: C# unit tests to test the compiler/engine.
13 | * **SmallBasic.Utilities**: helper utilities shared between different projects.
14 |
15 | #### Developer Workflow
16 |
17 | 1. Open **SmallBasic.sln** in Visual Studio 2017.
18 | 2. Choose **SmallBasic.Editor** and press F5 to run in the browser. This will also listen to C# changes and recompile when needed.
19 | 3. If you're editing **SmallBasic.Client** typescript files, you have to recompile that project, or run `dotnet build Source/SmallBasic.Client /p:Watch=True` from a command line to also listen/recompile these changes.
20 | 4. If changing any auto-generated files, rebuild **SmallBasic.Generators** to regenerate the files.
21 |
22 | NOTE: [this issue](https://github.com/sb/smallbasic-editor/issues/2) is currently tracking improving this workflow.
23 |
24 | ### Contributing to this project
25 |
26 | Please open an issue or comment on an existing one before you start working on a change, to make sure the effort is not duplicated/merged appropriately.
27 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Analyzers/DoNotUseAsserts.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Analyzers
6 | {
7 | using System;
8 | using System.Collections.Immutable;
9 | using System.Composition;
10 | using System.Linq;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 | using Microsoft.CodeAnalysis;
14 | using Microsoft.CodeAnalysis.CodeActions;
15 | using Microsoft.CodeAnalysis.CodeFixes;
16 | using Microsoft.CodeAnalysis.CSharp;
17 | using Microsoft.CodeAnalysis.CSharp.Syntax;
18 | using Microsoft.CodeAnalysis.Diagnostics;
19 | using Microsoft.CodeAnalysis.Text;
20 |
21 | [DiagnosticAnalyzer(LanguageNames.CSharp)]
22 | public class DoNotUseAssertsAnalyzer : DiagnosticAnalyzer
23 | {
24 | public const string Title = "Do not use Assert()";
25 | public const string MessageFormat = "Use 'Should()' extensions instead of 'Assert()' ones.";
26 | public const string Category = "SmallBasic.Analyzers";
27 |
28 | public const string DiagnosticId = "SB1008";
29 |
30 | private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true);
31 |
32 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
33 |
34 | public override void Initialize(AnalysisContext context)
35 | {
36 | context.RegisterSyntaxNodeAction(AnalyzeInvocationExpression, SyntaxKind.InvocationExpression);
37 | }
38 |
39 | private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
40 | {
41 | var invocation = (InvocationExpressionSyntax)context.Node;
42 | if (invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
43 | memberAccess.Expression is IdentifierNameSyntax identifier &&
44 | identifier.Identifier.Text == "Assert")
45 | {
46 | context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation()));
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Analyzers/SmallBasic.Analyzers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Bridge/NetworkBridge.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Bridge
6 | {
7 | using System;
8 | using System.Drawing;
9 | using System.IO;
10 | using System.Net;
11 | using SmallBasic.Utilities.Bridge;
12 |
13 | internal class NetworkBridge : INetworkBridge
14 | {
15 | public ImageListBridgeModels.ImageData LoadImage(string fileNameOrUrl)
16 | {
17 | if (new Uri(fileNameOrUrl).IsFile)
18 | {
19 | return CreateImage(() => File.ReadAllBytes(fileNameOrUrl));
20 | }
21 | else
22 | {
23 | using (var client = new WebClient())
24 | {
25 | return CreateImage(() => client.DownloadData(fileNameOrUrl));
26 | }
27 | }
28 | }
29 |
30 | public string DownloadFile(string url)
31 | {
32 | try
33 | {
34 | using (var client = new WebClient())
35 | {
36 | string path = Path.GetTempFileName();
37 | File.WriteAllText(path, client.DownloadString(url));
38 | return path;
39 | }
40 | }
41 | catch
42 | {
43 | return string.Empty;
44 | }
45 | }
46 |
47 | public string GetWebPageContents(string url)
48 | {
49 | try
50 | {
51 | using (var client = new WebClient())
52 | {
53 | return client.DownloadString(url);
54 | }
55 | }
56 | catch
57 | {
58 | return string.Empty;
59 | }
60 | }
61 |
62 | private static ImageListBridgeModels.ImageData CreateImage(Func factory)
63 | {
64 | try
65 | {
66 | byte[] bytes = factory();
67 | using (var stream = new MemoryStream(bytes))
68 | {
69 | using (var image = new Bitmap(Image.FromStream(stream)))
70 | {
71 | string base64Contents = Convert.ToBase64String(bytes, Base64FormattingOptions.None);
72 | return new ImageListBridgeModels.ImageData(image.Width, image.Height, base64Contents);
73 | }
74 | }
75 | }
76 | catch
77 | {
78 | return new ImageListBridgeModels.ImageData(width: 0, height: 0, base64Contents: string.Empty);
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Bridge/ProcessBridge.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Bridge
6 | {
7 | using System.Diagnostics;
8 |
9 | internal class ProcessBridge : IProcessBridge
10 | {
11 | public void OpenExternalLink(string url)
12 | {
13 | Process.Start(url);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Bridge/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Bridge
6 | {
7 | public static class Program
8 | {
9 | public static void Main(string[] args)
10 | {
11 | BridgeExecution.Run(args);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Bridge/SmallBasic.Bridge.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 | Exe
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Entries/Electron.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | import { app, BrowserWindow } from "electron";
6 |
7 | let window: BrowserWindow | null = null;
8 |
9 | function createWindow(): void {
10 | window = new BrowserWindow({
11 | width: 1200,
12 | height: 1100
13 | });
14 |
15 | // window.setMenu(null);
16 | window.loadFile("index.html");
17 |
18 | window.on("closed", () => {
19 | window = null;
20 | });
21 | }
22 |
23 | app.on("ready", createWindow);
24 |
25 | app.on("window-all-closed", () => {
26 | if (process.platform !== "darwin") {
27 | app.quit();
28 | }
29 | });
30 |
31 | app.on("activate", () => {
32 | if (window === null) {
33 | createWindow();
34 | }
35 | });
36 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Entries/Renderer.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | import "../Bridge/Bridge.Generated";
6 | import "./Web";
7 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Entries/Styles.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | @mixin set-background-image($relative-path, $width, $height) {
6 | width: $width;
7 | height: $height;
8 | background-size: cover;
9 | background-image: url("../Images/" + $relative-path);
10 | }
11 |
12 | $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
13 | @import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
14 | @import "@fortawesome/fontawesome-free/scss/solid.scss";
15 |
16 | @import "../../SmallBasic.Editor/Components/**/*.scss";
17 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Entries/Web.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | import "typeface-roboto";
6 |
7 | import "./Styles";
8 |
9 | import "../Utility/GraphicsDisplay";
10 | import "../Utility/SetupAppInsights";
11 | import "../Utility/SetupMonacoEnvironment";
12 | import "../Interop/JSInterop.Generated";
13 | import "../Interop/CSInterop.Generated";
14 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Back.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Continue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Copy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/New.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/NextLine.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Paste.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Pause.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Redo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Run.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Save.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Actions/Undo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/Caret.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/EditPage/Error.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/MemoryExplorer/CallStack.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/MemoryExplorer/MemoryExplorer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/MemoryExplorer/ProgramEnded.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/MemoryExplorer/Variables.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sb/smallbasic-editor/05fc82b7197d35d883118c85f19bd8cf51931615/Source/SmallBasic.Client/Images/favicon.ico
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Interop/CSInterop.Generated.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | ///
6 | /// This file is auto-generated by a build task. It shouldn't be edited by hand.
7 | ///
8 |
9 | ///
10 |
11 | export module CSIntrop {
12 | export module Monaco {
13 | export function updateDiagnostics(code: string): Promise {
14 | return DotNet.invokeMethodAsync("SmallBasic.Editor", "CSIntrop.Monaco.UpdateDiagnostics", code);
15 | }
16 |
17 | export function provideCompletionItems(code: string, position: monaco.IPosition): Promise {
18 | return DotNet.invokeMethodAsync("SmallBasic.Editor", "CSIntrop.Monaco.ProvideCompletionItems", code, position);
19 | }
20 |
21 | export function provideHover(code: string, position: monaco.IPosition): Promise {
22 | return DotNet.invokeMethodAsync("SmallBasic.Editor", "CSIntrop.Monaco.ProvideHover", code, position);
23 | }
24 | }
25 |
26 | export module GraphicsDisplay {
27 | export function updateDisplayLocation(x: number, y: number): Promise {
28 | return DotNet.invokeMethodAsync("SmallBasic.Editor", "CSIntrop.GraphicsDisplay.UpdateDisplayLocation", x, y).then(() => {
29 | Promise.resolve();
30 | });
31 | }
32 |
33 | export function onKeyUp(key: string): Promise {
34 | return DotNet.invokeMethodAsync("SmallBasic.Editor", "CSIntrop.GraphicsDisplay.OnKeyUp", key).then(() => {
35 | Promise.resolve();
36 | });
37 | }
38 |
39 | export function onKeyDown(key: string): Promise {
40 | return DotNet.invokeMethodAsync("SmallBasic.Editor", "CSIntrop.GraphicsDisplay.OnKeyDown", key).then(() => {
41 | Promise.resolve();
42 | });
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Interop/LayoutInterop.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | import { ILayoutInterop } from "./JSInterop.Generated";
6 |
7 | export class LayoutInterop implements ILayoutInterop {
8 | public async initializeWebView(locale: string, title: string): Promise {
9 | document.documentElement.setAttribute("lang", locale);
10 | document.title = title;
11 | }
12 |
13 | public async openExternalLink(url: string): Promise {
14 | window.open(url, "_blank");
15 | }
16 |
17 | public async getElementHeight(element: HTMLElement | null): Promise {
18 | if (element) {
19 | return element.getBoundingClientRect().height;
20 | }
21 | return 0;
22 | }
23 |
24 | public async getElementWidth(element: HTMLElement | null): Promise {
25 | if (element) {
26 | return element.getBoundingClientRect().width;
27 | }
28 | return 0;
29 | }
30 |
31 | public async scrollIntoView(element: HTMLElement | null): Promise {
32 | if (element) {
33 | element.scrollIntoView();
34 | }
35 | }
36 |
37 | public async focus(element: HTMLElement | null): Promise {
38 | if (element) {
39 | element.focus();
40 | }
41 | }
42 |
43 | public async showMessage(text: string, title: string): Promise {
44 | // second parameter will do nothing in web, but will display the title in electron
45 | (alert)(text, title);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/SmallBasic.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | $(RootDirectory)\Source\SmallBasic.Editor\wwwroot
6 |
7 |
8 |
9 | 3.0
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Utility/GraphicsDisplay.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | import * as $ from "jquery";
6 | import { CSIntrop } from "../Interop/CSInterop.Generated";
7 |
8 | let lastUpdatedX = 0;
9 | let lastUpdatedY = 0;
10 |
11 | $(window).resize(() => {
12 | const display = getGraphicsDisplay();
13 | if (display === null) {
14 | return;
15 | }
16 |
17 | const rect = display.getBoundingClientRect();
18 | if (rect.left !== lastUpdatedX || rect.top !== lastUpdatedY) {
19 | lastUpdatedX = rect.left;
20 | lastUpdatedY = rect.top;
21 | CSIntrop.GraphicsDisplay.updateDisplayLocation(lastUpdatedX, lastUpdatedY);
22 | }
23 | });
24 |
25 | const CHECK_INTERVAL = 250;
26 |
27 | setInterval(() => {
28 | const display = getGraphicsDisplay();
29 | if (display === null) {
30 | return;
31 | }
32 |
33 | const stamp = "x-display-key-events-done";
34 | if (display.hasAttribute(stamp)) {
35 | return;
36 | }
37 |
38 | $(display).keyup(e => {
39 | CSIntrop.GraphicsDisplay.onKeyUp(e.key);
40 | }).keydown(e => {
41 | CSIntrop.GraphicsDisplay.onKeyDown(e.key);
42 | });
43 |
44 | display.setAttribute(stamp, "true");
45 | }, CHECK_INTERVAL);
46 |
47 | function getGraphicsDisplay(): Element | null {
48 | return document.getElementsByTagName("graphics-display").item(0);
49 | }
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Utility/SetupAppInsights.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | import { AppInsights } from "applicationinsights-js";
6 |
7 | AppInsights.downloadAndSetup!({
8 | instrumentationKey: "4558db03-9e28-4a5a-9212-8a76bd8f6d1a"
9 | });
10 |
11 | AppInsights.trackPageView("PageLoad", window.location.toString());
12 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/Utility/SetupMonacoEnvironment.ts:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | /// Do not actually import in TypeScript. This is bundled by webpack separately:
6 | ///
7 |
8 | import { CSIntrop } from "../Interop/CSInterop.Generated";
9 |
10 | (window).MonacoEnvironment = {
11 | getWorkerUrl: function (): string {
12 | return "./monaco/editor.worker.js";
13 | }
14 | };
15 |
16 | function createRange(start: string, stop: string): string[] {
17 | const result: string[] = [];
18 | for (let idx = start.charCodeAt(0), end = stop.charCodeAt(0); idx <= end; ++idx) {
19 | result.push(String.fromCharCode(idx));
20 | }
21 | return result;
22 | }
23 |
24 | monaco.languages.registerCompletionItemProvider("sb", {
25 | triggerCharacters: [
26 | ".",
27 | ...createRange("a", "z"),
28 | ...createRange("A", "Z")
29 | ],
30 | provideCompletionItems: (model: monaco.editor.IReadOnlyModel, position: monaco.IPosition): monaco.Thenable => {
31 | return CSIntrop.Monaco.provideCompletionItems(model.getValue(), position);
32 | }
33 | });
34 |
35 | monaco.languages.registerHoverProvider("sb", {
36 | provideHover: (model: monaco.editor.IReadOnlyModel, position: monaco.IPosition): monaco.Thenable => {
37 | return CSIntrop.Monaco.provideHover(model.getValue(), position).then(lines => {
38 | return {
39 | range: null,
40 | contents: lines.map(line => {
41 | return {
42 | language: null,
43 | value: line
44 | };
45 | })
46 | };
47 | });
48 | }
49 | });
50 |
51 | monaco.languages.setLanguageConfiguration("sb", {
52 | indentationRules: {
53 | increaseIndentPattern: /^\s*(If|ElseIf|Else|While|For|Sub)/i,
54 | decreaseIndentPattern: /(ElseIf|Else|EndIf|EndWhile|EndFor|EndSub)\s*$/i
55 | }
56 | });
57 |
58 | // Reference: https://github.com/Microsoft/monaco-editor/blob/master/test/playground.generated/customizing-the-appearence-exposed-colors.html
59 | monaco.editor.defineTheme("small-basic", {
60 | base: "vs",
61 | inherit: true,
62 | rules: [],
63 | colors: {
64 | "editorWidget.background": "#E7E8EA",
65 | "editorWidget.border": "#656A72"
66 | }
67 | });
68 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "main": "SmallBasic.Electron.js",
4 | "devDependencies": {
5 | "@dotnet/jsinterop": "0.1.1",
6 | "@fortawesome/fontawesome-free": "5.15.4",
7 | "@timkendrick/monaco-editor": "0.0.9",
8 | "@types/applicationinsights-js": "1.0.9",
9 | "@types/copy-webpack-plugin": "8.0.1",
10 | "@types/element-resize-event": "2.0.0",
11 | "@types/file-saver": "2.0.0",
12 | "@types/html-webpack-plugin": "3.2.6",
13 | "@types/jquery": "3.5.0",
14 | "@types/mini-css-extract-plugin": "2.4.0",
15 | "@types/webpack": "5.28.0",
16 | "applicationinsights-js": "1.0.20",
17 | "autoprefixer": "9.3.1",
18 | "base64-inline-loader": "2.0.1",
19 | "copy-webpack-plugin": "9.0.1",
20 | "css-loader": "1.0.1",
21 | "element-resize-event": "3.0.3",
22 | "file-loader": "2.0.0",
23 | "file-saver": "2.0.0",
24 | "html-webpack-plugin": "5.4.0",
25 | "import-glob-loader": "1.1.0",
26 | "jquery": "3.5.0",
27 | "mini-css-extract-plugin": "2.4.2",
28 | "monaco-editor": "0.10.1",
29 | "popper.js": "1.14.4",
30 | "postcss-loader": "3.0.0",
31 | "precss": "3.1.2",
32 | "sass": "1.43.2",
33 | "sass-loader": "12.2.0",
34 | "source-map-loader": "0.2.4",
35 | "ts-loader": "9.2.6",
36 | "ts-node": "7.0.1",
37 | "tslint": "5.11.0",
38 | "tslint-loader": "3.6.0",
39 | "typeface-roboto": "0.0.54",
40 | "typescript": "4.4.4",
41 | "webpack": "5.58.2",
42 | "webpack-cli": "4.9.0"
43 | },
44 | "dependencies": {
45 | "dotnet-2.0.0": "1.4.4",
46 | "electron": "15.2.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "pretty": true,
4 | "diagnostics": true,
5 | "noEmitOnError": true,
6 |
7 | "strict": true,
8 | "allowJs": false,
9 | "alwaysStrict": true,
10 | "noImplicitAny": true,
11 | "noImplicitThis": true,
12 | "noUnusedLocals": true,
13 | "strictNullChecks": true,
14 | "noImplicitReturns": true,
15 | "noUnusedParameters": true,
16 | "allowUnusedLabels": false,
17 | "allowUnreachableCode": false,
18 | "noFallthroughCasesInSwitch": true,
19 |
20 | "target": "es5",
21 | "lib": [ "es6", "dom" ],
22 | "module": "commonjs",
23 | "moduleResolution": "node",
24 |
25 | "sourceMap": true,
26 | "inlineSourceMap": false,
27 | "inlineSources": false
28 | },
29 | "exclude": [
30 | "**/node_modules/**"
31 | ]
32 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Client/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-consecutive-blank-lines": true,
4 | "eofline": true,
5 | "no-var-keyword": true,
6 | "triple-equals": true,
7 | "typedef": [
8 | true,
9 | "call-signature",
10 | "parameter",
11 | "property-declaration",
12 | "member-variable-declaration",
13 | "object-destructuring",
14 | "array-destructuring"
15 | ],
16 | "member-access": [
17 | true,
18 | "check-constructor",
19 | "check-accessor"
20 | ],
21 | "semicolon": [
22 | true,
23 | "always"
24 | ],
25 | "quotemark": [
26 | true,
27 | "double"
28 | ],
29 | "indent": [
30 | true,
31 | "spaces",
32 | 4
33 | ],
34 | "trailing-comma": [
35 | true,
36 | {
37 | "multiline": "never",
38 | "singleline": "never"
39 | }
40 | ],
41 | "file-header": [
42 | true,
43 | "Licensed under the MIT License\\. See LICENSE file in the project root for license information\\.",
44 | "Licensed under the MIT License. See LICENSE file in the project root for license information."
45 | ]
46 | }
47 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Binding/BaseBoundNode.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Binding
6 | {
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using SmallBasic.Utilities;
10 |
11 | internal abstract class BaseBoundNode
12 | {
13 | private BaseBoundNode parent;
14 |
15 | public BaseBoundNode Parent
16 | {
17 | get => this.parent;
18 | set
19 | {
20 | Debug.Assert(this.parent.IsDefault(), "Parent node is already set.");
21 | this.parent = value;
22 | }
23 | }
24 |
25 | public abstract IEnumerable Children { get; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Binding/Visitors/GoToUndefinedLabelChecker.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Binding
6 | {
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using SmallBasic.Compiler.Diagnostics;
10 |
11 | internal sealed class GoToUndefinedLabelChecker : BaseBoundNodeVisitor
12 | {
13 | private readonly DiagnosticBag diagnostics;
14 | private readonly IReadOnlyCollection labels = new HashSet();
15 |
16 | public GoToUndefinedLabelChecker(DiagnosticBag diagnostics, IReadOnlyCollection labels, BoundStatementBlock module)
17 | {
18 | this.diagnostics = diagnostics;
19 | this.labels = labels;
20 | this.Visit(module);
21 | }
22 |
23 | private protected override void VisitGoToStatement(BoundGoToStatement node)
24 | {
25 | if (!this.labels.Contains(node.Label))
26 | {
27 | this.diagnostics.ReportGoToUndefinedLabel(node.Syntax.LabelToken.Range, node.Label);
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Binding/Visitors/LabelDefinitionsCollector.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Binding
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Compiler.Diagnostics;
9 | using SmallBasic.Compiler.Parsing;
10 | using SmallBasic.Utilities;
11 |
12 | internal sealed class LabelDefinitionsCollector : BaseBoundNodeVisitor
13 | {
14 | private readonly DiagnosticBag diagnostics;
15 | private readonly HashSet labels = new HashSet();
16 |
17 | public LabelDefinitionsCollector(DiagnosticBag diagnostics, BoundStatementBlock module)
18 | {
19 | this.diagnostics = diagnostics;
20 | this.Visit(module);
21 | }
22 |
23 | public IReadOnlyCollection Labels => this.labels;
24 |
25 | private protected override void VisitLabelStatement(BoundLabelStatement node)
26 | {
27 | if (!this.labels.Add(node.Label))
28 | {
29 | this.diagnostics.ReportTwoLabelsWithTheSameName(node.Syntax.LabelToken.Range, node.Label);
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Binding/Visitors/RuntimeAnalysis.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Binding
6 | {
7 | using System.Diagnostics;
8 | using System.Linq;
9 | using SmallBasic.Compiler.Runtime;
10 |
11 | public sealed class RuntimeAnalysis : BaseBoundNodeVisitor
12 | {
13 | internal RuntimeAnalysis(SmallBasicCompilation compilation)
14 | {
15 | Debug.Assert(!compilation.Diagnostics.Any(), "Cannot analyze a compilation with errors.");
16 | this.Compilation = compilation;
17 |
18 | this.Visit(this.Compilation.MainModule);
19 | foreach (var subModule in this.Compilation.SubModules.Values)
20 | {
21 | this.Visit(subModule);
22 | }
23 |
24 | if (!this.UsesGraphicsWindow)
25 | {
26 | this.UsesTextWindow = true;
27 | }
28 | }
29 |
30 | public SmallBasicCompilation Compilation { get; private set; }
31 |
32 | public bool UsesTextWindow { get; private set; }
33 |
34 | public bool UsesGraphicsWindow { get; private set; }
35 |
36 | public bool ListensToEvents { get; private set; }
37 |
38 | private protected override void VisitLibraryTypeExpression(BoundLibraryTypeExpression node)
39 | {
40 | base.VisitLibraryTypeExpression(node);
41 |
42 | var library = Libraries.Types[node.Name];
43 | this.UsesTextWindow |= library.UsesTextWindow;
44 | this.UsesGraphicsWindow |= library.UsesGraphicsWindow;
45 | }
46 |
47 | private protected override void VisitEventAssignmentStatement(BoundEventAssignmentStatement node)
48 | {
49 | base.VisitEventAssignmentStatement(node);
50 |
51 | this.ListensToEvents = true;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Binding/Visitors/VariablesAndSubModulesCollector.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Binding
6 | {
7 | using System.Collections.Generic;
8 |
9 | internal sealed class VariablesAndSubModulesCollector : BaseBoundNodeVisitor
10 | {
11 | private readonly HashSet names = new HashSet();
12 |
13 | public VariablesAndSubModulesCollector(Binder binder)
14 | {
15 | this.Visit(binder.MainModule);
16 | foreach (var subModule in binder.SubModules.Values)
17 | {
18 | this.Visit(subModule);
19 | }
20 | }
21 |
22 | public IReadOnlyCollection Names => this.names;
23 |
24 | private protected override void VisitArrayAssignmentStatement(BoundArrayAssignmentStatement node)
25 | {
26 | this.names.Add(node.Array.Name);
27 | base.VisitArrayAssignmentStatement(node);
28 | }
29 |
30 | private protected override void VisitVariableAssignmentStatement(BoundVariableAssignmentStatement node)
31 | {
32 | this.names.Add(node.Variable.Name);
33 | base.VisitVariableAssignmentStatement(node);
34 | }
35 |
36 | private protected override void VisitSubModule(BoundSubModule node)
37 | {
38 | this.names.Add(node.Name);
39 | base.VisitSubModule(node);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Diagnostics/Diagnostic.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Diagnostics
6 | {
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using System.Globalization;
10 | using SmallBasic.Compiler.Scanning;
11 |
12 | [DebuggerDisplay("{ToDisplayString()}")]
13 | public sealed class Diagnostic
14 | {
15 | private string[] args;
16 |
17 | public Diagnostic(DiagnosticCode code, TextRange range, params string[] args)
18 | {
19 | this.Code = code;
20 | this.Range = range;
21 | this.args = args;
22 | }
23 |
24 | public DiagnosticCode Code { get; private set; }
25 |
26 | public TextRange Range { get; private set; }
27 |
28 | public IReadOnlyList Args => this.args;
29 |
30 | public string ToDisplayString() => string.Format(CultureInfo.CurrentCulture, this.Code.ToDisplayString(), this.args);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Parsing/BaseSyntaxNode.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Parsing
6 | {
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using SmallBasic.Compiler.Scanning;
10 | using SmallBasic.Utilities;
11 |
12 | internal abstract class BaseSyntaxNode
13 | {
14 | private BaseSyntaxNode parent;
15 |
16 | public BaseSyntaxNode Parent
17 | {
18 | get => this.parent;
19 | set
20 | {
21 | Debug.Assert(this.parent.IsDefault(), "Parent node is already set.");
22 | this.parent = value;
23 | }
24 | }
25 |
26 | public abstract IEnumerable Children { get; }
27 |
28 | public abstract TextRange Range { get; }
29 |
30 | public BaseSyntaxNode FindNodeAt(TextPosition position)
31 | {
32 | if (!this.Range.Contains(position))
33 | {
34 | return null;
35 | }
36 |
37 | foreach (var child in this.Children)
38 | {
39 | var result = child.FindNodeAt(position);
40 | if (!result.IsDefault())
41 | {
42 | return result;
43 | }
44 | }
45 |
46 | return this;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Parsing/Visitors/SubModuleNamesCollector.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Parsing
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Compiler.Diagnostics;
9 |
10 | internal sealed class SubModuleNamesCollector : BaseSyntaxNodeVisitor
11 | {
12 | private readonly HashSet names = new HashSet();
13 |
14 | public SubModuleNamesCollector(StatementBlockSyntax syntaxTree)
15 | {
16 | this.Visit(syntaxTree);
17 | }
18 |
19 | public IReadOnlyCollection Names => this.names;
20 |
21 | private protected override void VisitSubModuleStatement(SubModuleStatementSyntax node)
22 | {
23 | this.names.Add(node.NameToken.Text);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/DebuggerSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using System.Collections.Generic;
8 |
9 | public sealed class DebuggerSnapshot
10 | {
11 | internal DebuggerSnapshot(int currentSourceLine, IReadOnlyCollection executionStack, IReadOnlyDictionary memory)
12 | {
13 | this.CurrentSourceLine = currentSourceLine;
14 | this.ExecutionStack = executionStack;
15 | this.Memory = memory;
16 | }
17 |
18 | public int CurrentSourceLine { get; set; }
19 |
20 | public IReadOnlyCollection ExecutionStack { get; private set; }
21 |
22 | public IReadOnlyDictionary Memory { get; private set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/Frame.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using System.Diagnostics;
8 |
9 | public sealed class Frame
10 | {
11 | private int index = 0;
12 |
13 | internal Frame(RuntimeModule module)
14 | {
15 | this.Module = module;
16 | }
17 |
18 | public RuntimeModule Module { get; private set; }
19 |
20 | public int InstructionIndex
21 | {
22 | get
23 | {
24 | return this.index;
25 | }
26 |
27 | internal set
28 | {
29 | Debug.Assert(value >= 0 && value <= this.Module.Instructions.Count, "Value should be within the module length");
30 | this.index = value;
31 | }
32 | }
33 |
34 | public int CurrentSourceLine
35 | {
36 | get
37 | {
38 | if (this.index < this.Module.Instructions.Count)
39 | {
40 | return this.Module.Instructions[this.index].Range.Start.Line;
41 | }
42 | else
43 | {
44 | return this.Module.Syntax.Range.End.Line;
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/Instructions/ChangingStateInstructions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using SmallBasic.Compiler.Scanning;
8 |
9 | internal sealed class PauseInstruction : BaseNonJumpInstruction
10 | {
11 | public PauseInstruction(TextRange range)
12 | : base(range)
13 | {
14 | }
15 |
16 | protected override void Execute(SmallBasicEngine engine) => engine.Pause();
17 | }
18 |
19 | internal sealed class TerminateInstruction : BaseNonJumpInstruction
20 | {
21 | public TerminateInstruction(TextRange range)
22 | : base(range)
23 | {
24 | }
25 |
26 | protected override void Execute(SmallBasicEngine engine) => engine.Terminate();
27 | }
28 |
29 | internal sealed class BlockOnStringInputInstruction : BaseNonJumpInstruction
30 | {
31 | public BlockOnStringInputInstruction(TextRange range)
32 | : base(range)
33 | {
34 | }
35 |
36 | protected override void Execute(SmallBasicEngine engine) => engine.BlockOnStringInput();
37 | }
38 |
39 | internal sealed class BlockOnNumberInputInstruction : BaseNonJumpInstruction
40 | {
41 | public BlockOnNumberInputInstruction(TextRange range)
42 | : base(range)
43 | {
44 | }
45 |
46 | protected override void Execute(SmallBasicEngine engine) => engine.BlockOnNumberInput();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/RuntimeModule.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Compiler.Parsing;
9 |
10 | public sealed class RuntimeModule
11 | {
12 | internal RuntimeModule(string name, IReadOnlyList instructions, StatementBlockSyntax syntax)
13 | {
14 | this.Name = name;
15 | this.Instructions = instructions;
16 | this.Syntax = syntax;
17 | }
18 |
19 | public string Name { get; private set; }
20 |
21 | internal IReadOnlyList Instructions { get; private set; }
22 |
23 | internal StatementBlockSyntax Syntax { get; private set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/Values/BaseValue.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using System.Diagnostics;
8 |
9 | [DebuggerDisplay("{ToDisplayString()}")]
10 | public abstract class BaseValue
11 | {
12 | public abstract string ToDisplayString();
13 |
14 | public sealed override string ToString() => this.ToDisplayString();
15 |
16 | internal abstract bool ToBoolean();
17 |
18 | internal abstract decimal ToNumber();
19 |
20 | internal abstract ArrayValue ToArray();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/Values/BooleanValue.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | public sealed class BooleanValue : BaseValue
8 | {
9 | public BooleanValue(bool value)
10 | {
11 | this.Value = value;
12 | }
13 |
14 | public bool Value { get; private set; }
15 |
16 | public override string ToDisplayString() => this.Value ? "True" : "False";
17 |
18 | internal override bool ToBoolean() => this.Value;
19 |
20 | internal override decimal ToNumber() => 0;
21 |
22 | internal override ArrayValue ToArray() => new ArrayValue();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/Values/NumberValue.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using System.Globalization;
8 |
9 | public sealed class NumberValue : BaseValue
10 | {
11 | public NumberValue(decimal value)
12 | {
13 | this.Value = value;
14 | }
15 |
16 | public decimal Value { get; private set; }
17 |
18 | public override string ToDisplayString() => this.Value.ToString(CultureInfo.CurrentCulture);
19 |
20 | internal override bool ToBoolean() => false;
21 |
22 | internal override decimal ToNumber() => this.Value;
23 |
24 | internal override ArrayValue ToArray() => new ArrayValue();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Runtime/Values/StringValue.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Runtime
6 | {
7 | using System.Diagnostics;
8 | using System.Globalization;
9 | using SmallBasic.Utilities;
10 |
11 | public sealed class StringValue : BaseValue
12 | {
13 | /*
14 | * Note: We use a a number style slightly different from the default 'NumberStyles.Number'
15 | * because for parity with SBD, we don't allow thousands separators.
16 | */
17 | private const NumberStyles NumberStyle = NumberStyles.Integer | NumberStyles.AllowTrailingSign | NumberStyles.AllowDecimalPoint;
18 |
19 | private StringValue(string value)
20 | {
21 | Debug.Assert(!value.IsDefault(), "Value should never be null.");
22 | this.Value = value;
23 | }
24 |
25 | public string Value { get; private set; }
26 |
27 | internal static StringValue Empty => new StringValue(string.Empty);
28 |
29 | public static BaseValue Create(string value)
30 | {
31 | switch (value.Trim().ToLower(CultureInfo.CurrentCulture))
32 | {
33 | case "true":
34 | return new BooleanValue(true);
35 | case "false":
36 | return new BooleanValue(false);
37 | case string other when decimal.TryParse(other, NumberStyle, NumberFormatInfo.CurrentInfo, out decimal decimalResult):
38 | return new NumberValue(decimalResult);
39 | default:
40 | return new StringValue(value);
41 | }
42 | }
43 |
44 | public override string ToDisplayString() => this.Value;
45 |
46 | internal override bool ToBoolean() => false;
47 |
48 | internal override decimal ToNumber() => 0;
49 |
50 | internal override ArrayValue ToArray() => new ArrayValue();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Scanning/TextPosition.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Scanning
6 | {
7 | using System;
8 | using System.Diagnostics;
9 | using SmallBasic.Compiler.Services;
10 |
11 | [DebuggerDisplay("{ToDisplayString()}")]
12 | public readonly struct TextPosition : IEquatable
13 | {
14 | internal TextPosition(int line, int column)
15 | {
16 | this.Line = line;
17 | this.Column = column;
18 | }
19 |
20 | public int Line { get; }
21 |
22 | public int Column { get; }
23 |
24 | public static implicit operator TextPosition(in (int Line, int Column) tuple)
25 | {
26 | return new TextPosition(tuple.Line, tuple.Column);
27 | }
28 |
29 | public static bool operator ==(TextPosition left, TextPosition right) => left.Line == right.Line && left.Column == right.Column;
30 |
31 | public static bool operator !=(TextPosition left, TextPosition right) => !(left == right);
32 |
33 | public static bool operator <(TextPosition left, TextPosition right) => left.Line < right.Line || (left.Line == right.Line && left.Column < right.Column);
34 |
35 | public static bool operator >(TextPosition left, TextPosition right) => left.Line > right.Line || (left.Line == right.Line && left.Column > right.Column);
36 |
37 | public static bool operator <=(TextPosition left, TextPosition right) => left < right || left == right;
38 |
39 | public static bool operator >=(TextPosition left, TextPosition right) => left > right || left == right;
40 |
41 | public override bool Equals(object obj) => obj is TextPosition other && this == other;
42 |
43 | public override int GetHashCode() => this.Line ^ this.Column;
44 |
45 | public bool Equals(TextPosition other) => this == other;
46 |
47 | public string ToDisplayString() => $"({this.Line}, {this.Column})";
48 |
49 | public MonacoPosition ToMonacoPosition() => new MonacoPosition
50 | {
51 | lineNumber = this.Line + 1,
52 | column = this.Column + 1
53 | };
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Scanning/TextRange.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Scanning
6 | {
7 | using System;
8 | using System.Diagnostics;
9 | using SmallBasic.Compiler.Services;
10 |
11 | [DebuggerDisplay("{ToDisplayString()}")]
12 | public readonly struct TextRange : IEquatable
13 | {
14 | internal TextRange(TextPosition start, TextPosition end)
15 | {
16 | this.Start = start;
17 | this.End = end;
18 | }
19 |
20 | public TextPosition Start { get; }
21 |
22 | public TextPosition End { get; }
23 |
24 | public static implicit operator TextRange(in (TextPosition Start, TextPosition End) tuple)
25 | {
26 | return new TextRange(tuple.Start, tuple.End);
27 | }
28 |
29 | public static bool operator ==(TextRange left, TextRange right) => left.Start == right.Start && left.End == right.End;
30 |
31 | public static bool operator !=(TextRange left, TextRange right) => !(left == right);
32 |
33 | public override bool Equals(object obj) => obj is TextRange other && this == other;
34 |
35 | public override int GetHashCode() => this.Start.GetHashCode() ^ this.End.GetHashCode();
36 |
37 | public bool Equals(TextRange other) => this == other;
38 |
39 | public string ToDisplayString() => $"({this.Start.ToDisplayString()}, {this.End.ToDisplayString()})";
40 |
41 | public bool Contains(in TextPosition position) => this.Start <= position && position <= this.End;
42 |
43 | public MonacoRange ToMonacoRange() => new MonacoRange
44 | {
45 | startLineNumber = this.Start.Line + 1,
46 | startColumn = this.Start.Column + 1,
47 | endLineNumber = this.End.Line + 1,
48 | endColumn = this.End.Column + 2
49 | };
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/Scanning/Token.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler.Scanning
6 | {
7 | using System.Diagnostics;
8 |
9 | [DebuggerDisplay("{ToDisplayString()}")]
10 | internal sealed class Token
11 | {
12 | public Token(TokenKind kind, string text, TextRange range)
13 | {
14 | Debug.Assert(range.Start.Line == range.End.Line, "Tokens should never span multiple lines");
15 |
16 | this.Kind = kind;
17 | this.Text = text;
18 | this.Range = range;
19 | }
20 |
21 | public TokenKind Kind { get; private set; }
22 |
23 | public string Text { get; private set; }
24 |
25 | public TextRange Range { get; private set; }
26 |
27 | public string ToDisplayString() => $"{nameof(TokenKind)}.{this.Kind}: '{this.Text}' at {this.Range.ToDisplayString()}";
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/SmallBasic.Compiler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Compiler/SmallBasicCompilation.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Compiler
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using SmallBasic.Compiler.Binding;
11 | using SmallBasic.Compiler.Diagnostics;
12 | using SmallBasic.Compiler.Parsing;
13 | using SmallBasic.Compiler.Scanning;
14 | using SmallBasic.Compiler.Services;
15 | using SmallBasic.Utilities;
16 |
17 | public sealed class SmallBasicCompilation
18 | {
19 | private readonly DiagnosticBag diagnostics;
20 | private readonly bool isRunningOnDesktop;
21 |
22 | private readonly Scanner scanner;
23 | private readonly Parser parser;
24 | private readonly Binder binder;
25 |
26 | private readonly Lazy lazyAnalysis;
27 |
28 | public SmallBasicCompilation(string text)
29 | #if IsBuildingForDesktop
30 | : this(text, isRunningOnDesktop: true)
31 | #else
32 | : this(text, isRunningOnDesktop: false)
33 | #endif
34 | {
35 | }
36 |
37 | public SmallBasicCompilation(string text, bool isRunningOnDesktop)
38 | {
39 | this.diagnostics = new DiagnosticBag();
40 | this.isRunningOnDesktop = isRunningOnDesktop;
41 |
42 | this.Text = text;
43 |
44 | this.scanner = new Scanner(this.Text, this.diagnostics);
45 | this.parser = new Parser(this.scanner.Tokens, this.diagnostics);
46 | this.binder = new Binder(this.parser.SyntaxTree, this.diagnostics, isRunningOnDesktop);
47 |
48 | this.lazyAnalysis = new Lazy(() => new RuntimeAnalysis(this));
49 | }
50 |
51 | public string Text { get; private set; }
52 |
53 | public RuntimeAnalysis Analysis => this.lazyAnalysis.Value;
54 |
55 | public IReadOnlyList Diagnostics => this.diagnostics.Contents;
56 |
57 | internal BoundStatementBlock MainModule => this.binder.MainModule;
58 |
59 | internal IReadOnlyDictionary SubModules => this.binder.SubModules;
60 |
61 | public MonacoCompletionItem[] ProvideCompletionItems(TextPosition position) => CompletionItemProvider.Provide(this.parser, this.binder, position);
62 |
63 | public string[] ProvideHover(TextPosition position) => HoverProvider.Provide(this.diagnostics, this.parser, position);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Display/EngineDisplay.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Display
6 | {
7 | using System.Collections.Generic;
8 | using Microsoft.AspNetCore.Blazor.Components;
9 | using SmallBasic.Editor.Components.Layout;
10 | using SmallBasic.Editor.Libraries.Utilities;
11 | using SmallBasic.Editor.Store;
12 |
13 | public sealed class EngineDisplay : SmallBasicComponent
14 | {
15 | [Parameter]
16 | private AsyncEngine Engine { get; set; }
17 |
18 | internal static void Inject(TreeComposer composer, AsyncEngine engine)
19 | {
20 | composer.Inject(new Dictionary
21 | {
22 | { nameof(EngineDisplay.Engine), engine }
23 | });
24 | }
25 |
26 | protected override void ComposeTree(TreeComposer composer)
27 | {
28 | composer.Element(
29 | name: "engine-display",
30 | attributes: new Dictionary
31 | {
32 | // Important to prevent the right-click menu
33 | { "oncontextmenu", "return false;" }
34 | },
35 | body: () =>
36 | {
37 | if (CompilationStore.Compilation.Analysis.UsesTextWindow)
38 | {
39 | TextDisplay.Inject(composer);
40 | }
41 |
42 | if (CompilationStore.Compilation.Analysis.UsesGraphicsWindow)
43 | {
44 | GraphicsDisplay.Inject(composer, this.Engine.Libraries);
45 | }
46 | });
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Display/EngineDisplay.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | engine-display {
6 | display: flex;
7 | flex-direction: row;
8 | justify-content: flex-start;
9 | align-items: stretch;
10 | align-content: stretch;
11 | height: 100%;
12 | width: 100%;
13 | }
14 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Display/GraphicsDisplay.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | graphics-display {
6 | flex: 1 0 50%;
7 | background-color: white;
8 | overflow-x: hidden;
9 | overflow-y: hidden;
10 | border: 1px solid #656A72;
11 | // Required to have "absolute" positioned children
12 | position: relative;
13 |
14 | title {
15 | display: block;
16 | padding: 4px 8px;
17 | background: #F3F3F3;
18 | border-bottom: 1px solid #656A72;
19 | font-family: Roboto, sans-serif;
20 | font-size: 16px;
21 | }
22 |
23 | svg {
24 | // Needs to have a "relative" parent
25 | position: absolute;
26 | }
27 |
28 | button {
29 | // Needs to have a "relative" parent
30 | position: absolute;
31 | font-family: Consolas, monospace, Hack;
32 | font-size: 14px;
33 | }
34 |
35 | input {
36 | // Needs to have a "relative" parent
37 | position: absolute;
38 | font-family: Consolas, monospace, Hack;
39 | font-size: 14px;
40 | }
41 |
42 | textarea {
43 | // Needs to have a "relative" parent
44 | position: absolute;
45 | font-family: Consolas, monospace, Hack;
46 | font-size: 14px;
47 | resize: none;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Display/TextDisplay.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | text-display {
6 | flex: 1 0 50%;
7 | padding: 5px;
8 | box-sizing: border-box;
9 | overflow-x: hidden;
10 | overflow-y: auto;
11 | word-break: break-all;
12 | font-size: 18px;
13 | font-family: Consolas, monospace, Hack;
14 | border: 1px solid #656A72;
15 | white-space: pre;
16 |
17 | title {
18 | display: block;
19 | margin: -5px -5px 5px -5px;
20 | padding: 4px 8px;
21 | background: #F3F3F3;
22 | border-bottom: 1px solid #656A72;
23 | font-family: Roboto, sans-serif;
24 | font-size: 16px;
25 | }
26 |
27 | input-field {
28 | color: gray;
29 | display: inline;
30 |
31 | cursor {
32 | animation: blink 0.7s infinite;
33 | }
34 |
35 | @keyframes blink {
36 | 0% {
37 | opacity: 0;
38 | }
39 |
40 | 100% {
41 | opacity: 1;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Layout/App.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Layout
6 | {
7 | using System.Collections.Generic;
8 | using Microsoft.AspNetCore.Blazor.Components;
9 | using Microsoft.AspNetCore.Blazor.Routing;
10 |
11 | // Configuring this here is temporary. Later we'll move the app config
12 | // into Program.cs, and it won't be necessary to specify AppAssembly.
13 | public sealed class App : SmallBasicComponent
14 | {
15 | protected override void ComposeTree(TreeComposer composer)
16 | {
17 | composer.Inject(new Dictionary
18 | {
19 | { "AppAssembly", RuntimeHelpers.TypeCheck(typeof(App).Assembly) }
20 | });
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Layout/MainLayout.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | main-layout {
6 | display: flex;
7 | flex-direction: column;
8 | color: #232528;
9 | font-family: Roboto, sans-serif;
10 | height: 100%;
11 |
12 | $header-row-height: 100px;
13 | $actions-row-height: 98px;
14 |
15 | header-row {
16 | display: flex;
17 | flex-shrink: 0;
18 | flex-direction: row;
19 | justify-content: space-between;
20 | align-items: center;
21 | height: $header-row-height;
22 | background: #F3F3F3;
23 |
24 | logo-area {
25 | display: flex;
26 | align-items: center;
27 |
28 | logo {
29 | @include set-background-image("logo.svg", 224px, 80px);
30 | margin-left: 40px;
31 | }
32 | }
33 |
34 | header-links {
35 | header-link {
36 | font-size: 20px;
37 | margin-right: 40px;
38 | cursor: pointer;
39 | }
40 | }
41 | }
42 |
43 | actions-row {
44 | height: $actions-row-height;
45 | flex-shrink: 0;
46 | }
47 |
48 | page-contents {
49 | height: calc(100% - #{$header-row-height} - #{$actions-row-height});
50 | min-height: 600px;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Layout/SmallBasicComponent.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Layout
6 | {
7 | using Microsoft.AspNetCore.Blazor.Components;
8 | using Microsoft.AspNetCore.Blazor.RenderTree;
9 |
10 | public abstract class SmallBasicComponent : BlazorComponent
11 | {
12 | protected abstract void ComposeTree(TreeComposer composer);
13 |
14 | protected override sealed void BuildRenderTree(RenderTreeBuilder builder)
15 | {
16 | base.BuildRenderTree(builder);
17 | this.ComposeTree(new TreeComposer(builder));
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Pages/Debug/DebugPage.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | debug-page {
6 | display: flex;
7 | flex-direction: row;
8 | justify-content: flex-start;
9 | align-items: stretch;
10 | height: 100%;
11 |
12 | main-space {
13 | width: 100%;
14 | height: 100%;
15 | display: flex;
16 | flex-direction: column;
17 | align-items: stretch;
18 | justify-content: flex-start;
19 | flex-grow: 1;
20 |
21 | editor-space {
22 | width: 100%;
23 | height: 300px;
24 | flex-grow: 1;
25 | display: flex;
26 | flex-direction: column;
27 | align-items: stretch;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Pages/Edit/EditPage.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | edit-page {
6 | display: flex;
7 | flex-direction: row;
8 | justify-content: flex-start;
9 | align-items: stretch;
10 | height: 100%;
11 |
12 | main-space {
13 | width: 100%;
14 | height: 100%;
15 | display: flex;
16 | flex-direction: column;
17 | align-items: stretch;
18 | justify-content: flex-start;
19 | flex-grow: 1;
20 |
21 | editor-space {
22 | width: 100%;
23 | flex-grow: 1;
24 | display: flex;
25 | flex-direction: column;
26 | align-items: stretch;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Pages/IndexPage.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Pages.Edit
6 | {
7 | using System;
8 | using Microsoft.AspNetCore.Blazor.Components;
9 | using Microsoft.AspNetCore.Blazor.Services;
10 | using SmallBasic.Editor.Components.Layout;
11 | using SmallBasic.Editor.Components.Pages.Debug;
12 | using SmallBasic.Editor.Components.Pages.Run;
13 | using SmallBasic.Editor.Store;
14 | using SmallBasic.Utilities;
15 |
16 | [Route("/")] // For browser entry
17 | [Route("/index.html")] // For electron entry
18 | public sealed class IndexPage : SmallBasicComponent, IDisposable
19 | {
20 | private IUriHelper UriHelper { get; set; }
21 |
22 | public void Dispose()
23 | {
24 | NavigationStore.PageChanged -= this.StateHasChanged;
25 | }
26 |
27 | protected override void OnInit()
28 | {
29 | NavigationStore.PageChanged += this.StateHasChanged;
30 | }
31 |
32 | protected override void ComposeTree(TreeComposer composer)
33 | {
34 | switch (NavigationStore.CurrentPage)
35 | {
36 | case NavigationStore.PageId.Edit:
37 | EditPage.Inject(composer);
38 | break;
39 | case NavigationStore.PageId.Run:
40 | RunPage.Inject(composer);
41 | break;
42 | case NavigationStore.PageId.Debug:
43 | DebugPage.Inject(composer);
44 | break;
45 | default:
46 | throw ExceptionUtilities.UnexpectedValue(NavigationStore.CurrentPage);
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Pages/Run/RunPage.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Pages.Run
6 | {
7 | using System;
8 | using System.Linq;
9 | using System.Threading.Tasks;
10 | using SmallBasic.Compiler;
11 | using SmallBasic.Editor.Components.Display;
12 | using SmallBasic.Editor.Components.Layout;
13 | using SmallBasic.Editor.Components.Toolbox;
14 | using SmallBasic.Editor.Libraries;
15 | using SmallBasic.Editor.Libraries.Utilities;
16 | using SmallBasic.Editor.Store;
17 | using SmallBasic.Utilities;
18 | using SmallBasic.Utilities.Resources;
19 |
20 | public sealed class RunPage : MainLayout, IDisposable
21 | {
22 | private readonly AsyncEngine engine = new AsyncEngine(isDebugging: false);
23 |
24 | private bool isInitialized;
25 |
26 | public static void Inject(TreeComposer composer)
27 | {
28 | composer.Inject();
29 | }
30 |
31 | public void Dispose()
32 | {
33 | this.engine.Dispose();
34 | }
35 |
36 | protected override void OnInit()
37 | {
38 | if (CompilationStore.Compilation.Diagnostics.Any())
39 | {
40 | NavigationStore.NagivateTo(NavigationStore.PageId.Edit);
41 | return;
42 | }
43 | }
44 |
45 | protected override void ComposeBody(TreeComposer composer)
46 | {
47 | composer.Element("run-page", body: () =>
48 | {
49 | EngineDisplay.Inject(composer, this.engine);
50 | });
51 | }
52 |
53 | protected override void ComposeLeftActions(TreeComposer composer)
54 | {
55 | Actions.Action(composer, "back", EditorResources.Actions_Back, () =>
56 | {
57 | NavigationStore.NagivateTo(NavigationStore.PageId.Edit);
58 | return Task.CompletedTask;
59 | });
60 | }
61 |
62 | protected override async Task OnAfterRenderAsync()
63 | {
64 | if (!this.isInitialized)
65 | {
66 | this.isInitialized = true;
67 | await Task.Run(() => this.engine.StartLoop()).ConfigureAwait(false);
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Pages/Run/RunPage.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | */
4 |
5 | run-page {
6 | display: flex;
7 | flex-direction: row;
8 | justify-content: flex-start;
9 | align-items: stretch;
10 | height: 100%;
11 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Toolbox/ActionsRow.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Toolbox
6 | {
7 | using System;
8 | using System.Threading.Tasks;
9 |
10 | internal static class Actions
11 | {
12 | public static void Row(TreeComposer composer, Action left = null, Action right = null)
13 | {
14 | composer.Element("actions-row", body: () =>
15 | {
16 | composer.Element("left-actions", body: left);
17 | composer.Element("right-actions", body: right);
18 | });
19 | }
20 |
21 | public static void Action(TreeComposer composer, string name, string title, Func onClick)
22 | {
23 | composer.Element(
24 | name: "action",
25 | events: new TreeComposer.Events
26 | {
27 | OnClickAsync = args => onClick()
28 | },
29 | body: () =>
30 | {
31 | composer.Element("icon-" + name);
32 | composer.Text(title);
33 | });
34 | }
35 |
36 | public static void DisabledAction(TreeComposer composer, string name, string title, string message)
37 | {
38 | composer.Element("disabled-action-container", body: () =>
39 | {
40 | composer.Element("action", body: () =>
41 | {
42 | composer.Element("icon-" + name);
43 | composer.Text(title);
44 | });
45 |
46 | composer.Element("disabled-message", body: () => composer.Text(message));
47 | });
48 | }
49 |
50 | public static void Separator(TreeComposer composer)
51 | {
52 | composer.Element("separator");
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Toolbox/Micro.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Toolbox
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 | using Microsoft.AspNetCore.Blazor;
11 |
12 | internal static class Micro
13 | {
14 | public static void FontAwesome(TreeComposer composer, string iconName)
15 | {
16 | composer.Element(name: "font-awesome-icon", attributes: new Dictionary
17 | {
18 | { "class", $"fas fa-{iconName}" }
19 | });
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Toolbox/MonacoEditor.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Components.Toolbox
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 | using Microsoft.AspNetCore.Blazor;
11 | using Microsoft.AspNetCore.Blazor.Components;
12 | using SmallBasic.Editor.Components.Layout;
13 | using SmallBasic.Editor.Interop;
14 | using SmallBasic.Editor.Store;
15 |
16 | public sealed class MonacoEditor : SmallBasicComponent, IDisposable
17 | {
18 | private ElementRef editorElement = default;
19 |
20 | [Parameter]
21 | private bool IsReadOnly { get; set; }
22 |
23 | public static void Inject(TreeComposer composer, bool isReadOnly)
24 | {
25 | composer.Inject(new Dictionary
26 | {
27 | { nameof(MonacoEditor.IsReadOnly), isReadOnly },
28 | });
29 | }
30 |
31 | public void Dispose()
32 | {
33 | JSInterop.Monaco.Dispose().ConfigureAwait(false);
34 | }
35 |
36 | protected override Task OnAfterRenderAsync()
37 | {
38 | return JSInterop.Monaco.Initialize(this.editorElement, CompilationStore.Compilation.Text, this.IsReadOnly);
39 | }
40 |
41 | protected override void ComposeTree(TreeComposer composer)
42 | {
43 | composer.Element("editor-container", body: () =>
44 | {
45 | composer.Element("editor", capture: element => this.editorElement = element);
46 | });
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Components/Toolbox/MonacoEditor.scss:
--------------------------------------------------------------------------------
1 | editor-container {
2 | padding-top: 20px;
3 | padding-bottom: 20px;
4 | box-sizing: border-box;
5 | flex-grow: 1;
6 | // absolute position is required to layout the editor correctly.
7 | // This container needs to not be attached to it's parent width,
8 | // So that its width can shrink/grow accourding to the page.
9 | position: absolute;
10 |
11 | editor {
12 |
13 | .monaco-editor-hover .monaco-tokenized-source {
14 | word-break: normal;
15 | }
16 |
17 | .wavy-line {
18 | display: inline-block;
19 | position: relative;
20 | background: url(data:image/gif;base64,R0lGODdhBAADAPEAANv///8AAP///wAAACwAAAAABAADAEACBZQjmIAFADs=) bottom repeat-x;
21 | }
22 |
23 | .error-line-glyph {
24 | margin-left: 14px;
25 | @include set-background-image("EditPage/Error.svg", 20px, 20px);
26 | }
27 |
28 | .debugger-line-highlight {
29 | background: #FEF849;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Interop/GraphicsDisplayInterop.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Interop
6 | {
7 | using System.Threading.Tasks;
8 | using SmallBasic.Editor.Store;
9 |
10 | public class GraphicsDisplayInterop : IGraphicsDisplayInterop
11 | {
12 | public Task UpdateDisplayLocation(decimal x, decimal y)
13 | {
14 | GraphicsDisplayStore.UpdateDisplayLocation(x, y);
15 | return Task.CompletedTask;
16 | }
17 |
18 | public Task OnKeyUp(string key)
19 | {
20 | GraphicsDisplayStore.NotifyKeyUp(key);
21 | return Task.CompletedTask;
22 | }
23 |
24 | public Task OnKeyDown(string key)
25 | {
26 | GraphicsDisplayStore.NotifyKeyDown(key);
27 | return Task.CompletedTask;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Interop/MonacoInterop.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Interop
6 | {
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using SmallBasic.Compiler.Services;
10 | using SmallBasic.Editor.Components;
11 | using SmallBasic.Editor.Store;
12 |
13 | public class MonacoInterop : IMonacoInterop
14 | {
15 | public Task UpdateDiagnostics(string code)
16 | {
17 | CompilationStore.NotifyCodeChanged(code);
18 | return Task.FromResult(CompilationStore.Compilation.Diagnostics.Select(d => d.Range.ToMonacoRange()).ToArray());
19 | }
20 |
21 | public Task ProvideCompletionItems(string code, MonacoPosition position)
22 | {
23 | return Task.FromResult(CompilationStore.Compilation.ProvideCompletionItems(position.ToCompilerPosition()));
24 | }
25 |
26 | public Task ProvideHover(string code, MonacoPosition position)
27 | {
28 | return Task.FromResult(CompilationStore.Compilation.ProvideHover(position.ToCompilerPosition()));
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/ArrayLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using System.Linq;
10 | using SmallBasic.Compiler.Runtime;
11 |
12 | internal sealed class ArrayLibrary : IArrayLibrary
13 | {
14 | private readonly Dictionary arrays = new Dictionary();
15 |
16 | public bool ContainsIndex(ArrayValue array, string index) => array.ContainsKey(index);
17 |
18 | public bool ContainsValue(ArrayValue array, string value) => array.Values.Any(existing => existing.ToString() == value);
19 |
20 | public ArrayValue GetAllIndices(ArrayValue array)
21 | {
22 | int i = 1;
23 | return new ArrayValue(array.Keys.Select(k => StringValue.Create(k)).ToDictionary(value => (i++).ToString(CultureInfo.CurrentCulture)));
24 | }
25 |
26 | public decimal GetItemCount(ArrayValue array) => array.Count;
27 |
28 | public BaseValue GetValue(string arrayName, string index)
29 | {
30 | if (this.arrays.TryGetValue(arrayName, out ArrayValue array) && array.TryGetValue(index, out BaseValue value))
31 | {
32 | return value;
33 | }
34 | else
35 | {
36 | return StringValue.Create(string.Empty);
37 | }
38 | }
39 |
40 | public bool IsArray(BaseValue array) => array is ArrayValue;
41 |
42 | public void RemoveValue(string arrayName, string index)
43 | {
44 | if (this.arrays.TryGetValue(arrayName, out ArrayValue array) && array.ContainsKey(index))
45 | {
46 | array.RemoveIndex(index);
47 | this.arrays[arrayName] = array;
48 | }
49 | }
50 |
51 | public void SetValue(string arrayName, string index, BaseValue value)
52 | {
53 | if (this.arrays.TryGetValue(arrayName, out ArrayValue array))
54 | {
55 | array.SetIndex(index, value);
56 | this.arrays[arrayName] = array;
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/ClockLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System;
8 | using System.Globalization;
9 | using SmallBasic.Compiler.Runtime;
10 |
11 | internal sealed class ClockLibrary : IClockLibrary
12 | {
13 | public string Get_Date() => DateTime.Now.ToString(DateTimeFormatInfo.GetInstance(CultureInfo.CurrentCulture).ShortDatePattern, CultureInfo.CurrentCulture);
14 |
15 | public decimal Get_Day() => DateTime.Now.Day;
16 |
17 | public decimal Get_ElapsedMilliseconds() => (decimal)(DateTime.Now - new DateTime(1900, 1, 1)).TotalMilliseconds;
18 |
19 | public decimal Get_Hour() => DateTime.Now.Hour;
20 |
21 | public decimal Get_Millisecond() => DateTime.Now.Millisecond;
22 |
23 | public decimal Get_Minute() => DateTime.Now.Minute;
24 |
25 | public decimal Get_Month() => DateTime.Now.Month;
26 |
27 | public decimal Get_Second() => DateTime.Now.Second;
28 |
29 | public string Get_Time() => DateTime.Now.ToString(DateTimeFormatInfo.GetInstance(CultureInfo.CurrentCulture).LongTimePattern, CultureInfo.CurrentCulture);
30 |
31 | public string Get_WeekDay() => DateTime.Now.ToString("dddd", CultureInfo.CurrentCulture);
32 |
33 | public decimal Get_Year() => DateTime.Now.Year;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Controls/BaseControl.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Controls
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Editor.Components;
9 |
10 | internal abstract class BaseControl
11 | {
12 | protected BaseControl(string name, decimal left, decimal top, decimal width, decimal height)
13 | {
14 | this.Name = name;
15 | this.Left = left;
16 | this.Top = top;
17 | this.Width = width;
18 | this.Height = height;
19 | this.Visible = true;
20 | }
21 |
22 | public string Name { get; set; }
23 |
24 | public decimal Left { get; set; }
25 |
26 | public decimal Top { get; set; }
27 |
28 | public decimal Width { get; set; }
29 |
30 | public decimal Height { get; set; }
31 |
32 | public bool Visible { get; set; }
33 |
34 | protected IReadOnlyDictionary Styles => new Dictionary
35 | {
36 | { "left", $"{this.Left}px" },
37 | { "top", $"{this.Top}px" },
38 | { "width", $"{this.Width}px" },
39 | { "height", $"{this.Height}px" },
40 | { "visibility", this.Visible ? "visible" : "hidden" }
41 | };
42 |
43 | public abstract void ComposeTree(ControlsLibrary library, TreeComposer composer);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Controls/ButtonControl.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Controls
6 | {
7 | using SmallBasic.Editor.Components;
8 |
9 | internal sealed class ButtonControl : BaseControl
10 | {
11 | public ButtonControl(string name, string caption, decimal left, decimal top, decimal width, decimal height)
12 | : base(name, left, top, width, height)
13 | {
14 | this.Caption = caption;
15 | }
16 |
17 | public string Caption { get; set; }
18 |
19 | public override void ComposeTree(ControlsLibrary library, TreeComposer composer)
20 | {
21 | composer.Element(
22 | name: "button",
23 | body: () => composer.Text(this.Caption),
24 | events: new TreeComposer.Events
25 | {
26 | OnClick = args => library.NotifyButtonClicked(this.Name)
27 | },
28 | styles: this.Styles);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Controls/MultilineTextBoxControl.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Controls
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Editor.Components;
9 |
10 | internal sealed class MultilineTextBoxControl : BaseControl
11 | {
12 | public MultilineTextBoxControl(string name, decimal left, decimal top, decimal width, decimal height)
13 | : base(name, left, top, width, height)
14 | {
15 | this.Text = string.Empty;
16 | }
17 |
18 | public string Text { get; set; }
19 |
20 | public override void ComposeTree(ControlsLibrary library, TreeComposer composer)
21 | {
22 | composer.Element(
23 | name: "textarea",
24 | styles: this.Styles,
25 | events: new TreeComposer.Events
26 | {
27 | OnInput = args =>
28 | {
29 | this.Text = args.Value.ToString();
30 | library.NotifyTextTyped(this.Name);
31 | }
32 | },
33 | attributes: new Dictionary()
34 | {
35 | { "value", this.Text },
36 | });
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Controls/TextBoxControl.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Controls
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Editor.Components;
9 |
10 | internal sealed class TextBoxControl : BaseControl
11 | {
12 | public TextBoxControl(string name, decimal left, decimal top, decimal width, decimal height)
13 | : base(name, left, top, width, height)
14 | {
15 | this.Text = string.Empty;
16 | }
17 |
18 | public string Text { get; set; }
19 |
20 | public override void ComposeTree(ControlsLibrary library, TreeComposer composer)
21 | {
22 | composer.Element(
23 | name: "input",
24 | styles: this.Styles,
25 | events: new TreeComposer.Events
26 | {
27 | OnInput = args =>
28 | {
29 | this.Text = args.Value.ToString();
30 | library.NotifyTextTyped(this.Name);
31 | }
32 | },
33 | attributes: new Dictionary()
34 | {
35 | { "type", "text" },
36 | { "value", this.Text },
37 | });
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/DesktopLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using SmallBasic.Compiler.Runtime;
8 |
9 | internal sealed class DesktopLibrary : IDesktopLibrary
10 | {
11 | // All members are deprecated
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/DictionaryLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using SmallBasic.Compiler.Runtime;
8 |
9 | internal sealed class DictionaryLibrary : IDictionaryLibrary
10 | {
11 | // All members are deprecated
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/FlickrLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using SmallBasic.Compiler.Runtime;
8 |
9 | internal sealed class FlickrLibrary : IFlickrLibrary
10 | {
11 | // All members are deprecated
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/BaseGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using SmallBasic.Editor.Components;
8 | using SmallBasic.Editor.Libraries.Utilities;
9 |
10 | internal abstract class BaseGraphicsObject
11 | {
12 | protected BaseGraphicsObject(GraphicsWindowStyles styles)
13 | {
14 | this.Styles = styles;
15 | }
16 |
17 | public GraphicsWindowStyles Styles { get; set; }
18 |
19 | public abstract void ComposeTree(TreeComposer composer);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/EllipseGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using SmallBasic.Editor.Components;
10 | using SmallBasic.Editor.Libraries.Utilities;
11 |
12 | internal sealed class EllipseGraphicsObject : BaseGraphicsObject
13 | {
14 | public EllipseGraphicsObject(decimal x, decimal y, decimal width, decimal height, GraphicsWindowStyles styles)
15 | : base(styles)
16 | {
17 | this.X = x + width;
18 | this.Y = y + height;
19 | this.Width = width;
20 | this.Height = height;
21 | }
22 |
23 | public decimal X { get; set; }
24 |
25 | public decimal Y { get; set; }
26 |
27 | public decimal Width { get; set; }
28 |
29 | public decimal Height { get; set; }
30 |
31 | public override void ComposeTree(TreeComposer composer)
32 | {
33 | composer.Element(
34 | name: "ellipse",
35 | styles: new Dictionary
36 | {
37 | { "fill", this.Styles.BrushColor },
38 | { "stroke", this.Styles.PenColor },
39 | { "stroke-width", $"{this.Styles.PenWidth}px" },
40 | },
41 | attributes: new Dictionary
42 | {
43 | { "cx", (this.X - (this.Width / 2)).ToString(CultureInfo.CurrentCulture) },
44 | { "cy", (this.Y - (this.Height / 2)).ToString(CultureInfo.CurrentCulture) },
45 | { "rx", (this.Width / 2).ToString(CultureInfo.CurrentCulture) },
46 | { "ry", (this.Height / 2).ToString(CultureInfo.CurrentCulture) },
47 | });
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/ImageGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using SmallBasic.Editor.Components;
10 | using SmallBasic.Editor.Libraries.Utilities;
11 |
12 | internal sealed class ImageGraphicsObject : BaseGraphicsObject
13 | {
14 | public ImageGraphicsObject(decimal x, decimal y, decimal scaleX, decimal scaleY, string name, GraphicsWindowStyles styles)
15 | : base(styles)
16 | {
17 | this.X = x;
18 | this.Y = y;
19 | this.ScaleX = scaleX;
20 | this.ScaleY = scaleY;
21 | this.Name = name;
22 | }
23 |
24 | public decimal X { get; set; }
25 |
26 | public decimal Y { get; set; }
27 |
28 | public decimal ScaleX { get; set; }
29 |
30 | public decimal ScaleY { get; set; }
31 |
32 | public string Name { get; set; }
33 |
34 | public override void ComposeTree(TreeComposer composer)
35 | {
36 | composer.Element(
37 | name: "image",
38 | attributes: new Dictionary
39 | {
40 | { "href", this.Name },
41 | { "x", this.X.ToString(CultureInfo.CurrentCulture) },
42 | { "y", this.Y.ToString(CultureInfo.CurrentCulture) },
43 | { "transform", $"scale({this.ScaleX}, {this.ScaleY})" }
44 | });
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/RectangleGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using SmallBasic.Editor.Components;
10 | using SmallBasic.Editor.Libraries.Utilities;
11 |
12 | internal sealed class RectangleGraphicsObject : BaseGraphicsObject
13 | {
14 | public RectangleGraphicsObject(decimal x, decimal y, decimal width, decimal height, GraphicsWindowStyles styles)
15 | : base(styles)
16 | {
17 | this.X = x;
18 | this.Y = y;
19 | this.Width = width;
20 | this.Height = height;
21 | }
22 |
23 | public decimal X { get; set; }
24 |
25 | public decimal Y { get; set; }
26 |
27 | public decimal Width { get; set; }
28 |
29 | public decimal Height { get; set; }
30 |
31 | public override void ComposeTree(TreeComposer composer)
32 | {
33 | composer.Element(
34 | name: "rect",
35 | styles: new Dictionary
36 | {
37 | { "fill", this.Styles.BrushColor },
38 | { "stroke", this.Styles.PenColor },
39 | { "stroke-width", $"{this.Styles.PenWidth}px" },
40 | },
41 | attributes: new Dictionary
42 | {
43 | { "x", this.X.ToString(CultureInfo.CurrentCulture) },
44 | { "y", this.Y.ToString(CultureInfo.CurrentCulture) },
45 | { "width", this.Width.ToString(CultureInfo.CurrentCulture) },
46 | { "height", this.Height.ToString(CultureInfo.CurrentCulture) },
47 | });
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/TextGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using SmallBasic.Editor.Components;
10 | using SmallBasic.Editor.Libraries.Utilities;
11 |
12 | internal sealed class TextGraphicsObject : BaseGraphicsObject
13 | {
14 | public TextGraphicsObject(decimal x, decimal y, string text, decimal? width, GraphicsWindowStyles styles)
15 | : base(styles)
16 | {
17 | this.X = x;
18 | this.Y = y;
19 | this.Text = text;
20 | this.Width = width;
21 | }
22 |
23 | public decimal X { get; set; }
24 |
25 | public decimal Y { get; set; }
26 |
27 | public string Text { get; set; }
28 |
29 | public decimal? Width { get; set; }
30 |
31 | public override void ComposeTree(TreeComposer composer)
32 | {
33 | var attributes = new Dictionary
34 | {
35 | { "x", this.X.ToString(CultureInfo.CurrentCulture) },
36 | { "y", this.Y.ToString(CultureInfo.CurrentCulture) },
37 | { "dy", this.Styles.FontSize.ToString(CultureInfo.CurrentCulture) }
38 | };
39 |
40 | if (this.Width.HasValue)
41 | {
42 | attributes.Add("textLength", this.Width.Value.ToString(CultureInfo.CurrentCulture));
43 | }
44 |
45 | composer.Element(
46 | name: "text",
47 | styles: new Dictionary
48 | {
49 | { "fill", this.Styles.BrushColor },
50 | { "font-weight", this.Styles.FontBold ? "bold" : "normal" },
51 | { "font-style", this.Styles.FontItalic ? "italic" : "normal" },
52 | { "font-family", $@"""{this.Styles.FontName}""" },
53 | { "font-size", $"{this.Styles.FontSize}px" },
54 | { "pointer-events", "none" }
55 | },
56 | attributes: attributes,
57 | body: () => composer.Text(this.Text));
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/TriangleGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using System.Collections.Generic;
8 | using SmallBasic.Editor.Components;
9 | using SmallBasic.Editor.Libraries.Utilities;
10 |
11 | internal sealed class TriangleGraphicsObject : BaseGraphicsObject
12 | {
13 | public TriangleGraphicsObject(decimal x1, decimal y1, decimal x2, decimal y2, decimal x3, decimal y3, GraphicsWindowStyles styles)
14 | : base(styles)
15 | {
16 | this.X1 = x1;
17 | this.Y1 = y1;
18 | this.X2 = x2;
19 | this.Y2 = y2;
20 | this.X3 = x3;
21 | this.Y3 = y3;
22 | }
23 |
24 | public decimal X1 { get; set; }
25 |
26 | public decimal Y1 { get; set; }
27 |
28 | public decimal X2 { get; set; }
29 |
30 | public decimal Y2 { get; set; }
31 |
32 | public decimal X3 { get; set; }
33 |
34 | public decimal Y3 { get; set; }
35 |
36 | public override void ComposeTree(TreeComposer composer)
37 | {
38 | composer.Element(
39 | name: "polygon",
40 | styles: new Dictionary
41 | {
42 | { "fill", this.Styles.BrushColor },
43 | { "stroke", this.Styles.PenColor },
44 | { "stroke-width", $"{this.Styles.PenWidth}px" },
45 | },
46 | attributes: new Dictionary
47 | {
48 | { "points", string.Join(",", this.X1, this.Y1, this.X2, this.Y2, this.X3, this.Y3) }
49 | });
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Graphics/TurtleGraphicsObject.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Graphics
6 | {
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using SmallBasic.Editor.Components;
10 | using SmallBasic.Editor.Libraries.Utilities;
11 |
12 | internal sealed class TurtleGraphicsObject : BaseGraphicsObject
13 | {
14 | public TurtleGraphicsObject(GraphicsWindowStyles styles)
15 | : base(styles)
16 | {
17 | }
18 |
19 | public static decimal Width => 48;
20 |
21 | public static decimal Height => 61;
22 |
23 | public override void ComposeTree(TreeComposer composer)
24 | {
25 | composer.Element(
26 | name: "image",
27 | attributes: new Dictionary
28 | {
29 | { "href", $"Turtle.svg" },
30 | /* width and height attributes required on Firefox */
31 | { "width", Width.ToString(CultureInfo.CurrentCulture) },
32 | { "height", Height.ToString(CultureInfo.CurrentCulture) }
33 | });
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/ImageListLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Globalization;
10 | using System.Threading.Tasks;
11 | using SmallBasic.Compiler.Runtime;
12 | using SmallBasic.Editor.Components;
13 | using SmallBasic.Editor.Libraries.Utilities;
14 | using SmallBasic.Utilities.Bridge;
15 |
16 | internal sealed class ImageListLibrary : IImageListLibrary
17 | {
18 | private readonly LibrariesCollection libraries;
19 | private readonly NamedCounter counter = new NamedCounter();
20 | private readonly Dictionary images = new Dictionary();
21 |
22 | public ImageListLibrary(LibrariesCollection libraries)
23 | {
24 | this.libraries = libraries;
25 | }
26 |
27 | public decimal GetHeightOfImage(string imageName)
28 | {
29 | if (this.images.TryGetValue(imageName, out ImageListBridgeModels.ImageData image))
30 | {
31 | return image.Height;
32 | }
33 |
34 | return 0;
35 | }
36 |
37 | public decimal GetWidthOfImage(string imageName)
38 | {
39 | if (this.images.TryGetValue(imageName, out ImageListBridgeModels.ImageData image))
40 | {
41 | return image.Width;
42 | }
43 |
44 | return 0;
45 | }
46 |
47 | public async Task LoadImage(string fileNameOrUrl)
48 | {
49 | var name = this.counter.GetNext("ImageList");
50 | var data = await Bridge.Network.LoadImage(fileNameOrUrl).ConfigureAwait(false);
51 | this.images.Add(name, data);
52 | return name;
53 | }
54 |
55 | internal void EmbedImages(TreeComposer composer)
56 | {
57 | composer.Element(name: "defs", body: () =>
58 | {
59 | foreach (var pair in this.images)
60 | {
61 | composer.Element("image", attributes: new Dictionary
62 | {
63 | { "id", pair.Key },
64 | { "width", pair.Value.Width.ToString(CultureInfo.CurrentCulture) },
65 | { "height", pair.Value.Height.ToString(CultureInfo.CurrentCulture) },
66 | { "href", $"data:image/image;base64,{pair.Value.Base64Contents}" }
67 | });
68 | }
69 | });
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/MathLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System;
8 | using SmallBasic.Compiler.Runtime;
9 |
10 | internal sealed class MathLibrary : IMathLibrary
11 | {
12 | private static readonly Random Random = new Random((int)DateTime.Now.Ticks);
13 |
14 | public decimal Get_Pi() => (decimal)Math.PI;
15 |
16 | public decimal Abs(decimal number) => Math.Abs(number);
17 |
18 | public decimal ArcCos(decimal cosValue) => (decimal)Math.Acos((double)cosValue);
19 |
20 | public decimal ArcSin(decimal sinValue) => (decimal)Math.Asin((double)sinValue);
21 |
22 | public decimal ArcTan(decimal tanValue) => (decimal)Math.Atan((double)tanValue);
23 |
24 | public decimal Ceiling(decimal number) => Math.Ceiling(number);
25 |
26 | public decimal Cos(decimal angle) => (decimal)Math.Cos((double)angle);
27 |
28 | public decimal Floor(decimal number) => Math.Floor(number);
29 |
30 | public decimal GetDegrees(decimal angle) => (180 * angle / (decimal)Math.PI) % 360;
31 |
32 | public decimal GetRadians(decimal angle) => (angle % 360) * (decimal)Math.PI / 180;
33 |
34 | public decimal GetRandomNumber(decimal maxNumber) => Random.Next((int)Math.Max(1, maxNumber)) + 1;
35 |
36 | public decimal Log(decimal number) => (decimal)Math.Log10((double)number);
37 |
38 | public decimal Max(decimal number1, decimal number2) => Math.Max(number1, number2);
39 |
40 | public decimal Min(decimal number1, decimal number2) => Math.Min(number1, number2);
41 |
42 | public decimal NaturalLog(decimal number) => (decimal)Math.Log((double)number);
43 |
44 | public decimal Power(decimal baseNumber, decimal exponent) => (decimal)Math.Pow((double)baseNumber, (double)exponent);
45 |
46 | public decimal Remainder(decimal dividend, decimal divisor) => divisor == 0 ? 0 : (dividend % divisor);
47 |
48 | public decimal Round(decimal number) => Math.Round(number);
49 |
50 | public decimal Sin(decimal angle) => (decimal)Math.Sin((double)angle);
51 |
52 | public decimal SquareRoot(decimal number) => (decimal)Math.Sqrt((double)number);
53 |
54 | public decimal Tan(decimal angle) => (decimal)Math.Tan((double)angle);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/NetworkLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System.Threading.Tasks;
8 | using SmallBasic.Compiler.Runtime;
9 |
10 | internal sealed class NetworkLibrary : INetworkLibrary
11 | {
12 | public Task DownloadFile(string url)
13 | => Bridge.Network.DownloadFile(url);
14 |
15 | public Task GetWebPageContents(string url)
16 | => Bridge.Network.GetWebPageContents(url);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/ProgramLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using SmallBasic.Compiler.Runtime;
11 | using SmallBasic.Editor.Store;
12 |
13 | internal sealed class ProgramLibrary : IProgramLibrary
14 | {
15 | public Task Delay(decimal milliSeconds)
16 | {
17 | // Update display if needed
18 | GraphicsDisplayStore.UpdateDisplay();
19 |
20 | return Task.Delay((int)milliSeconds);
21 | }
22 |
23 | public void End() => throw new InvalidOperationException("This should have been removed in binding.");
24 |
25 | public void Pause() => throw new InvalidOperationException("This should have been removed in binding.");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/EllipseShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using SmallBasic.Editor.Libraries.Graphics;
8 | using SmallBasic.Editor.Libraries.Utilities;
9 |
10 | internal sealed class EllipseShape : BaseShape
11 | {
12 | public EllipseShape(decimal width, decimal height, GraphicsWindowStyles styles)
13 | : base(new EllipseGraphicsObject(x: 0, y: 0, width, height, styles))
14 | {
15 | }
16 |
17 | public override decimal Height => this.Graphics.Height;
18 |
19 | public override decimal Width => this.Graphics.Width;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/ImageShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using System;
8 | using SmallBasic.Editor.Libraries.Graphics;
9 | using SmallBasic.Editor.Libraries.Utilities;
10 |
11 | internal sealed class ImageShape : BaseShape
12 | {
13 | private readonly decimal width;
14 | private readonly decimal height;
15 |
16 | public ImageShape(string imageName, decimal width, decimal height, GraphicsWindowStyles styles)
17 | : base(new ImageGraphicsObject(x: 0, y: 0, scaleX: 1, scaleY: 1, imageName, styles))
18 | {
19 | this.width = width;
20 | this.height = height;
21 | }
22 |
23 | public override decimal Height => this.height;
24 |
25 | public override decimal Width => this.width;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/LineShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using System;
8 | using SmallBasic.Editor.Libraries.Graphics;
9 | using SmallBasic.Editor.Libraries.Utilities;
10 |
11 | internal sealed class LineShape : BaseShape
12 | {
13 | public LineShape(decimal x1, decimal y1, decimal x2, decimal y2, GraphicsWindowStyles styles)
14 | : base(new LineGraphicsObject(x1, y1, x2, y2, styles))
15 | {
16 | }
17 |
18 | public override decimal Height => Math.Abs(this.Graphics.Y1 - this.Graphics.Y2);
19 |
20 | public override decimal Width => Math.Abs(this.Graphics.X1 - this.Graphics.X2);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/RectangleShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using SmallBasic.Editor.Libraries.Graphics;
8 | using SmallBasic.Editor.Libraries.Utilities;
9 |
10 | internal sealed class RectangleShape : BaseShape
11 | {
12 | public RectangleShape(decimal width, decimal height, GraphicsWindowStyles styles)
13 | : base(new RectangleGraphicsObject(x: 0, y: 0, width, height, styles))
14 | {
15 | }
16 |
17 | public override decimal Height => this.Graphics.Height;
18 |
19 | public override decimal Width => this.Graphics.Width;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/TextShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using SmallBasic.Editor.Libraries.Graphics;
8 | using SmallBasic.Editor.Libraries.Utilities;
9 |
10 | internal sealed class TextShape : BaseShape
11 | {
12 | public TextShape(string text, GraphicsWindowStyles styles)
13 | : base(new TextGraphicsObject(x: 0, y: 0, text, width: default, styles))
14 | {
15 | }
16 |
17 | public override decimal Height => this.Graphics.Styles.FontSize;
18 |
19 | public override decimal Width => this.Graphics.Width ?? 0;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/TriangleShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using System;
8 | using SmallBasic.Editor.Libraries.Graphics;
9 | using SmallBasic.Editor.Libraries.Utilities;
10 |
11 | internal sealed class TriangleShape : BaseShape
12 | {
13 | public TriangleShape(decimal x1, decimal y1, decimal x2, decimal y2, decimal x3, decimal y3, GraphicsWindowStyles styles)
14 | : base(new TriangleGraphicsObject(x1, y1, x2, y2, x3, y3, styles))
15 | {
16 | }
17 |
18 | public override decimal Height => Math.Max(this.Graphics.Y1, Math.Max(this.Graphics.Y2, this.Graphics.Y3)) - Math.Min(this.Graphics.Y1, Math.Min(this.Graphics.Y2, this.Graphics.Y3));
19 |
20 | public override decimal Width => Math.Max(this.Graphics.X1, Math.Max(this.Graphics.X2, this.Graphics.X3)) - Math.Min(this.Graphics.X1, Math.Min(this.Graphics.X2, this.Graphics.X3));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Shapes/TurtleShape.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Shapes
6 | {
7 | using SmallBasic.Editor.Libraries.Graphics;
8 | using SmallBasic.Editor.Libraries.Utilities;
9 |
10 | internal sealed class TurtleShape : BaseShape
11 | {
12 | public TurtleShape(GraphicsWindowStyles styles)
13 | : base(new TurtleGraphicsObject(styles))
14 | {
15 | }
16 |
17 | public override decimal Height => TurtleGraphicsObject.Height;
18 |
19 | public override decimal Width => TurtleGraphicsObject.Width;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/SoundLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using SmallBasic.Compiler.Runtime;
8 |
9 | internal sealed class SoundLibrary : ISoundLibrary
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/StackLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using SmallBasic.Compiler.Runtime;
10 |
11 | internal sealed class StackLibrary : IStackLibrary
12 | {
13 | private readonly Dictionary> stacks = new Dictionary>();
14 |
15 | public decimal GetCount(string stackName)
16 | {
17 | if (this.stacks.TryGetValue(stackName, out Stack stack))
18 | {
19 | return stack.Count;
20 | }
21 |
22 | return 0;
23 | }
24 |
25 | public string PopValue(string stackName)
26 | {
27 | if (this.stacks.TryGetValue(stackName, out Stack stack) && stack.Any())
28 | {
29 | return stack.Pop();
30 | }
31 |
32 | return string.Empty;
33 | }
34 |
35 | public void PushValue(string stackName, string value)
36 | {
37 | if (!this.stacks.ContainsKey(stackName))
38 | {
39 | this.stacks.Add(stackName, new Stack());
40 | }
41 |
42 | this.stacks[stackName].Push(value);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/TextLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System;
8 | using System.Globalization;
9 | using System.Linq;
10 | using SmallBasic.Compiler.Runtime;
11 |
12 | public sealed class TextLibrary : ITextLibrary
13 | {
14 | public string Append(string text1, string text2) => text1 + text2;
15 |
16 | public string ConvertToLowerCase(string text) => text.ToLower(CultureInfo.CurrentCulture);
17 |
18 | public string ConvertToUpperCase(string text) => text.ToUpper(CultureInfo.CurrentCulture);
19 |
20 | public bool EndsWith(string text, string subText) => text.EndsWith(subText, StringComparison.CurrentCulture);
21 |
22 | public string GetCharacter(decimal characterCode) => ((char)characterCode).ToString(CultureInfo.CurrentCulture);
23 |
24 | public decimal GetCharacterCode(string character) => character.Any() ? (decimal)character[0] : 0;
25 |
26 | public decimal GetIndexOf(string text, string subText) => text.IndexOf(subText, StringComparison.CurrentCulture) + 1;
27 |
28 | public decimal GetLength(string text) => text.Length;
29 |
30 | public string GetSubText(string text, decimal start, decimal length)
31 | {
32 | start--;
33 |
34 | if (start < 0 || start >= text.Length || length < 1)
35 | {
36 | return string.Empty;
37 | }
38 |
39 | length = Math.Min(length, text.Length - start);
40 | return text.Substring((int)start, (int)length);
41 | }
42 |
43 | public string GetSubTextToEnd(string text, decimal start)
44 | {
45 | start--;
46 | if (start < 0 || start >= text.Length)
47 | {
48 | return string.Empty;
49 | }
50 |
51 | return text.Substring((int)start);
52 | }
53 |
54 | public bool IsSubText(string text, string subText) => text.Contains(subText);
55 |
56 | public bool StartsWith(string text, string subText) => text.StartsWith(subText, StringComparison.CurrentCulture);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/TimerLibrary.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries
6 | {
7 | using System;
8 | using System.Threading;
9 | using SmallBasic.Compiler.Runtime;
10 | using SmallBasic.Utilities;
11 |
12 | internal sealed class TimerLibrary : ITimerLibrary, IDisposable
13 | {
14 | private const int MaxInterval = 100000000;
15 |
16 | private readonly Timer timer;
17 |
18 | private int interval;
19 |
20 | public TimerLibrary()
21 | {
22 | this.timer = new Timer((object state) =>
23 | {
24 | if (!this.Tick.IsDefault())
25 | {
26 | this.Tick();
27 | }
28 | });
29 |
30 | this.interval = MaxInterval;
31 | this.Pause();
32 | }
33 |
34 | public event Action Tick;
35 |
36 | public decimal Get_Interval() => this.interval;
37 |
38 | public void Set_Interval(decimal value)
39 | {
40 | this.interval = Math.Max(Math.Min((int)value, MaxInterval), 10);
41 | this.timer.Change(this.interval, this.interval);
42 | }
43 |
44 | public void Pause()
45 | {
46 | this.timer.Change(Timeout.Infinite, Timeout.Infinite);
47 | }
48 |
49 | public void Resume()
50 | {
51 | this.timer.Change(this.interval, this.interval);
52 | }
53 |
54 | public void Dispose()
55 | {
56 | this.timer.Dispose();
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Utilities/GraphicsWindowStyles.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Utilities
6 | {
7 | internal sealed class GraphicsWindowStyles
8 | {
9 | public GraphicsWindowStyles(
10 | decimal penWidth,
11 | string penColor,
12 | string brushColor,
13 | bool fontBold,
14 | bool fontItalic,
15 | string fontName,
16 | decimal fontSize)
17 | {
18 | this.PenWidth = penWidth;
19 | this.PenColor = penColor;
20 | this.BrushColor = brushColor;
21 | this.FontBold = fontBold;
22 | this.FontItalic = fontItalic;
23 | this.FontName = fontName;
24 | this.FontSize = fontSize;
25 | }
26 |
27 | public decimal PenWidth { get; private set; }
28 |
29 | public string PenColor { get; private set; }
30 |
31 | public string BrushColor { get; private set; }
32 |
33 | public bool FontBold { get; private set; }
34 |
35 | public bool FontItalic { get; private set; }
36 |
37 | public string FontName { get; private set; }
38 |
39 | public decimal FontSize { get; private set; }
40 |
41 | public GraphicsWindowStyles With(
42 | decimal? penWidth = default,
43 | string penColor = default,
44 | string brushColor = default,
45 | bool? fontBold = default,
46 | bool? fontItalic = default,
47 | string fontName = default,
48 | decimal? fontSize = default)
49 | => new GraphicsWindowStyles(
50 | penWidth: penWidth ?? this.PenWidth,
51 | penColor: penColor ?? this.PenColor,
52 | brushColor: brushColor ?? this.BrushColor,
53 | fontBold: fontBold ?? this.FontBold,
54 | fontItalic: fontItalic ?? this.FontItalic,
55 | fontName: fontName ?? this.FontName,
56 | fontSize: fontSize ?? this.FontSize);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Libraries/Utilities/NamedCounter.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Libraries.Utilities
6 | {
7 | using System.Collections.Generic;
8 |
9 | public sealed class NamedCounter
10 | {
11 | private readonly Dictionary counters = new Dictionary();
12 |
13 | public string GetNext(string name)
14 | {
15 | if (!this.counters.TryGetValue(name, out int value))
16 | {
17 | value = 0;
18 | }
19 |
20 | this.counters[name] = ++value;
21 | return name + value;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor
6 | {
7 | using System.Globalization;
8 | using Microsoft.AspNetCore.Blazor.Builder;
9 | using Microsoft.AspNetCore.Blazor.Hosting;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using SmallBasic.Editor.Components.Layout;
12 |
13 | public static class Program
14 | {
15 | public static void Main()
16 | {
17 | CultureInfo.CurrentCulture = new CultureInfo("en-US");
18 |
19 | BlazorWebAssemblyHost
20 | .CreateDefaultBuilder()
21 | .UseBlazorStartup()
22 | .Build()
23 | .Run();
24 | }
25 | }
26 |
27 | public class Startup
28 | {
29 | #pragma warning disable CA1801, CA1822
30 | public void ConfigureServices(IServiceCollection services)
31 | {
32 | }
33 |
34 | public void Configure(IBlazorApplicationBuilder app)
35 | {
36 | app.AddComponent("app");
37 | }
38 | #pragma warning restore CA1801, CA1822
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:56177/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "SmallBasic.Editor": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:56178/"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/SmallBasic.Editor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | 3.0
6 |
7 |
8 |
9 | dotnet
10 | blazor serve
11 |
12 | false
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | $([System.IO.Path]::GetFullPath($(OutputPath)\dist))
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Store/CompilationStore.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Store
6 | {
7 | using System;
8 | using SmallBasic.Compiler;
9 | using SmallBasic.Utilities;
10 |
11 | internal static class CompilationStore
12 | {
13 | static CompilationStore()
14 | {
15 | Compilation = new SmallBasicCompilation(
16 | @"' A new Program!
17 | TextWindow.WriteLine(""What is your name?"")
18 | name = TextWindow.Read()
19 | TextWindow.WriteLine(""Hello "" + name + ""!"")");
20 | }
21 |
22 | public static event Action CodeChanged;
23 |
24 | public static SmallBasicCompilation Compilation { get; private set; }
25 |
26 | public static void NotifyCodeChanged(string code)
27 | {
28 | Compilation = new SmallBasicCompilation(code);
29 |
30 | if (!CodeChanged.IsDefault())
31 | {
32 | CodeChanged();
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Store/NavigationStore.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Store
6 | {
7 | using System;
8 |
9 | internal static class NavigationStore
10 | {
11 | static NavigationStore()
12 | {
13 | CurrentPage = PageId.Edit;
14 | }
15 |
16 | public static event Action PageChanged;
17 |
18 | internal enum PageId
19 | {
20 | Edit,
21 | Run,
22 | Debug,
23 | }
24 |
25 | public static PageId CurrentPage { get; private set; }
26 |
27 | public static void NagivateTo(PageId page)
28 | {
29 | CurrentPage = page;
30 | PageChanged();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Editor/Store/TextDisplayStore.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Editor.Store
6 | {
7 | using System.Diagnostics;
8 | using System.Threading.Tasks;
9 | using SmallBasic.Editor.Components.Display;
10 | using SmallBasic.Utilities;
11 |
12 | internal delegate void TextInputEventSignature(string text);
13 |
14 | internal static class TextDisplayStore
15 | {
16 | private static TextDisplay display;
17 |
18 | public static event TextInputEventSignature TextInput;
19 |
20 | public static string Title
21 | {
22 | get
23 | {
24 | if (display.IsDefault())
25 | {
26 | return string.Empty;
27 | }
28 |
29 | return display.Title;
30 | }
31 |
32 | set
33 | {
34 | if (!display.IsDefault())
35 | {
36 | display.Title = value;
37 | }
38 | }
39 | }
40 |
41 | public static void SetDisplay(TextDisplay instance)
42 | {
43 | display = instance;
44 | }
45 |
46 | public static void NotifyTextInput(string text)
47 | {
48 | if (!TextInput.IsDefault())
49 | {
50 | TextInput(text);
51 | }
52 | }
53 |
54 | public static Task AppendOutput(OutputChunk chunk)
55 | {
56 | if (!display.IsDefault())
57 | {
58 | return display.AppendOutput(chunk);
59 | }
60 |
61 | return Task.CompletedTask;
62 | }
63 |
64 | public static Task SetInputMode(AcceptedInputMode mode)
65 | {
66 | if (!display.IsDefault())
67 | {
68 | return display.SetInputMode(mode);
69 | }
70 |
71 | return Task.CompletedTask;
72 | }
73 |
74 | public static void Clear()
75 | {
76 | if (!display.IsDefault())
77 | {
78 | display.Clear();
79 | }
80 | }
81 |
82 | public static void SetBackgroundColor(string hexColor)
83 | {
84 | if (!display.IsDefault())
85 | {
86 | display.SetBackgroundColor(hexColor);
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/BaseConverterTask.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators
6 | {
7 | using System;
8 | using System.IO;
9 | using System.Text;
10 | using System.Xml;
11 | using System.Xml.Schema;
12 | using System.Xml.Serialization;
13 | using SmallBasic.Utilities;
14 |
15 | public abstract class BaseConverterTask : BaseTask
16 | {
17 | public abstract int Execute(string inputFile, string outputFile);
18 | }
19 |
20 | public abstract class BaseConverterTask : BaseConverterTask
21 | {
22 | public override sealed int Execute(string inputFile, string outputFile)
23 | {
24 | var settings = new XmlReaderSettings();
25 | settings.ValidationEventHandler += (sender, args) =>
26 | {
27 | switch (args.Severity)
28 | {
29 | case XmlSeverityType.Error:
30 | this.LogError(args.Message);
31 | break;
32 | case XmlSeverityType.Warning:
33 | this.LogError(args.Message);
34 | break;
35 | default:
36 | throw ExceptionUtilities.UnexpectedValue(args.Severity);
37 | }
38 | };
39 |
40 | using (var stream = new MemoryStream(File.ReadAllBytes(inputFile)))
41 | {
42 | using (var xmlReader = XmlReader.Create(stream, settings))
43 | {
44 | var serializer = new XmlSerializer(typeof(TModel));
45 | var model = (TModel)serializer.Deserialize(xmlReader);
46 |
47 | this.GenerateDocHeader(outputFile);
48 | this.Generate(model);
49 |
50 | return this.SaveAndExit(outputFile);
51 | }
52 | }
53 | }
54 |
55 | protected abstract void Generate(TModel model);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Binding/Models.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Binding
6 | {
7 | using System.Collections.Generic;
8 | using System.Xml.Serialization;
9 |
10 | public sealed class Member
11 | {
12 | [XmlAttribute]
13 | public string Name { get; set; }
14 |
15 | [XmlAttribute]
16 | public string Type { get; set; }
17 |
18 | [XmlAttribute]
19 | public bool IsOptional { get; set; }
20 |
21 | [XmlAttribute]
22 | public bool IsList { get; set; }
23 | }
24 |
25 | public sealed class BoundNode
26 | {
27 | [XmlAttribute]
28 | public string Name { get; set; }
29 |
30 | [XmlAttribute]
31 | public string Inherits { get; set; }
32 |
33 | [XmlAttribute]
34 | public bool IsAbstract { get; set; }
35 |
36 | [XmlAttribute]
37 | public string Syntax { get; set; }
38 |
39 | [XmlArray(nameof(Members))]
40 | [XmlArrayItem(typeof(Member))]
41 | public List Members { get; set; }
42 | }
43 |
44 | [XmlRoot("root")]
45 | public sealed class BoundNodeCollection : List
46 | {
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Bridge/BridgeTypes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Bridge/Models.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Bridge
6 | {
7 | using System.Collections.Generic;
8 | using System.Xml.Serialization;
9 |
10 | public sealed class Method
11 | {
12 | [XmlAttribute]
13 | public string Name { get; set; }
14 |
15 | [XmlAttribute]
16 | public string InputType { get; set; }
17 |
18 | [XmlAttribute]
19 | public string InputName { get; set; }
20 |
21 | [XmlAttribute]
22 | public string OutputType { get; set; }
23 | }
24 |
25 | public sealed class BridgeType
26 | {
27 | [XmlAttribute]
28 | public string Name { get; set; }
29 |
30 | [XmlArray(nameof(Methods))]
31 | [XmlArrayItem(typeof(Method))]
32 | public List Methods { get; set; }
33 | }
34 |
35 | [XmlRoot("root")]
36 | public sealed class BridgeTypeCollection : List
37 | {
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Diagnostics/GenerateDiagnosticBag.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Diagnostics
6 | {
7 | using System.Linq;
8 | using SmallBasic.Utilities;
9 |
10 | public sealed class GenerateDiagnosticBag : BaseConverterTask
11 | {
12 | protected override void Generate(DiagnosticsCollection model)
13 | {
14 | this.Line("namespace SmallBasic.Compiler.Diagnostics");
15 | this.Brace();
16 |
17 | this.Line("using System.Collections.Generic;");
18 | this.Line("using SmallBasic.Compiler.Scanning;");
19 | this.Line("using SmallBasic.Utilities;");
20 | this.Blank();
21 |
22 | this.Line("internal sealed class DiagnosticBag");
23 | this.Brace();
24 |
25 | this.Line("private readonly List builder = new List();");
26 | this.Blank();
27 |
28 | this.Line("public IReadOnlyList Contents => this.builder;");
29 | this.Blank();
30 |
31 | foreach (var diagnostic in model)
32 | {
33 | string arguments = diagnostic.Parameters.Select(parameter => $", {parameter.Type} {parameter.Name}").Join();
34 | this.Line($"public void Report{diagnostic.Name}(TextRange range{arguments})");
35 | this.Brace();
36 |
37 | string displayStrings = diagnostic.Parameters.Select(parameter => $", {parameter.Name}.ToDisplayString()").Join();
38 | this.Line($"this.builder.Add(new Diagnostic(DiagnosticCode.{diagnostic.Name}, range{displayStrings}));");
39 | this.Unbrace();
40 | }
41 |
42 | this.Unbrace();
43 | this.Unbrace();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Diagnostics/GenerateDiagnosticCode.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Diagnostics
6 | {
7 | public sealed class GenerateDiagnosticCode : BaseConverterTask
8 | {
9 | protected override void Generate(DiagnosticsCollection model)
10 | {
11 | this.Line("namespace SmallBasic.Compiler.Diagnostics");
12 | this.Brace();
13 |
14 | this.Line("using SmallBasic.Utilities;");
15 | this.Line("using SmallBasic.Utilities.Resources;");
16 | this.Blank();
17 |
18 | this.Line("public enum DiagnosticCode");
19 | this.Brace();
20 |
21 | foreach (var diagnostic in model)
22 | {
23 | this.Line($"{diagnostic.Name},");
24 | }
25 |
26 | this.Unbrace();
27 |
28 | this.Line("internal static partial class DiagnosticCodeExtensions");
29 | this.Brace();
30 |
31 | this.Line("public static string ToDisplayString(this DiagnosticCode kind)");
32 | this.Brace();
33 |
34 | this.Line("switch (kind)");
35 | this.Brace();
36 |
37 | foreach (var diagnostic in model)
38 | {
39 | this.Line($"case DiagnosticCode.{diagnostic.Name}: return DiagnosticsResources.{diagnostic.Name};");
40 | }
41 |
42 | this.Line("default: throw ExceptionUtilities.UnexpectedValue(kind);");
43 |
44 | this.Unbrace();
45 | this.Unbrace();
46 | this.Unbrace();
47 | this.Unbrace();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Diagnostics/Models.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Diagnostics
6 | {
7 | using System.Collections.Generic;
8 | using System.Xml.Serialization;
9 |
10 | public sealed class Parameter
11 | {
12 | [XmlAttribute]
13 | public string Name { get; set; }
14 |
15 | [XmlAttribute]
16 | public string Type { get; set; }
17 | }
18 |
19 | public sealed class Diagnostic
20 | {
21 | [XmlAttribute]
22 | public string Name { get; set; }
23 |
24 | [XmlArray(nameof(Parameters))]
25 | [XmlArrayItem(typeof(Parameter))]
26 | public List Parameters { get; set; }
27 | }
28 |
29 | [XmlRoot("root")]
30 | public sealed class DiagnosticsCollection : List
31 | {
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Interop/CSInteropTypes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Interop/GenerateCSClientInterop.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Interop
6 | {
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using SmallBasic.Utilities;
10 |
11 | public sealed class GenerateCSClientInterop : BaseConverterTask
12 | {
13 | protected override void Generate(InteropTypeCollection model)
14 | {
15 | this.Blank();
16 | this.Line(@"/// ");
17 | this.Blank();
18 |
19 | this.Line("export module CSIntrop {");
20 | this.Indent();
21 |
22 | foreach (InteropType type in model)
23 | {
24 | this.Line($"export module {type.Name} {{");
25 | this.Indent();
26 |
27 | foreach (Method method in type.Methods)
28 | {
29 | this.Line($"export function {method.Name.ToLowerFirstChar()}({method.Parameters.Select(p => $"{p.Name}: {p.Type}").Join(", ")}): Promise<{method.ReturnType ?? "void"}> {{");
30 | this.Indent();
31 |
32 | IEnumerable arguments = new string[]
33 | {
34 | @"""SmallBasic.Editor""",
35 | $@"""CSIntrop.{type.Name}.{method.Name}"""
36 | }.Concat(method.Parameters.Select(p => p.Name));
37 |
38 | if (method.ReturnType.IsDefault())
39 | {
40 | this.Line($"return DotNet.invokeMethodAsync({arguments.Join(", ")}).then(() => {{");
41 | this.Indent();
42 | this.Line("Promise.resolve();");
43 | this.Unindent();
44 | this.Line("});");
45 | }
46 | else
47 | {
48 | this.Line($"return DotNet.invokeMethodAsync<{method.ReturnType}>({arguments.Join(", ")});");
49 | }
50 |
51 | this.Unbrace();
52 | }
53 |
54 | this.Unbrace();
55 | }
56 |
57 | this.Unbrace();
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Interop/GenerateJSEditorInterop.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Interop
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using SmallBasic.Utilities;
11 |
12 | public sealed class GenerateJSEditorInterop : BaseConverterTask
13 | {
14 | protected override void Generate(InteropTypeCollection model)
15 | {
16 | this.Line("namespace SmallBasic.Editor.Interop");
17 | this.Brace();
18 |
19 | this.Line("using System.Threading.Tasks;");
20 | this.Line("using Microsoft.AspNetCore.Blazor;");
21 | this.Line("using Microsoft.JSInterop;");
22 | this.Line("using SmallBasic.Compiler.Services;");
23 | this.Blank();
24 |
25 | this.Line("internal static class JSInterop");
26 | this.Brace();
27 |
28 | foreach (InteropType type in model)
29 | {
30 | this.Line($"public static class {type.Name}");
31 | this.Brace();
32 |
33 | foreach (Method method in type.Methods)
34 | {
35 | string returnType = method.ReturnType.IsDefault() ? "Task" : $"Task<{method.ReturnType.ToCSharpType()}>";
36 | string parameters = method.Parameters.Select(p => $"{p.Type.ToCSharpType()} {p.Name}").Join(", ");
37 | this.Line($"public static {(method.ReturnType.IsDefault() ? "async " : string.Empty)}{returnType} {method.Name}({parameters})");
38 | this.Brace();
39 |
40 | IEnumerable arguments = new string[]
41 | {
42 | $@"""JSInterop.{type.Name}.{method.Name.ToLowerFirstChar()}"""
43 | }.Concat(method.Parameters.Select(p => p.Name));
44 |
45 | if (method.ReturnType.IsDefault())
46 | {
47 | this.Line($@"await JSRuntime.Current.InvokeAsync({arguments.Join(", ")}).ConfigureAwait(false);");
48 | }
49 | else
50 | {
51 | this.Line($@"return JSRuntime.Current.InvokeAsync<{method.ReturnType.ToCSharpType()}>({arguments.Join(", ")});");
52 | }
53 |
54 | this.Unbrace();
55 | }
56 |
57 | this.Unbrace();
58 | }
59 |
60 | this.Unbrace();
61 | this.Unbrace();
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Interop/Models.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Interop
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Xml.Serialization;
10 | using SmallBasic.Utilities;
11 |
12 | public static class InteropTypeExtensions
13 | {
14 | public static string ToCSharpType(this string type)
15 | {
16 | switch (type)
17 | {
18 | // Native Types
19 | case "number": return "decimal";
20 | case "string": return "string";
21 | case "boolean": return "bool";
22 |
23 | // Blazor Types
24 | case "HTMLElement": return "ElementRef";
25 |
26 | // Monaco Types
27 | case "monaco.languages.CompletionItem": return "MonacoCompletionItem";
28 | case "monaco.IPosition": return "MonacoPosition";
29 | case "monaco.IRange": return "MonacoRange";
30 |
31 | case string array when array.EndsWith("[]", StringComparison.InvariantCulture):
32 | return ToCSharpType(array.RemoveSuffix("[]")) + "[]";
33 |
34 | default: throw ExceptionUtilities.UnexpectedValue(type);
35 | }
36 | }
37 | }
38 |
39 | public sealed class Parameter
40 | {
41 | [XmlAttribute]
42 | public string Name { get; set; }
43 |
44 | [XmlAttribute]
45 | public string Type { get; set; }
46 | }
47 |
48 | public sealed class Method
49 | {
50 | [XmlAttribute]
51 | public string Name { get; set; }
52 |
53 | [XmlAttribute]
54 | public string ReturnType { get; set; }
55 |
56 | [XmlArray(nameof(Parameters))]
57 | [XmlArrayItem(typeof(Parameter))]
58 | public List Parameters { get; set; }
59 | }
60 |
61 | public sealed class InteropType
62 | {
63 | [XmlAttribute]
64 | public string Name { get; set; }
65 |
66 | [XmlArray(nameof(Methods))]
67 | [XmlArrayItem(typeof(Method))]
68 | public List Methods { get; set; }
69 | }
70 |
71 | [XmlRoot("root")]
72 | public sealed class InteropTypeCollection : List
73 | {
74 | }
75 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Parsing/Models.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Parsing
6 | {
7 | using System.Collections.Generic;
8 | using System.Xml.Serialization;
9 |
10 | public sealed class Member
11 | {
12 | [XmlAttribute]
13 | public string Name { get; set; }
14 |
15 | [XmlAttribute]
16 | public string Type { get; set; }
17 |
18 | [XmlAttribute]
19 | public bool IsOptional { get; set; }
20 |
21 | [XmlAttribute]
22 | public bool IsList { get; set; }
23 |
24 | [XmlAttribute]
25 | public string TokenKinds { get; set; }
26 | }
27 |
28 | public sealed class SyntaxNode
29 | {
30 | [XmlAttribute]
31 | public string Name { get; set; }
32 |
33 | [XmlAttribute]
34 | public string Inherits { get; set; }
35 |
36 | [XmlAttribute]
37 | public bool IsAbstract { get; set; }
38 |
39 | [XmlArray(nameof(Members))]
40 | [XmlArrayItem(typeof(Member))]
41 | public List Members { get; set; }
42 | }
43 |
44 | [XmlRoot("root")]
45 | public sealed class SyntaxNodeCollection : List
46 | {
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Globalization;
10 | using CommandLine;
11 |
12 | [Verb("convert", HelpText = "Converts a model file into a code file.")]
13 | public class ConvertVerb
14 | {
15 | [Option(longName: "task", Required = true, HelpText = "Task name to run")]
16 | public string TaskName { get; set; }
17 |
18 | [Option(longName: "input", Required = true, HelpText = "Path to input model file")]
19 | public string InputFile { get; set; }
20 |
21 | [Option(longName: "output", Required = true, HelpText = "Path to output code file")]
22 | public string OutputFile { get; set; }
23 | }
24 |
25 | public static class Program
26 | {
27 | public static int Main(string[] args) =>
28 | CommandLine.Parser.Default.ParseArguments(args).MapResult(
29 | (ConvertVerb verb) => FindAndRunTask(verb.TaskName, task => task.Execute(verb.InputFile, verb.OutputFile)),
30 | (IEnumerable errors) =>
31 | {
32 | foreach (var error in errors)
33 | {
34 | Console.Error.WriteLine(error.ToString());
35 | }
36 |
37 | return 1;
38 | });
39 |
40 | private static int FindAndRunTask(string taskName, Func then)
41 | {
42 | foreach (Type type in typeof(Program).Assembly.DefinedTypes)
43 | {
44 | if (type.Name.ToLower(CultureInfo.CurrentCulture) == taskName.Replace("-", string.Empty, StringComparison.CurrentCulture))
45 | {
46 | return then((TTask)Activator.CreateInstance(type));
47 | }
48 | }
49 |
50 | Console.Error.WriteLine($"Cannot find a task with name '{taskName}'.");
51 | return 1;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Scanning/GenerateTokenKinds.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Scanning
6 | {
7 | using System;
8 | using System.Linq;
9 | using SmallBasic.Utilities;
10 |
11 | public sealed class GenerateTokenKinds : BaseConverterTask
12 | {
13 | protected override void Generate(TokenKindCollection model)
14 | {
15 | this.Line("namespace SmallBasic.Compiler.Scanning");
16 | this.Brace();
17 |
18 | this.Line("using SmallBasic.Utilities;");
19 | this.Line("using SmallBasic.Utilities.Resources;");
20 | this.Blank();
21 |
22 | this.Line("internal enum TokenKind");
23 | this.Brace();
24 |
25 | foreach (var tokenKind in model)
26 | {
27 | this.Line($"{tokenKind.Name},");
28 | }
29 |
30 | this.Unbrace();
31 | this.Blank();
32 |
33 | this.Line("internal static partial class TokenKindExtensions");
34 | this.Brace();
35 |
36 | this.Line("public static string ToDisplayString(this TokenKind kind)");
37 | this.Brace();
38 |
39 | this.Line("switch (kind)");
40 | this.Brace();
41 |
42 | foreach (var tokenKind in model)
43 | {
44 | this.Line($"case TokenKind.{tokenKind.Name}: return {tokenKind.Display};");
45 | }
46 |
47 | this.Line("default: throw ExceptionUtilities.UnexpectedValue(kind);");
48 |
49 | this.Unbrace();
50 | this.Unbrace();
51 | this.Unbrace();
52 | this.Unbrace();
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Scanning/Models.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Generators.Scanning
6 | {
7 | using System.Collections.Generic;
8 | using System.Xml.Serialization;
9 |
10 | public sealed class TokenKind
11 | {
12 | [XmlAttribute]
13 | public string Name { get; set; }
14 |
15 | [XmlAttribute]
16 | public string Display { get; set; }
17 | }
18 |
19 | [XmlRoot("root")]
20 | public sealed class TokenKindCollection : List
21 | {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Generators/Scanning/TokenKinds.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Server/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Server
6 | {
7 | using System.Linq;
8 | using System.Net.Mime;
9 | using Microsoft.AspNetCore;
10 | using Microsoft.AspNetCore.Blazor.Server;
11 | using Microsoft.AspNetCore.Builder;
12 | using Microsoft.AspNetCore.Hosting;
13 | using Microsoft.AspNetCore.ResponseCompression;
14 | using Microsoft.Extensions.Configuration;
15 | using Microsoft.Extensions.DependencyInjection;
16 |
17 | public static class Program
18 | {
19 | public static void Main(string[] args)
20 | {
21 | var configuration = new ConfigurationBuilder()
22 | .AddCommandLine(args)
23 | .Build();
24 |
25 | WebHost.CreateDefaultBuilder(args)
26 | .UseConfiguration(configuration)
27 | .UseStartup()
28 | .Build()
29 | .Run();
30 | }
31 | }
32 |
33 | public class Startup
34 | {
35 | #pragma warning disable CA1801, CA1822
36 | public void ConfigureServices(IServiceCollection services)
37 | {
38 | services.AddResponseCompression(options =>
39 | {
40 | options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
41 | {
42 | MediaTypeNames.Application.Octet,
43 | WasmMediaTypeNames.Application.Wasm,
44 | });
45 | });
46 | }
47 |
48 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
49 | {
50 | app.UseResponseCompression();
51 |
52 | if (env.IsDevelopment())
53 | {
54 | app.UseDeveloperExceptionPage();
55 | }
56 |
57 | app.UseBlazor();
58 | }
59 | #pragma warning restore CA1801, CA1822
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Server/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:63223/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "SmallBasic.Server": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:63226/"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Source/SmallBasic.Server/SmallBasic.Server.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Tests/Compiler/ScanningTests.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Tests.Compiler
6 | {
7 | using SmallBasic.Compiler;
8 | using SmallBasic.Compiler.Diagnostics;
9 | using Xunit;
10 |
11 | public sealed class ScanningTests : IClassFixture
12 | {
13 | [Fact]
14 | public void ItReportsUnterminatedStringLiterals()
15 | {
16 | new SmallBasicCompilation(@"
17 | x = ""name").VerifyDiagnostics(
18 | // x = "name
19 | // ^^^^^
20 | // This string is missing its right double quotes.
21 | new Diagnostic(DiagnosticCode.UnterminatedStringLiteral, ((1, 4), (1, 8))));
22 | }
23 |
24 | [Fact]
25 | public void ItReportsMultipleUnterminatedStringLiterals()
26 | {
27 | new SmallBasicCompilation(@"
28 | x = ""name
29 | y = ""another").VerifyDiagnostics(
30 | // x = "name
31 | // ^^^^^
32 | // This string is missing its right double quotes.
33 | new Diagnostic(DiagnosticCode.UnterminatedStringLiteral, ((1, 4), (1, 8))),
34 | // y = "another
35 | // ^^^^^^^^
36 | // This string is missing its right double quotes.
37 | new Diagnostic(DiagnosticCode.UnterminatedStringLiteral, ((2, 4), (2, 11))));
38 | }
39 |
40 | [Fact]
41 | public void ItReportsUnrecognizedCharactersOnStartOfLine()
42 | {
43 | new SmallBasicCompilation(@"
44 | $").VerifyDiagnostics(
45 | // $
46 | // ^
47 | // I don't understand this character '$'.
48 | new Diagnostic(DiagnosticCode.UnrecognizedCharacter, ((1, 0), (1, 0)), "$"));
49 | }
50 |
51 | [Fact]
52 | public void ItReportsMultipleUnrecognizedCharacters()
53 | {
54 | new SmallBasicCompilation(@"
55 | x = ____^
56 | ok = ""value $ value""
57 | not_ok = 6 $
58 | ' $ still ok").VerifyDiagnostics(
59 | // x = ____^
60 | // ^
61 | // I don't understand this character '^'.
62 | new Diagnostic(DiagnosticCode.UnrecognizedCharacter, ((1, 8), (1, 8)), "^"),
63 | // not_ok = 6 $
64 | // ^
65 | // I don't understand this character '$'.
66 | new Diagnostic(DiagnosticCode.UnrecognizedCharacter, ((3, 11), (3, 11)), "$"));
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Tests/CultureFixture.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Tests
6 | {
7 | using System.Globalization;
8 |
9 | public class CultureFixture
10 | {
11 | public CultureFixture()
12 | {
13 | CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Tests/Runtime/ExpressionTests.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Tests.Runtime
6 | {
7 | using System.Threading.Tasks;
8 | using SmallBasic.Compiler;
9 | using Xunit;
10 |
11 | public sealed class ExpressionTests : IClassFixture
12 | {
13 | [Fact]
14 | public Task NumericStringsAreTreatedAsNumbers()
15 | {
16 | return new SmallBasicCompilation(@"
17 | x = ""1"" + 1
18 | y = 4 + ""-1""").VerifyLoggingRuntime(memoryContents: @"
19 | x = 2
20 | y = 3");
21 | }
22 |
23 | [Fact]
24 | public Task NumbersAreConcatenatedWithStrings()
25 | {
26 | return new SmallBasicCompilation(@"
27 | x = 200 + "","" + 100
28 | y = 300 + "", "" + 100").VerifyLoggingRuntime(memoryContents: @"
29 | x = 200,100
30 | y = 300, 100");
31 | }
32 |
33 | [Fact]
34 | public Task ItEvaluatesArrayAccess()
35 | {
36 | return new SmallBasicCompilation(@"
37 | ar[0] = ""first""
38 | ar[1][0] = ""second""
39 | ar[1][2] = ""third""
40 |
41 | found_first = ar[0]
42 | found_second = ar[1][2]
43 |
44 | not_found_ar = none[0]
45 | not_found_first = ar[4]
46 | not_found_second = ar[1][6]
47 | ").VerifyLoggingRuntime(memoryContents: @"
48 | ar = 0=first;1=0\=second\;2\=third\;;
49 | found_first = first
50 | found_second = third
51 | not_found_ar =
52 | not_found_first =
53 | not_found_second = ");
54 | }
55 |
56 | [Fact]
57 | public Task ItSupportsDBCSInStrings()
58 | {
59 | return new SmallBasicCompilation(@"
60 | TextWindow.WriteLine(""こんにちは!"")
61 | ").VerifyLoggingRuntime(expectedLog: @"
62 | TextWindow.WriteLine(data: 'こんにちは!')
63 | ");
64 | }
65 |
66 | [Fact]
67 | public Task ItSupportsDBCSInIdentifiers()
68 | {
69 | return new SmallBasicCompilation(@"
70 | サブ()
71 | TextWindow.WriteLine(変数)
72 | Goto ラベル
73 |
74 | Sub サブ
75 | 変数 = 5
76 | EndSub
77 |
78 | TextWindow.WriteLine(""should be skipped"")
79 | ラベル:
80 | ").VerifyLoggingRuntime(expectedLog: @"
81 | TextWindow.WriteLine(data: '5')
82 | ");
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Tests/Runtime/RuntimeAnalysisTests.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Tests.Runtime
6 | {
7 | using FluentAssertions;
8 | using SmallBasic.Compiler;
9 | using SmallBasic.Compiler.Binding;
10 | using Xunit;
11 |
12 | public sealed class RuntimeAnalysisTests : IClassFixture
13 | {
14 | [Fact]
15 | public void ItDoesNotUseGraphicsWindowWhenNotNeeded()
16 | {
17 | var compilation = new SmallBasicCompilation("TextWindow.WriteLine(5)");
18 | compilation.Analysis.UsesTextWindow.Should().Be(true);
19 | compilation.Analysis.UsesGraphicsWindow.Should().Be(false);
20 | }
21 |
22 | [Fact]
23 | public void ItUsesGraphicsWindowWhenNeeded()
24 | {
25 | var compilation = new SmallBasicCompilation("GraphicsWindow.Clear()");
26 | compilation.Analysis.UsesTextWindow.Should().Be(false);
27 | compilation.Analysis.UsesGraphicsWindow.Should().Be(true);
28 | }
29 |
30 | [Fact]
31 | public void ItUsesTextWindowWhenNothingIsNeeded()
32 | {
33 | var compilation = new SmallBasicCompilation("x = 1");
34 | compilation.Analysis.UsesTextWindow.Should().Be(true);
35 | compilation.Analysis.UsesGraphicsWindow.Should().Be(false);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Tests/SmallBasic.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Utilities/Bridge/ImageListBridgeModels.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Utilities.Bridge
6 | {
7 | public static class ImageListBridgeModels
8 | {
9 | public sealed class ImageData
10 | {
11 | public ImageData()
12 | {
13 | }
14 |
15 | public ImageData(decimal width, decimal height, string base64Contents)
16 | {
17 | this.Width = width;
18 | this.Height = height;
19 | this.Base64Contents = base64Contents;
20 | }
21 |
22 | public decimal Width { get; set; }
23 |
24 | public decimal Height { get; set; }
25 |
26 | public string Base64Contents { get; set; }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Utilities/ExceptionUtilities.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Utilities
6 | {
7 | using System;
8 |
9 | public static class ExceptionUtilities
10 | {
11 | public static InvalidOperationException UnexpectedValue(TValue value)
12 | {
13 | return new InvalidOperationException($"Unexpected value '{value}' of type '{typeof(TValue).FullName}'");
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Utilities/Extensions/ObjectExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Utilities
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Globalization;
10 |
11 | public static class ObjectExtensions
12 | {
13 | #pragma warning disable SB1002 // Use IsDefault Helper
14 | public static bool IsDefault(this object value) => ReferenceEquals(value, default);
15 | #pragma warning restore SB1002 // Use IsDefault Helper
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Utilities/Extensions/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed under the MIT License. See LICENSE file in the project root for license information.
3 | //
4 |
5 | namespace SmallBasic.Utilities
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Globalization;
10 |
11 | public static class StringExtensions
12 | {
13 | public static string Join(this IEnumerable enumerable, string separator = "") => string.Join(separator, enumerable);
14 |
15 | public static string ToLowerFirstChar(this string value) => char.ToLowerInvariant(value[0]) + value.Substring(1);
16 |
17 | public static string RemovePrefix(this string value, string prefix)
18 | {
19 | if (!value.StartsWith(prefix, StringComparison.CurrentCulture))
20 | {
21 | throw new ArgumentException($"Value '{value}' does not start with prefix '{prefix}'.");
22 | }
23 |
24 | return value.Substring(prefix.Length);
25 | }
26 |
27 | public static string RemoveSuffix(this string value, string suffix)
28 | {
29 | if (!value.EndsWith(suffix, StringComparison.CurrentCulture))
30 | {
31 | throw new ArgumentException($"Value '{value}' does not end with suffix '{suffix}'.");
32 | }
33 |
34 | return value.Substring(0, value.Length - suffix.Length);
35 | }
36 |
37 | public static string ToDisplayString(this string value) => value;
38 |
39 | public static string ToDisplayString(this char value) => value.ToString(CultureInfo.CurrentCulture);
40 |
41 | public static string ToDisplayString(this int value) => value.ToString(CultureInfo.CurrentCulture);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Source/SmallBasic.Utilities/SmallBasic.Utilities.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 | PublicResXFileCodeGenerator
10 | DiagnosticsResources.Designer.cs
11 |
12 |
13 | PublicResXFileCodeGenerator
14 | EditorResources.Designer.cs
15 |
16 |
17 | PublicResXFileCodeGenerator
18 | EditorResources.Designer.cs
19 |
20 |
21 | PublicResXFileCodeGenerator
22 | LibrariesResources.Designer.cs
23 |
24 |
25 | PublicResXFileCodeGenerator
26 | TokenKindsResources.Designer.cs
27 |
28 |
29 |
30 |
31 |
32 | True
33 | True
34 | DiagnosticsResources.resx
35 |
36 |
37 | True
38 | True
39 | EditorResources.resx
40 |
41 |
42 | True
43 | True
44 | EditorResources.resx
45 |
46 |
47 | True
48 | True
49 | LibrariesResources.resx
50 |
51 |
52 | True
53 | True
54 | TokenKindsResources.resx
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Source/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
3 | "settings": {
4 | "documentationRules": {
5 | "companyName": "MIT License",
6 | "copyrightText": "Licensed under the MIT License. See LICENSE file in the project root for license information."
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "2.1.816"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------