Skip to content

Latest commit

 

History

History
1042 lines (708 loc) · 38.4 KB

DOC.md

File metadata and controls

1042 lines (708 loc) · 38.4 KB

Links to Items within this Document

Dev Notes

Webpack Notes

These are mainly notes on the fields within webpack.config.js.

  • entry: these are the various entries into the dependency graph that webpack uses to connect to other dependencies. Any new entry point needs to be added here. This is mostly for adding individual JS scripts since the rest of our code is added by the entry for index.ts. If you want to add a new script, you can just add the path to it inside the array under app. Make sure to not add any scripts under a NEW entry. This will cause webpack to bundle multiple times which will end up running the code multiple times.

  • output: this describes the path to the bundles generated by each entry point. If you want the bundles to be served from some other file or to rename them, this is the place to do it.

  • module: rules:: this lists how various file types are transpiled to code that can be ran by the browser. That's what the loaders are for. After adding a loader here, you need to specify what types of files it processes and then just install it through npm.




Notifications Documentation

Notification.ts and NotificationController.ts

These two are pretty well documented inside the code. Notification.ts provides class definitions for all warnings that we have in the editor. This includes the draft mode. It also contains the definition for ConstructHighlight an object that can be used to highlight a piece of code within the editor.

ErrorMsgGenerator.ts

This contains the old strings used for warning messages. Most of these are not used anymore, but they were left in the code in case some of the text can be used in the future.

Suggestion Controller Documentation

Overall the way this works is you create a Menu object which holds MenuOption objects which perform some action when selected. Menu objects can be nested in a tree to provided nested menu functionality. MenuController is a singleton controlling all existing menus. It keeps track of open/closed menus as well as the currently focused option within each open menu.

If you want to create a menu you should use MenuController, you should not have to interact with Menu and MenuOption directly. So before modifying those, check if MenuController already provides the functionality you want and if it does not, it is likely that it should be added there rather than the menus and the options.

Module has a MenuController and that is how our code instantiates these menus. It calls buldSingleLevelMenu() each time a menu needs to be opened. If you want to see exactly how a menu is created by the calling code in various contexts, just search for usages of buildSingleLevelMenu().


Menu

This is the main class that provides the functionality for our autocomplete and other menus. It can be used to create both a single-level and a tree menu. This only depends on how the menu is built and the options are connected. This class also grants access to the DOM object of the menu as well as methods for manipulating it.

Attributes

  • options: MenuOption[]:
    List of MenuOption objects that are displayed by the menu.
  • editCodeActionsOptions: EditCodeAction[]:
    List of actions from which this menus options are created. These actions' performAction methods are executed when their corresponding option is selected in the menu.
  • openedLinkOptionIndex: number:
    Index into this.options of an option that is currently focused and links to another menu.
  • children: Menu[]:
    Stores all child menus of this menu. This allows the menus to be organized in a tree. This array should only be used to contain the next level of the tree, not all descendants of this menu.
  • parentMenu: Menu:
    The parent menu of this menu. The tree above it in the tree of menus. null if the current menu is a tree root.
  • htmlElement: HTMLDivElement:
    The menu DOM element to which option DOM elements are attached.
  • static menuCount: number:
  • static idPrefix: string:
    Used for numbering menus with unique IDs in the DOM in case the menus form a tree.

Behaviours

1. constructor(options: Map<string, Function>)

Summary:

Parameters:

  • options:
    This map is expected to contain a mapping from option name to the action that is to be executed when the option is selected.


2. closeChildren(): void

Summary:

Close all open descendants of this menu if it has any.

3. indentChildren(offset: number = 0): void

Summary:

Indent all children of this menu according to their depth. This method visualizes the tree structure of the nested menus in the browser.

Parameters:

  • offset:
    Indentation value in px. All indents are made from left to right. If offset > 0 this will be the initial offset used and the menus on the second level will appear that many px away from their parent. All subsequent menus will add to this offset. Keep this set to 0 if you want menus on each level to use their width as the indentation amount.


4. linkMenuThroughOption(child: Menu, optionInParent: string): void

Summary:

Link this and child together in a parent-child relationship such that when optionInParent is focused, it opens child. optionInParent is a string and so its value is searched for inside the options array of this menu. This is for ease of use so that you don't need access to the menu option object itself when linking menus.

Parameters:

  • child:
    The menu to be opened when optionInParent is focused in this menu.
  • optionInParent:
    The text of the option to be used to link the two menus.


5. removeChild(child: Menu): void

Summary:

Remove a given child from the menu.

Parameters:

  • child:
    Child to be removed.


6. static collapseSingleLinkMenus(root: Menu): void

Summary:

Remove menu's that only serve as links (have a single option that links to another menu). In the example below option3 is not really necessary. These are the kinds of options this method will remove.

option1 --> option3 --> option4
option2

Will become

option1 --> option4
option2

Parameters:

  • root: the root of the menu structure


7. removeEmptyChildren(): void

Summary:

Remove all menus that are either completely empty or have options that don't perform any valid action. This is for cases such as the one below:

option1 --> option3 --> Empty Menu
option2     option4

Will become:

option1 --> option4
option2


8. open(): void

Summary:

Display this menu in the editor.

9. close(): void

Summary:

Hide this menu in the editor.

10. isOpen(): boolean

Summary:

Return whether this menu is currently visible in the editor or not.

11. setChildMenus(menus: Menu[]): void

Summary:

Replace this menus children list with menus.

Parameters:

  • menus:
    New menus that will be the children of this menu.


12. addChildMenu(menu: Menu): void

Summary:

Add a single child to this menu's children and update the parent of menu to be this.

Parameters:

  • menu:
    Menu that will become the child of this.


13. removeFromDOM(): void

Summary:

Remove this menu from the DOM.

14. getOptionByText(optionText: string): MenuOption

Summary:

Return the menu option with matching optionText within this menu's options. undefined if no options is found to have the given text.

Parameters:

  • optionText:
    Option text to match options on.



MenuOption

Provides the definition of our menu options. This are placed within menu objects and are displayed as part of the menu in the editor. These offer functionality for linking options to other menus allowing the user code to nest menus.

Attributes

  • parentMenu: Menu:
    The menu within which this option is contained.
  • text: string:
    Display text of this option.
  • doc: ConstructDoc:
    Documentation object associated with this option.
  • htmlElement: HTMLDivElement:
    DOM element of this option.
  • selectAction: Function:
    Action performed when this option is selected, null if this option links to another menu.

Behaviours

1.

constructor(text: string = "Option Text",
        useInnerHTML: boolean = false,
        childMenu?: Menu,
        parentMenu?: Menu,
        doc?: ConstructDoc,
        selectAction?: Function,
        extraInformation?: string)

Summary:

Parameters:

  • text:
    Option text that will be used by the option.
  • useInnerHTML:
    Set to True if you want text to be treated as HTML by the option.
  • childMenu:
    The menu object that this option links to. Allows this option to open sub menus when focused.
  • parentMenu:
    The menu within which this option is contained.
  • doc:
    Documentation object associated with this option.
  • selectAction:
    Callback that runs when this option is clicked.
  • extraInformation:
    Tooltip that appears next to the option name in the menu.


2. select(): void

Summary:

Either runs this option's selectAction or opens the sub menu attached to this option

3. linkToChildMenu(child: Menu): void

Summary:

Add a menu that will be open when this option is focused.

Parameters:

  • child:
    Menu object representing the menu that will be opened when this option is focused.


4. attachToParentMenu(menu: Menu): void

Summary:

Attach this option to menu so that it is displayed as a potential selection in said menu.

Parameters:

  • menu:
    The menu that will contain this option.


5. hasChild(): boolean

Summary:

Return whether this option has a menu that it links to.

6. getChildMenu(): Menu

Summary:

Return the child object that is linked to by this option.

7. setFocus(): void

Summary:

Update the visuals of this option to indicate that it has been focused.

8 removeFocus(): void

Summary:

Update the visuals of this option to indicate that it is not focused.

9 removeFromDOM(): void

Summary:

Remove the DOM element of this option from the DOM. NOTE: This does not remove it from the menu that it was a part of on the backend. That has to be done manually.

10 setChildMenu(child: Menu): void

Summary:

Update the menu object that this option links to. The current menu that is being linked to, if there is one, will be replaced.

Parameters:

  • child:
    Menu to link to.



MenuController

This class provides the main control logic for creating and controlling a menu and its options. Some parts of this class are documented within the code so this doc contains only those parts that are not documented in the code.

Attributes

  • static suggestionOptionExtraInfo: string:

  • static optionElementClass: string:

  • static menuElementClass: string:

  • static optionTextElementClass: string:

  • static selectedOptionElementClass: string:
    These are all CSS class names used by the various elements of the menu.

  • module: Module:
    The global module instance of the entire program.

  • editor: Editor:
    The global editor instance of the entire program.

  • indexOfRootMenu: number:
    The index into menus indicating the location of the top-level menu. This is not necessarily always 0 for nested menus. It depends entirely on how it is constructed.

  • focusedMenuIndex: number:
    The index into menus of the currently open menu.

  • focusedOptionIndex: number:
    The index into this.menus[this.focusedMenuIndex].options indicating the location of the currently focused option within an open menu.

  • menus: Menu[]:
    The list of all menus currently controlled by this controller. Will usually contain a single element since we don't have nested menus anymore.


Behaviours

1. static getInstance(): MenuController

Summary:

MenuController is a singleton and this method should be used for obtaining its current instance. If not instance exists, a new one will be created.

2. setInstance(module: Module, editor: Editor): void

Summary:

Update the module and editor instances of the current MenuController instance.

Parameters:

  • module:
    Module object to use.
  • editor:
    Editor object to use.


3. removeMenus(): void

Summary:

Close and remove all menus from the MenuController (both backend and DOM removal). Completely clears the menus list.

4. isMenuOpen(): boolean

Summary:

Return whether the top-level menu of this controller is currently open and visible in the editor or not.

5. updateMenuArrayFromTree(root: Menu, isRoot: boolean): void

Summary:

Populate the menus list from a tree of menus.

Parameters:

  • root:
    The root of this menu.
  • isRoot:
    Whether root is the root of the overall menu tree. Should be false as long as root.parentMenu is not null.


6. updateMenuOptions(optionText: string): void

Summary:

Filter out options the text of which does not match optionText. Each menu has a list of edit actions originally associated with it. This function will filter those to only contain options whose text most closely matches optionText.

Parameters:

  • optionText:
    Current user input from the AutocompleteTkn associated with this menu.


7. updatePosition(pos: { left: number; top: number }): void

Summary:

Set the position of the menu to pos.

Parameters:

  • pos:
    (x, y) position of the top left corner of the menu within the viewport.


8. getNewMenuPosition(code: CodeConstruct): { left: number; top: number }

Summary:

Update the position of the menu according to changes in the associated AutocompleteTkn. This ensures the menu moves to the end of the AutocompleteTkn as the user types.

Parameters:

  • code: AutocompleteTkn or other CodeConstruct to which the menu is attached.



User Code Execution Documentation

To run the user code we are currently using Pyodide which enables us to run everything in the client's browser. Pyodide is loaded inside of index.html so if that ever needs to be updated just update the script tag inside of that file.

The two scripts responsible for actually working with Pyodide are load-pyodide.js and pyodide-controller.js. The former simply loads Pyodide and exports the loaded object. Note that this export is asynchronous and exports a Promise. See pyodide-controller.js for how to perform the corresponding import.

The user's code will only run if the following conditions are satisfied:

  1. There are no empty holes in the user's code.
  2. There are no unfinished autocompletes in the user's code.
  3. There are no open draft modes in the user's code

If one of the above conditions is not satisfied, the user will be notified through the console. NOTE: This does not protect from runtime errors completely. These are still possible and will be displayed in the console.



Setting Pyodide Options

Inside of load-pyodide.js there is a method loadPyodide() which accepts an options object. Here is where you would set any of the options from the Pyodide docs. The most useful ones are overriding the behaviours of stderr, stdin and stdout. You can also set where Pyodide is loaded from here.


Here is a sample:
loadPyodide({
   indexURL: "https://cdn.jsdelivr.net/pyodide/v0.18.0/full/",
   stdout: (text) => {
       addTextToConsole(text);
   },
})


Working with Pyodide

This is done in pyodide-controller.js. This script imports the Pyodide object loaded by load-pyodide.js and defines various useful functions for working with it. This module has one main anonymous function which contains the logic of using Pyodide. If you want to make any changes to the execution flow, here is the place. Here are some things that you might want to do with it:

  • Running Python Code:
    Simply call pyodideControler.runPython(). The first argument is a string with the code to be ran.

  • Load JS functions into the user's Python script:
    This can be done by simply adding the necessary functions to the jsModule object at the top of the script. This is already loaded into the Python script so all you have to do is use it inside the argument string to runPython(). See how the current input behaviour is modified for an example.

  • Good to Know:

    • If you want to add another script, don't forget to add it to the bundle within webpack.config.js.
    • The anonymous function is called immediately on script load.



Variable Controller Documentation

This object deals with most variable-related logic such as determining variable type on a given line, finding references to a given variable, working with variable reference buttons in the toolbox, etc... It also deals with the creation and management of the cascaded menu.

Behaviours

1. addVariableRefButton(assignmentStmt: VarAssignmentStmt)

Summary:

Create a button within the toolbox's User-Defined Variables region for referencing the variable created with assignmentStmt.

Parameters:

  • assignmentStmt:
    Definition of the variable from which the reference button can be created.


2. isVariableReferenceButton(buttonId: string): boolean

Summary:

Return whether the DOM element with the id buttonId is a variable reference button or not.

Parameters:

  • buttonId:
    DOM id to search the variable reference buttons for.


3. removeVariableRefButton(varId: string)

Summary:

Remove the variable reference button with a given id from the DOM and internal storage.

Parameters:

  • varId:
    id of the button to remove. Should be [VarAssignmentStmt Object].buttonId unless the id is known from somewhere else.


4. addWarningToVarRefs(varId: string, module: Module)

Summary:

Highlight all references to the variable with id varId and provide a textual warning saying that all assingments of this variable have actually been deleted and therefore the variable cannot be referenced anymore. Despite its name this method is only meant to be used SPECIFICALLY on variable references of variables that no longer exist.

Parameters:

  • varId:
    the id of the variable the references to which should be highlighted.
  • module:
    module objects passed in so that the method may access the notification system to create the warning.


5. getVariableButtons(): HTMLDivElement[]

Summary:

Return the list of all variable reference buttons that currently exist. Not all of these are necessarily shown in the toolbox since the toolbox displays them based on context and scope.

6. getVariableButton(varId: string): HTMLDivElement

Summary:

Return the button associated with the variable with a given varId (buttonId if this comes from a VarAssignmentStmt).

Parameters:

  • varId:
    id of the button to search for.


7. hideUnavailableVarsInToolbox(scope: Scope, lineNumber: number): void

Summary:

Remove all reference buttons for variables that cannot be referenced in the current context from the "User-Defined Variables" area in the toolbox.

Parameters:

  • scope:
    The scope of the line that the cursor is currently on.
  • lineNumber:
    The line number of the line that the cursor is currently on. Any variable initialized below this line are considered to be unavailable.


8. updateVarButtonWithType(buttonId: string, scope: Scope, lineNumber: number, identifier: string): void

Summary:

Updates the variable reference button with the given id with a text displaying the type the associated variable would have at line lineNumber.

Parameters:

  • buttonId:
    id of the button/variable to determine the type of.
  • scope:
    The scope within which to search for the variable.
  • lineNumber:
    The line number at which to stop the search.
  • identifier:
    The identifier of the variable.


9. getVariableTypeNearLine(scope: Scope, lineNumber: number, identifier: string, excludeCurrentLine: boolean = true): DataType

Summary:

Return the type of the variable with the given identifier within the given scope and above line lineNumber. Can optionally include line lineNumber in the search by setting excludeCurrentLine to false.

Parameters:

  • scope:
    The current scope.
  • lineNumber:
    The line number at which to stop the search.
  • identifier:
    Identifier of the variable being searched for.


10. getAllAssignmentsToVar(varId: string, module: Module): VarAssignmentStmt[]

Summary:

Return a list of absolutely all assignments to the variable with id varId within the AST.

Parameters:

  • varId:
    ID of the variable to search for.
  • module:
    Module holding the AST to search in.



Toolbox Documentation

Our toolbox functionality is mostly contained within toolbox.ts and toolbox.json. Except for the onClick actions of the buttons themselves, those are in a different place.


Toolbox.ts

This file stores various functions that operate on the toolbox.

1. addVariableReferenceButton(identifier: string, buttonId: string, events: EventStack): HTMLDivElement

Summary:

Add a button the toolbox that can be used for inserting variable references of a particular variable. Returns the button object. Note that the button is actually a DIV and not an HTMLButton.

Parameters:

  • identifier:
    The identifier of the variable referenced by this button.
  • buttonId:
    The id of the variable and the button itself.
  • events:
    The event stack used to notify our system that this button was clicked. This is required since toolbox button clicks do not get processed through event listeners. Instead they go through our custom processing in the event stack.


2. removeVariableReferenceButton(buttonId: string): void

Summary:

Remove a button used for referencing a variable. Could be used to remove any button in which case it should be renamed. Other buttons usually do not require removal however.

Parameters:

  • buttonId:
    The DOM id of the button to be removed.


3. addClassToButton(buttonId: string, className: string): void

Summary:

Add a CSS class className to a button within the toolbox with DOM id buttonId.

Parameters:

  • buttonId:
    The DOM id of the button.
  • className:
    Name of the CSS class to be attached to the button in the DOM.


4. removeClassFromButton(buttonId: string, className: string): void

Summary:

Remove a CSS class className, if it exists, from the button with id buttonId.

Parameters:

  • buttonId:
    Id of the button to remove the class from.
  • className:
    Name of the class to be removed.


5. updateButtonsVisualMode(insertionRecords: EditCodeAction[]): void

Summary:

Change the visual look and possibly disable various buttons in the toolbox based on whether their corresponding EditCodeAction is currently Valid, Invalid or Draft. This operates on all buttons that we have in the toolbox and so should receive all of the EditCodeActions that are accessible from the toolbox.

Parameters:

  • insertionRecords:
    A list of EditCodeActions specifying the state of each action and by extension the state of the corresponding button.


6. loadToolboxFromJson(): void

Summary:

Load constructs into the toolbox from toolbox.json. This is how our toolbox is populated with the various categories and individual constructs that we have. This is only for static constructs.

This file also contains a small class ToolboxButton with the specification of a toolbox button and some useful methods. It is mostly used by loadToolboxFromJson(). The class methods are self-explanatory. The only useful thing to note is that it relies on the button text being supplied to it to contain --- if we want to display holes as they appear in the editor itself. If the string has no such substrings, then it will be directly inserted into the button without any changes.

Toolbox.json

This file specifies the structure of the toolbox and which parts of it are available. It contains two main fields:

  • toolboxConstructGroupOptions:
    This field specifies which construct groups are enabled and which items within said groups are enabled. For example:
"functionCalls": {
    "includeCategory": 1, //Whether this category is displayed in the toolbox. Set to 0 if you don't want any function call to be present in the toolbox.
    "categoryDisplayName": "Function Calls", //The name of the category used by the toolbox group.
    "includeCategoryItems": { //individual items from the category to be included. Set to 0 if you don't want the item to appear in the toolbox.
        "print": 1,
        "randint": 1,
        "range": 1,
        "len": 1,
        "input": 1
    }
}
  • toolboxDefaultButtonTemplates:
    This field specifies some information for creating the toolbox buttons. For now it only includes a field for the DOM id of the button and the text the button should have.
"print": {
    "id": "add-print-btn", //id of the button in the DOM
    "text": "print(---)" //the text of the print button
},



Typechecker Documentation

This is the class we use for various type-related functionalities that did not fit into the code constructs. It is documented inside of the code. Mostly it is used for converting list types from one to another. It used to contain some other functionality, but after the refactoring of the insert() method and the code constructs themselves, most of that functionality was either removed or placed within the construct definitions. So if you are looking for some particular type functionality and it is not found inside of this class, it is likely within Expression, Statement or Token definitions.

Construct Events Documentation

Our code constructs had various methods added to them for performing numerous important updates. Particularly for types. This section will go over them. Some of these are documented in the code so this document will only contain brief explanations of what those actions do.

Code Construct-level Behaviours

1. typeValidateInsertionIntoHole(insertCode: Expression, insertInto?: TypedEmptyExpr): InsertionType

Summary:

Validates the insertion into a hole of a construct based on type of the code being inserted and the type of hole being inserted into. Should be implemented by ALL constructs that contain TypedEmptyExpr. It is most often called by the construct that CONTAINS the hole being inserted into. That is why the insertInto parameter is necessary. Some constructs have multiple holes.

Parameters:

  • insertCode:
    Code being inserted into.
  • insertInto:
    The hole being inserted into.

Example:
```TypeScript if (--- + ---): //we are inserting an integer literal into the first operand of the binary expression

//so the method would be called like this

binaryOpExpr.typeValidateInsertionIntoHole(intLiteraObj, firstHoleObj)

<br/>
<br/>

**2.** `performPreInsertionUpdates(insertInto?: TypedEmptyExpr, insertCode?: Expression): void`

#### Summary:
This method contains  per-construct logic for actions that need to be performed right before a construct is inserted into the AST. This is meant to be used with holes and expressions.
#### Parameters:

-   **`insertInto`**: <br/> Hole being inserted into.
-   **`insertCode`**: <br/> Expression gbeing inserted.

<br/>
<br/>

**3.** `onFocusOff(arg: any): void`

#### Summary:
Callback that is called when a construct is focused off of in the editor. Should contain any actions that need to be executed at this point.
#### Parameters:

-   **`arg`**: <br/> Any data required by the action.

<br/>
<br/>

**4.** `performPostInsertionUpdates(insertInto?: TypedEmptyExpr, insertCode?: Expression): void`

#### Summary:
This method contains  per-construct logic for actions that need to be performed right after a construct is inserted into the AST. This is meant to be used with holes and expressions.
#### Parameters:

-   **`insertInto`**: <br/> Hole being inserted into.
-   **`insertCode`**: <br/> Expression gbeing inserted.

<br/>
<br/>


### Statement/Expression-level Behaviours
**1.** `Statement -> onInsertInto(insertCode: CodeConstruct)`

#### Summary:
This is ran when a `Statement` or `Expression` are inserted into. So it runs in cases like any time you modify an operand of a binary operator expression or when you modify the condition of an if statement for the first time, etc...
#### Parameters:

-   **`insertCode`**: <br/> Construct being inserted.

<br/>
<br/>

**2.** `Expression -> canReplaceWithConstruct(replaceWith: Expression): InsertionType`

#### Summary:
Return whether `replaceWith` can replace `this` in the AST. This is mostly based on type checks, but there are some structural considerations as well. See the individual implementations of this method for more information.
#### Parameters:

-   **`replaceWith`**: <br/> Code to replace `this` with in the AST.

<br/>
<br/>

**3.** `Expression -> updateVariableType(dataType: DataType)`

#### Summary:
Update the type of variable with the given data type. This should run any time we insert into a `VarAssignmentStmt` or modify the second hole of a for loop.
#### Parameters:

-   **`dataType`**: <br/> The new data type of the variable. 

<br/>
<br/>
<br/>
<br/>

## Misc Documentation

### Draft Mode
Draft mode is attached to the particular construct that triggered it. The current condition for opening the draft mode is:<br/>
- The type of expression being inserted does not match the type of hole it is being inserted into, BUT it can be converted to that type. 

The type conversion is specified by `typeConversionMap: Map<DataType, Array<DataType>>` in `util.ts`. It maps data types to a list of types each data type can be converted to. So `typeConversionMap.get(DataType.Number)` will return a list of all types that a number can be converted to. This should be equal to (subject to change in the future) `[DataType.String, DataType.NumberList, DataType.Boolean]`. **The map takes into account ALL possible ways of converting a type to another. This includes: casting, wrapping and using the expression as an operand of some larger expression.** <br/>
<br/>
The draft mode itself is controlled by two methods within `Module`. These are `closeConstructDraftRecord()` and `openDraftMode()`. They don't do anything special and their code is not difficult to understand. At least at the time of writing this. In summary, they simply add a highlight to the offending code in the editor and mark it internally as being in draft mode by setting `draftModeEnabled` to true. This variable is part of every code construct and can be used to identify constructs that are currently in draft mode.

<br/>
<br/>

### Variables
Variable functionality is split between `Scope`, `VariableContainer`, `variable-controller.ts` and `VarAssignmentStmt`. `ForStatement` also contains some specific functionality for for-loop vars. <br/>

The basic life cycle of a variable is this. 
1. A `VarAssignmentStmt` is created.
2. The statement from step 1 is populated with an identifier and value at some point.
3. **When the statement is focused OFF and IF it has an identifier, only then will a variable be created.** At this point a reference button for the variable will be added to the toolbox.
4. The variable is used and either stays in the code or gets removed. 
5. In the case that the variable is removed, its remaining references are highlighted to indicate that they should be fixed.

<br/>

#### VariableContainer
This is an interface that specifies the behaviours that anything that contains a `VarAssignmentStmt` should implement. <br/>

**1.** `assignId()`

#### Summary:
Every variable needs a **unique** id. This is also the ID used for its reference button in the toolbox. This method should implement the assignment process of this id.
<br/>
<br/>


**2.** `assignVariable(varController: VariableController, currentIdentifierAssignments: Statement[])`

#### Summary:
This method should make use of 3. and 4. It should implement high level logic for how 3. and 4. interact. <br/>

The way it is implemented for `VarAssignmentStmt` and `ForStatement` is that it decides whether `assignNewVariable()` or `assignExistingVariable` run. `assignVariable` itself should be called within the `onFocusOff` of the class that implements the container. Particularly in such a way that there is a decision step between running `assignVariable()` and `reassignVariable()`. 
#### Parameters:

-   **`varController`**: <br/> Current instance of the `VarController` object used by the `Module`.
-   **`currentIdentifierAssignments`**: <br/> All current assignments (within a given scope) to the identifier of the variable we are about to create.

<br/>
<br/>

**3.** `assignNewVariable(varController: VariableController, currentIdentifierAssignments: Statement[])`

#### Summary:
This method should implement the algorithm for assigning a completely new variable that does not exist within the current scope.
#### Parameters:

-   **`varController`**: <br/> Current instance of the `VarController` object used by the `Module`.
-   **`currentIdentifierAssignments`**: <br/> All current assignments (within a given scope) to the identifier of the variable we are about to create.

<br/>
<br/>

**4.** `assignExistingVariable(varController: VariableController, currentIdentifierAssignments: Statement[])`

#### Summary:
This method should implement the algorithm for assigning an existing variable using a new `VarAssignmentStmt` within the current scope.
#### Parameters:

-   **`varController`**: <br/> Current instance of the `VarController` object used by the `Module`.
-   **`currentIdentifierAssignments`**: <br/> All current assignments (within a given scope) to the identifier of the variable we are about to create.

<br/>
<br/>


**5.** `reassignVar(varController: VariableController, currentIdentifierAssignments: Statement[])`

#### Summary:
This method should implement the algorithm for modifying the identifier of an existing `VarAssignmentStmt`.
#### Parameters:

-   **`varController`**: <br/> Current instance of the `VarController` object used by the `Module`.
-   **`currentIdentifierAssignments`**: <br/> All current assignments (within a given scope) to the identifier of the variable we are about to create.

<br/>
<br/>

### What are the Differences between the Methods above?
3. and 4. are meant to be used on **completely new `VarAssignmentStmt`** objects. Ones were just created. 5. is meant to be used on **existing `VarAssignmentStmt`** that are being modified.

### ForStatement
The ForStatement implements its variable a bit differently. You can look at the differences between the implementations of the various `VariableContainer` methods in `ForStatement` and `VarAssignmentStmt`. **`ForStatement` uses the attribute `loopVar: VarAssignmentStmt` to keep track of its loop variable.** This dummy `VarAssignmentStmt` DOES NOT appear in the editor and it IS NOT part of the AST. It is used purely for being able to treat the `ForStatement` as a variable in cases where this is required. 
<br/>
<br/>
<br/>



### Text Enhance
This class can be used to change the visuals of the text we are using in our editor and toolbox. It only has two methods.
<br/>

**1.** `getStyledSpan(content: string, styleClass: string): string`

#### Summary:
Wrap `content` into a `<span>` element with `className=styleClass` and return the resulting string. This returned string can then be assigned to `innerHTML` of various DOM elements to have styled text. 
#### Parameters:

-   **`content`**: <br/> The text to be styled.
-   **`styleClass`**: <br/> Name of the CSS class used to style the text.
<br/>
<br/>

**2.** `getStyledSpanAtSubstrings(content: string, styleClass: string, matches: [][]): string`

#### Summary:
Wrap substrings specified by `matches` within `content` with a `<span>` element with `className=styleClass` and return the resulting string. The result can be assigned to `innerHTML` of various DOM elements to have styled text. <br/>

The structure of matches is very important for this. It is an array of tuples specifying the start and end indeces of each substring to be styled. **The end index is inclusive!**
#### Parameters:

-   **`content`**: <br/> Text to be styled.
-   **`styleClass`**: <br/> Name of the CSS class used to style the text.
-   **`matches`**: <br/> List specifying the substring ranges within `content` to be styled. <br/>
Here is an example:
```TypeScript
content = "This is the text to be styled."
styleClass = "styleClassName"
matches = [[0, 4], [8, 9]]
let res = getStyledSpanAtSubstrings(content, styleClass, matches)

console.log(res)
>>> "<span class='styleClassName'>This </span>is <span class='styleClassName'>th</span>e text to be styled."