From 48e8bf97fb9b12c223451a7f1e573972ca994f45 Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Thu, 16 Jun 2022 17:37:07 +0200 Subject: [PATCH] :sparkles: --- README.md | 48 ++--- centvrion/ast_nodes.py | 2 +- centvrion/lexer.py | 3 +- centvrion/parser.py | 199 +++++++++--------- tests/fib.cent | 10 +- tests/guessing.cent | 17 ++ vscode-extension/.vscodeignore | 4 + vscode-extension/CHANGELOG.md | 9 + vscode-extension/README.md | 65 ++++++ vscode-extension/language-configuration.json | 30 +++ vscode-extension/package.json | 25 +++ .../syntaxes/cent.tmLanguage.json | 83 ++++++++ vscode-extension/vsc-extension-quickstart.md | 29 +++ 13 files changed, 397 insertions(+), 127 deletions(-) create mode 100644 tests/guessing.cent create mode 100644 vscode-extension/.vscodeignore create mode 100644 vscode-extension/CHANGELOG.md create mode 100644 vscode-extension/README.md create mode 100644 vscode-extension/language-configuration.json create mode 100644 vscode-extension/package.json create mode 100644 vscode-extension/syntaxes/cent.tmLanguage.json create mode 100644 vscode-extension/vsc-extension-quickstart.md diff --git a/README.md b/README.md index 7812ad0..97c8fae 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ DICE x ### Recursive Fibonacci number function ``` -DEFINI fib x VT { +DEFINI fib(x) VT { SI x EST NVLLVS TVNC { - REDI NVLLVS + REDI(NVLLVS) } ALVID SI x EST I TVNC { - REDI I + REDI(I) } ALVID { - REDI ((INVOCA fib (x-II)) + (INVOCA fib (x-I))) + REDI(INVOCA fib(x-II) + INVOCA fib(x-I)) } } ``` @@ -29,21 +29,21 @@ DEFINI fib x VT { ``` CVM FORS -DESIGNA correct VT FORTIS_NVMERVS I C +DESIGNA correct VT FORTIS_NVMERVS(I,C) DESIGNA gvess VT NVLLVS DVM FALSITAS FACE { - DESIGNA gvess VT AVDI_NVMERVS + DESIGNA gvess VT AVDI_NVMERVS() SI gvess MINVS correct TVNC { - DICE "Too low!" + DICE("Too low!") } ALVID SI gvess PLVS correct TVNC { - DICE "Too high!" + DICE("Too high!") } ALVID { ERVMPE } } -DICE "You guessed correctly!" +DICE("You guessed correctly!") ``` ## Variables @@ -109,8 +109,8 @@ If-then statements are denoted with the keywords `SI` (if) and `TVNC` (then). Th ``` DESIGNA x VT VERITAS SI x TVNC { - DICE I - REDI NVLLLVS + DICE(I) + REDI(NVLLLVS) } DICE NVLLVS @@ -130,9 +130,9 @@ When using `SI`/`TVNC` statements, you can also use `ALVID` as an "else". ``` DESIGNA x VT VERITAS SI x TVNC { - DICE I + DICE(I) } ALVID { - DICE NVLLVS + DICE(NVLLVS) } > I @@ -143,11 +143,11 @@ SI x TVNC { ``` DESIGNA x VT II SI x EST I TVNC - DICE I + DICE(I) ALVID SI x EST II TVNC - DICE II + DICE(II) ALVID - DICE III + DICE(III) > II ``` @@ -160,11 +160,11 @@ The keyword `ET` can be used as a boolean "and". The keyword `AVT` can be used a DESIGNA x VT VERITAS DESIGNA y VT FALSITAS SI x ET y TVNC { - DICE I + DICE(I) } ALVID SI x AVT y TVNC { - DICE II + DICE(II) } ALVID { - DICE III + DICE(III) } > II @@ -178,7 +178,7 @@ DESIGNA x VT NVLLVS DONICVM y VT NVLLVS VSQVE X FACE { DESIGNA x VT x + y } -DICE x +DICE(x) > XLV ``` @@ -189,7 +189,7 @@ DESIGNA x VT NVLLVS DVM x PLVS X FACE { DESIGNA x VT x+I } -DICE x +DICE(x) > XI ``` @@ -198,7 +198,7 @@ DICE x ``` DESIGNA x VT [I, II, III, IV, V] PER y IN x FACE { - DICE y + DICE(y) } > I @@ -215,10 +215,10 @@ Calling a function is done with the `INVOCA` keyword. ``` DEFINI square x VT { - REDI (x*x) + REDI(x*x) } -DICE (INVOCA square XI) +DICE(INVOCA square(XI)) > CXXI ``` diff --git a/centvrion/ast_nodes.py b/centvrion/ast_nodes.py index a429361..1c80e4a 100644 --- a/centvrion/ast_nodes.py +++ b/centvrion/ast_nodes.py @@ -50,7 +50,7 @@ def num_to_int(n, m): nums = [single_num_to_int(i, m) for i in chars] new_nums = nums.copy() for x, num in enumerate(nums[:-3]): - if all(num == nums[x+i] for i in range(0,3)): + if all(num == nums[x+i] for i in range(0,4)): raise Exception(n, "is not a valid roman numeral") while True: diff --git a/centvrion/lexer.py b/centvrion/lexer.py index 0bdeb49..dbbba44 100644 --- a/centvrion/lexer.py +++ b/centvrion/lexer.py @@ -58,7 +58,8 @@ symbol_tokens = [ ("SYMBOL_PLUS", r"\+"), ("SYMBOL_MINUS", r"\-"), ("SYMBOL_TIMES", r"\*"), - ("SYMBOL_DIVIDE", r"\/") + ("SYMBOL_DIVIDE", r"\/"), + ("SYMBOL_COMMA", r",") ] whitespace_tokens = [ diff --git a/centvrion/parser.py b/centvrion/parser.py index 90a26b4..77e1f61 100644 --- a/centvrion/parser.py +++ b/centvrion/parser.py @@ -17,27 +17,24 @@ class Parser(): ) def parse(self, tokens_input) -> ast_nodes.BaseBox: - @self.pg.production('program : opt_newline opt_module_calls opt_newline opt_statements opt_newline') + + # Top-level program stuff + @self.pg.production('program : opt_newline module_calls statement_list') def program(tokens): - return ast_nodes.Program(tokens[1], tokens[3]) + return ast_nodes.Program(tokens[1], tokens[2]) @self.pg.production('opt_newline : ') @self.pg.production('opt_newline : NEWLINE') def opt_newline(_): return None - @self.pg.production('opt_module_calls : ') - @self.pg.production('opt_module_calls : module_calls') - def opt_module_calls(calls): - if len(calls) == 0: - return calls - else: - return calls[0] - - @self.pg.production('module_calls : module_call NEWLINE ') + # Module calls + @self.pg.production('module_calls : ') @self.pg.production('module_calls : module_call NEWLINE module_calls') def module_calls(calls): - if len(calls) == 2: + if len(calls) == 0: + return [] + elif len(calls) == 1: return [calls[0]] else: return [calls[0]] + calls[2] @@ -47,17 +44,14 @@ class Parser(): return ast_nodes.ModuleCall(tokens[1].value) - @self.pg.production('opt_statements : ') - @self.pg.production('opt_statements : statements') - def opt_statements(calls): - if len(calls) == 0: - return calls - else: - return calls[0] + # Statements + @self.pg.production('statements : opt_newline statement_list') + def statements(tokens): + return tokens[1] - @self.pg.production('statements : statement NEWLINE ') - @self.pg.production('statements : statement NEWLINE statements') - def statements(calls): + @self.pg.production('statement_list : statement opt_newline') + @self.pg.production('statement_list : statement NEWLINE statement_list') + def statement_list(calls): if len(calls) == 2: return [calls[0]] else: @@ -71,33 +65,77 @@ class Parser(): def statement_expression(tokens): return ast_nodes.ExpressionStatement(tokens[0]) - @self.pg.production('expressions : ') - @self.pg.production('expressions : expression expressions') - def expressions(calls): - if len(calls) == 0: - return [] - else: - return [calls[0]] + calls[1] + @self.pg.production('statement : KEYWORD_DEFINI id ids KEYWORD_VT SYMBOL_LCURL statements SYMBOL_RCURL') + def defini(tokens): + return ast_nodes.Defini(tokens[1], tokens[2], tokens[5]) - @self.pg.production('ids : ') - @self.pg.production('ids : id ids') - def ids(calls): - if len(calls) == 0: - return [] + @self.pg.production('statement : KEYWORD_REDI expressions') + def redi(tokens): + return ast_nodes.Redi(tokens[1]) + + @self.pg.production('statement : per_statement') + @self.pg.production('statement : dum_statement') + @self.pg.production('statement : donicum_statement') + @self.pg.production('statement : si_statement') + def nested_statements(tokens): + return tokens[0] + + @self.pg.production('statement : KEYWORD_ERVMPE') + def erumpe(_): + return ast_nodes.Erumpe() + + @self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL') + @self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL aluid_statement') + def si_statement(tokens): + if len(tokens) == 7: + return ast_nodes.SiStatement(tokens[1], tokens[4], tokens[6]) else: - return [calls[0]] + calls[1] + return ast_nodes.SiStatement(tokens[1], tokens[4], None) + + @self.pg.production('aluid_statement : KEYWORD_ALVID si_statement') + def aluid_si(tokens): + return [tokens[1]] + + @self.pg.production('aluid_statement : KEYWORD_ALVID SYMBOL_LCURL statements SYMBOL_RCURL') + def aluid(tokens): + return tokens[2] + + @self.pg.production('dum_statement : KEYWORD_DVM expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL') + def dum(tokens): + return ast_nodes.DumStatement(tokens[1], tokens[4]) + + @self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL') + def per(tokens): + return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6]) + + @self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL') + def donicum(tokens): + range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5]) + return ast_nodes.PerStatement(range_array, tokens[1], tokens[8]) + + # expressions + @self.pg.production('expressions : SYMBOL_LPARENS expression_list') + def expressions(tokens): + return tokens[1] + + @self.pg.production('expression_list : SYMBOL_RPARENS') + @self.pg.production('expression_list : expression SYMBOL_RPARENS') + @self.pg.production('expression_list : expression SYMBOL_COMMA expression_list') + def expression_list(calls): + if len(calls) == 1: + return [] + elif len(calls) == 2: + return [calls[0]] + else: + return [calls[0]] + calls[2] @self.pg.production('expression : id') def expression_id(tokens): return tokens[0] - @self.pg.production('statement : KEYWORD_DEFINI id ids KEYWORD_VT SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL') - def defini(tokens): - return ast_nodes.Defini(tokens[1], tokens[2], tokens[6]) - - @self.pg.production('statement : KEYWORD_REDI expressions') - def redi(tokens): - return ast_nodes.Redi(tokens[1]) + @self.pg.production('expression : BUILTIN expressions') + def expression_builtin(tokens): + return ast_nodes.BuiltIn(tokens[0].value, tokens[1]) @self.pg.production('expression : DATA_STRING') def expression_string(tokens): @@ -126,61 +164,10 @@ class Parser(): def binop(tokens): return ast_nodes.BinOp(tokens[0], tokens[2], tokens[1].name) - @self.pg.production('expression : BUILTIN expressions') - def expression_builtin(tokens): - return ast_nodes.BuiltIn(tokens[0].value, tokens[1]) - - @self.pg.production("id : ID") - def id_expression(tokens): - return ast_nodes.ID(tokens[0].value) - @self.pg.production('expression : KEYWORD_INVOCA id expressions') def invoca(tokens): return ast_nodes.Invoca(tokens[1], tokens[2]) - @self.pg.production('statement : si_statement') - def si_statement(tokens): - return tokens[0] - - @self.pg.production('statement : per_statement') - @self.pg.production('statement : dum_statement') - @self.pg.production('statement : donicum_statement') - def loops(tokens): - return tokens[0] - - @self.pg.production('statement : KEYWORD_ERVMPE') - def erumpe(_): - return ast_nodes.Erumpe() - - @self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL opt_newline aluid_statement') - def si(tokens): - return ast_nodes.SiStatement(tokens[1], tokens[5], tokens[9]) - - @self.pg.production('dum_statement : KEYWORD_DVM expression KEYWORD_FACE SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL') - def dum(tokens): - return ast_nodes.DumStatement(tokens[1], tokens[5]) - - @self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL') - def per(tokens): - return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[7]) - - @self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL') - def donicum(tokens): - range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5]) - return ast_nodes.PerStatement(range_array, tokens[1], tokens[9]) - - @self.pg.production('aluid_statement : ') - def aluid_empty(_): - return None - - @self.pg.production('aluid_statement : KEYWORD_ALVID si_statement') - def aluid_si(tokens): - return [tokens[1]] - - @self.pg.production('aluid_statement : KEYWORD_ALVID SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL aluid_statement') - def aluid(tokens): - return tokens[3] - @self.pg.production('expression : SYMBOL_LPARENS expression SYMBOL_RPARENS') def parens(tokens): return tokens[1] @@ -193,9 +180,29 @@ class Parser(): def range_array(tokens): return ast_nodes.DataRangeArray(tokens[1], tokens[3]) - # @self.pg.error - # def error_handle(token): - # raise ValueError(token) + # ids + @self.pg.production('ids : SYMBOL_LPARENS id_list') + def ids(tokens): + return tokens[1] + + @self.pg.production('id_list : SYMBOL_RPARENS') + @self.pg.production('id_list : id SYMBOL_RPARENS') + @self.pg.production('id_list : id SYMBOL_COMMA id_list') + def id_list(calls): + if len(calls) == 1: + return [] + elif len(calls) == 2: + return [calls[0]] + else: + return [calls[0]] + calls[2] + + @self.pg.production("id : ID") + def id_expression(tokens): + return ast_nodes.ID(tokens[0].value) + + @self.pg.error + def error_handle(token): + raise Exception(token.name, token.value, token.source_pos) parser = self.pg.build() return parser.parse(tokens_input) diff --git a/tests/fib.cent b/tests/fib.cent index a31cf0b..c10cadd 100644 --- a/tests/fib.cent +++ b/tests/fib.cent @@ -1,11 +1,11 @@ -DEFINI fib x VT { +DEFINI fib(x) VT { SI x EST NVLLVS TVNC { - REDI NVLLVS + REDI(NVLLVS) } ALVID SI x EST I TVNC { - REDI I + REDI(I) } ALVID { - REDI ((INVOCA fib (x-II)) + (INVOCA fib (x-I))) + REDI(INVOCA fib(x-II) + INVOCA fib(x-I)) } } -DICE INVOCA fib (AVDI_NVMERVS) \ No newline at end of file +DICE(INVOCA fib(AVDI_NVMERVS())) diff --git a/tests/guessing.cent b/tests/guessing.cent new file mode 100644 index 0000000..4dc8dc1 --- /dev/null +++ b/tests/guessing.cent @@ -0,0 +1,17 @@ +CVM FORS + +DESIGNA correct VT FORTIS_NVMERVS(I,C) +DESIGNA gvess VT NVLLVS + +DVM FALSITAS FACE { + DESIGNA gvess VT AVDI_NVMERVS() + SI gvess MINVS correct TVNC { + DICE("Too low!") + } ALVID SI gvess PLVS correct TVNC { + DICE("Too high!") + } ALVID { + ERVMPE + } +} + +DICE("You guessed correctly!") \ No newline at end of file diff --git a/vscode-extension/.vscodeignore b/vscode-extension/.vscodeignore new file mode 100644 index 0000000..f369b5e --- /dev/null +++ b/vscode-extension/.vscodeignore @@ -0,0 +1,4 @@ +.vscode/** +.vscode-test/** +.gitignore +vsc-extension-quickstart.md diff --git a/vscode-extension/CHANGELOG.md b/vscode-extension/CHANGELOG.md new file mode 100644 index 0000000..4fd6f3f --- /dev/null +++ b/vscode-extension/CHANGELOG.md @@ -0,0 +1,9 @@ +# Change Log + +All notable changes to the "centvrion" extension will be documented in this file. + +Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. + +## [Unreleased] + +- Initial release \ No newline at end of file diff --git a/vscode-extension/README.md b/vscode-extension/README.md new file mode 100644 index 0000000..230130b --- /dev/null +++ b/vscode-extension/README.md @@ -0,0 +1,65 @@ +# centvrion README + +This is the README for your extension "centvrion". After writing up a brief description, we recommend including the following sections. + +## Features + +Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. + +For example if there is an image subfolder under your extension project workspace: + +\!\[feature X\]\(images/feature-x.png\) + +> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. + +## Requirements + +If you have any requirements or dependencies, add a section describing those and how to install and configure them. + +## Extension Settings + +Include if your extension adds any VS Code settings through the `contributes.configuration` extension point. + +For example: + +This extension contributes the following settings: + +* `myExtension.enable`: enable/disable this extension +* `myExtension.thing`: set to `blah` to do something + +## Known Issues + +Calling out known issues can help limit users opening duplicate issues against your extension. + +## Release Notes + +Users appreciate release notes as you update your extension. + +### 1.0.0 + +Initial release of ... + +### 1.0.1 + +Fixed issue #. + +### 1.1.0 + +Added features X, Y, and Z. + +----------------------------------------------------------------------------------------------------------- + +## Working with Markdown + +**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: + +* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux) +* Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux) +* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets + +### For more information + +* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) +* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) + +**Enjoy!** diff --git a/vscode-extension/language-configuration.json b/vscode-extension/language-configuration.json new file mode 100644 index 0000000..8f162a0 --- /dev/null +++ b/vscode-extension/language-configuration.json @@ -0,0 +1,30 @@ +{ + "comments": { + // symbol used for single line comment. Remove this entry if your language does not support line comments + "lineComment": "//", + // symbols used for start and end a block comment. Remove this entry if your language does not support block comments + "blockComment": [ "/*", "*/" ] + }, + // symbols used as brackets + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ], + // symbols that can be used to surround a selection + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ] +} \ No newline at end of file diff --git a/vscode-extension/package.json b/vscode-extension/package.json new file mode 100644 index 0000000..be0d62b --- /dev/null +++ b/vscode-extension/package.json @@ -0,0 +1,25 @@ +{ + "name": "centvrion", + "displayName": "centvrion", + "description": "", + "version": "0.0.1", + "engines": { + "vscode": "^1.68.0" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [{ + "id": "cent", + "aliases": ["CENTVRION", "cent"], + "extensions": [".cent"], + "configuration": "./language-configuration.json" + }], + "grammars": [{ + "language": "cent", + "scopeName": "source.cent", + "path": "./syntaxes/cent.tmLanguage.json" + }] + } +} \ No newline at end of file diff --git a/vscode-extension/syntaxes/cent.tmLanguage.json b/vscode-extension/syntaxes/cent.tmLanguage.json new file mode 100644 index 0000000..9affe61 --- /dev/null +++ b/vscode-extension/syntaxes/cent.tmLanguage.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "CENTVRION", + "patterns": [ + { + "include": "#strings" + }, + { + "include": "#keywords" + }, + { + "include": "#builtins" + }, + { + "include": "#constants" + }, + { + "include": "#variables" + } + ], + "repository": { + "keywords": { + "patterns": [ + { + "name": "keyword.control.cent", + "match": "\\b(ALVID|DEFINI|DESIGNA|DONICVM|DVM|ERVMPE|FACE|INVOCA|IN|PER|SI|TVNC|VSQVE|VT|CVM)\\b" + }, + { + "name": "keyword.operator.comparison.cent", + "match": "\\b(EST|MINVS|PLVS)\\b" + }, + { + "name": "keyword.operator.arithmetic.cent", + "match": "(\\*|\\+|-|/)" + } + ] + }, + "builtins": { + "patterns": [ + { + "name": "support.function.builtin.cent", + "match": "\\b(AVDI_NVMERVS|AVDI|DICE|FORTIS_NVMERVS|FORTIS_ELECTIONIS|LONGITVDO|REDI)\\b" + } + ] + }, + "constants": { + "patterns": [ + { + "name": "constant.numeric.roman.cent", + "match": "\\b[IVXLCDM]+\\b" + }, + { + "name": "constant.language.roman.cent", + "match": "\\b(VERITAS|FALSITAS)\\b" + }, + { + "name": "constant.numeric.nullus.cent", + "match": "\\bNVLLVS\\b" + } + ] + }, + "strings": { + "name": "string.quoted.double.cent", + "begin": "\"", + "end": "\"", + "patterns": [ + { + "name": "constant.character.escape.cent", + "match": "\\\\." + } + ] + }, + "variables": { + "patterns": [ + { + "name": "variable.language.cent", + "match": "\\b[abcdefghiklmnopqrstvxyz_]+\\b" + } + ] + } + }, + "scopeName": "source.cent" +} \ No newline at end of file diff --git a/vscode-extension/vsc-extension-quickstart.md b/vscode-extension/vsc-extension-quickstart.md new file mode 100644 index 0000000..105cc93 --- /dev/null +++ b/vscode-extension/vsc-extension-quickstart.md @@ -0,0 +1,29 @@ +# Welcome to your VS Code Extension + +## What's in the folder + +* This folder contains all of the files necessary for your extension. +* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension. +* `syntaxes/cent.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization. +* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets. + +## Get up and running straight away + +* Make sure the language configuration settings in `language-configuration.json` are accurate. +* Press `F5` to open a new window with your extension loaded. +* Create a new file with a file name suffix matching your language. +* Verify that syntax highlighting works and that the language configuration settings are working. + +## Make changes + +* You can relaunch the extension from the debug toolbar after making changes to the files listed above. +* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. + +## Add more language features + +* To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs + +## Install your extension + +* To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. +* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.