{"id":13658526,"url":"https://github.com/1Hibiki1/locks-py","last_synced_at":"2025-04-24T11:31:50.643Z","repository":{"id":65235722,"uuid":"315680184","full_name":"1Hibiki1/locks-py","owner":"1Hibiki1","description":"Python implementation of locks, which is an imperative, dynamically typed, procedure oriented scripting language based on the lox programming language.","archived":false,"fork":false,"pushed_at":"2022-03-03T14:30:55.000Z","size":77,"stargazers_count":34,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-10T12:42:20.708Z","etag":null,"topics":["compiler","interpreter","locks","lox","programming-language"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/1Hibiki1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-24T15:51:11.000Z","updated_at":"2024-10-01T16:01:28.000Z","dependencies_parsed_at":"2023-01-16T15:00:54.919Z","dependency_job_id":null,"html_url":"https://github.com/1Hibiki1/locks-py","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1Hibiki1%2Flocks-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1Hibiki1%2Flocks-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1Hibiki1%2Flocks-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1Hibiki1%2Flocks-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/1Hibiki1","download_url":"https://codeload.github.com/1Hibiki1/locks-py/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250618329,"owners_count":21460072,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler","interpreter","locks","lox","programming-language"],"created_at":"2024-08-02T05:01:00.387Z","updated_at":"2025-04-24T11:31:50.377Z","avatar_url":"https://github.com/1Hibiki1.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Locks\r\n[Note: I made this during my first sem at uni, so expect some not-so-well-written code ;)]\r\nLocks is an imperative, dynamically typed, procedure oriented scripting language based on the [lox](https://github.com/munificent/craftinginterpreters) language. Locks-py is the python implementation of locks. While locks and lox share almost the same grammar, the locks implementation is not based on that of lox. This was made as a project for an introductory programming course.\r\n\r\n## Contents\r\n\r\n- [Usage](#usage)\r\n- [The Locks language](#the-locks-language)\r\n  - [IO](#io)\r\n  - [Comments](#comments)\r\n  - [Keywords and Identifiers](#keywords-and-identifiers)\r\n  - [Datatypes](#datatypes)\r\n  - [Variables](#variables)\r\n  - [Statements](#statements)\r\n    - [Expression Statement](#expression-statement)\r\n    - [Assign Statement](#assign-statement)\r\n    - [If Statement](#if-statement)\r\n  - [Loops](#loops)\r\n    - [While loop](#while-loop)\r\n    - [For loop](#for-loop)\r\n  - [Functions](#functions)\r\n  - [Builtin functions](#builtin-functions)\r\n    - [IO functions](#io-functions)\r\n    - [String and Array functions](#string-and-array-functions)\r\n      - [String](#string)\r\n      - [Both](#both)\r\n    - [Type conversion](#type-conversion)\r\n- [The Locks VM](#the-locks-vm)\r\n  - [Byte code Format](#byte-code-format)\r\n    - [Constants Pool](#constants-pool)\r\n  - [Opcodes](#opcodes)\r\n- [Editor](#editor)\r\n  - [Opening files](#opening-files)\r\n  - [Saving files](#saving-files)\r\n  - [Running Locks programs](#running-locks-programs)\r\n  - [Visualizing The AST from the Editor](#visualizing-the-ast-from-the-editor)\r\n  - [Customizing](#customizing)\r\n  - [Keyboard shortcuts](#keyboard-shortcuts)\r\n- [Visualizing The AST](#visualizing-the-ast)\r\n- [Known Bugs](#known-bugs)\r\n\r\n## Usage\r\n\r\nNote: You will need to have python 3 installed. This project was tested with python 3.8.3.\r\n\r\nTo start the editor, clone this repo and run\r\n\r\n``` console\r\npython locks-editor.py\r\n```\r\n\r\nAn editor window should pop up. Start coding! You can find examples at `examples/`. To run a program, open a locks file through `File -\u003e Open`, and choose `Run -\u003e Run(debug)` from the menu bar. For more details, check the [Editor](#editor) section.\r\n\r\nTo run a locks program from the command line, run\r\n\r\n``` console\r\npython locks-interpreter.py \u003cpath-to-locks-file\u003e\r\n```\r\n\r\nTo be able to visualize the AST, the requests, cairosvg, and Pillow libraries will have to be installed.\r\n\r\n``` console\r\npip install requests\r\npip install cairosvg\r\npip install Pillow\r\n```\r\n\r\nIf these are not installed, the visualizer will generate a dot file, the contents of which can be pasted at [GraphViz Online](https://dreampuf.github.io/GraphvizOnline/) to render it. For more information, see [Visualizing The AST](#visualizing-the-ast).\r\n\r\nThe interpreter will use the VM to run the program by default.\r\n\r\n`locks-interpreter.py` accepts the following options:\r\n| Options                       | Description                                                          |\r\n|-------------------------------|----------------------------------------------------------------------|\r\n| path (required)               | path to locks file                                                   |\r\n| -d (optional)                 | use tree walk interpreter instead of VM.                             |\r\n| -b output-filename (optional) | output code generated by compiler to specified file                  |\r\n| -v (optional)                 | output code generated by compiler to stdout                          |\r\n| -g output-filename (optional) | generate dot, svg, and png file to visualize AST generated by parser |\r\n| -h                            | show usage                                                           |\r\n\r\n## The Locks language\r\n\r\n### IO\r\n\r\nThe `print()` function prints arguments to stdout. `println` adds a trailing newline character.\r\n\r\n``` javascript\r\nprint(\"Hello World\");\r\nprintln(\"Hello World\");\r\n```\r\n\r\nThe `input()` function accepts input from stdin. It accepts a prompt as string, and returns the inputted string.\r\n\r\n``` javascript\r\ninput(\"\");  // no prompt\r\ninput(\"Enter something\");  // input with prompt\r\n\r\nvar x = input(\"Enter something\");  // store input in a variable (as a string)\r\n```\r\n\r\n### Comments\r\n\r\nLocks supports single line and multi-line C-style comments. Multi-line comments cannot be nested.\r\n\r\n```javascript\r\n// single line comment\r\n/*\r\n    Multi-line comment\r\n*/\r\n```\r\n\r\n### Keywords and Identifiers\r\n\r\nThe following are reserved keywords in Locks:\r\n\r\n```lang-none\r\nvar, fun, if, elsif, else, while, for, return, continue, break, and, or, true, false, nil\r\n```\r\n\r\nA valid Locks identifier may contain alphanumeric and '_' characters, and may not begin with a number.\r\n\r\n```javascript\r\nvar _a123_;  //valid\r\nvar 12r; //invalid!\r\n```\r\n\r\n### Datatypes\r\n\r\nLocks supports the following datatypes:\r\n\r\n- `Nil`: Used to define a null value, denoted by the `nil` keyword\r\n- `Number`: Can be 64 bit signed integer, or double precision floating-point numbers. For example: `135, 31.63, -1331`\r\n- `String`: Sequence of ascii characters surrounded by `\"`. For example: `\"Hello!\"`\r\n- `Boolean`: Can be `true` or `false`\r\n- `Array`: A sequence of Locks datatypes, surrounded by `[` and `]` and separated by `,`. For example: `[1, \"hello\", [true, 2]]`\r\n\r\nThe following are falsey values in locks: `0`, `\"\"`, `[]`, `false`, `nil`, and functions.\r\n\r\n### Variables\r\n\r\nVariables are declared using the `var` keyword.\r\n\r\n``` javascript\r\nvar a;  // declare\r\na = 5;  // assign\r\nvar b = 5;  // declare and assign\r\n```\r\n\r\n### Statements\r\n\r\nLocks supports the following statements (apart from loops, return, continue and break statements):\r\n\r\n- [Expression Statement](#expression-statement)\r\n- [Assign Statement](#assign-statement)\r\n- [If Statement](#if-statement)\r\n\r\n#### Expression Statement\r\n\r\nLocks supports the following operators for arithmetic and logical expressions:\r\n\r\n- `+`: Adds two numbers or concatenates two strings. Both operands must be of the same type (i.e. String or Number)\r\n- `-`: Subtracts right operand from left operand. Both operands must be numbers. Can also function as a unary negation operator.\r\n- `*`: Multiplies two numbers\r\n- `\\`: Divides two numbers\r\n- `%`: Gives remainder when left operand is divided by right operand (modulo)\r\n\r\n- `==`: Returns `true` if left operand is equal to right operand, otherwise `false`\r\n- `!=`: Returns `true` if left operand is not equal to right operand, otherwise `false`\r\n- `\u003c`: Returns `true` if left operand is less than right operand, otherwise `false`. Both operands must be numbers\r\n- `\u003e`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers\r\n- `\u003c=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers\r\n- `\u003e=`: Returns `true` if left operand is equal to right operand, otherwise `false`. Both operands must be numbers\r\n- `and`: Returns `true` if both left and right operands are truthy, otherwise `false`\r\n- `or`: Returns `true` if either the left or the right operand is truthy, otherwise `false`\r\n- `!`: Performs a logical not on its operand\r\n\r\n#### Assign Statement\r\n\r\nUnlike Lox, variable assignment is a statement in Locks rather than an expression. The left operand for the `=` (assign) operator can be either an identifier, or an indexed identifier that refers to an array.\r\n\r\n``` javascript\r\nvar a;\r\n// assignment statements\r\na = [1,2,3,4,5];\r\na[3] = 7;\r\n```\r\n\r\n#### If Statement\r\n\r\nThe if-elsif-else statement is similar to that of C.\r\n\r\n```javascript\r\nvar a = 3;\r\nvar b;\r\n\r\nif(a \u003c 10){\r\n    b = 0;\r\n}elsif(a \u003e= 10 and a \u003c 20){\r\n    b = a;\r\n}else{\r\n    b = 1;\r\n}\r\n```\r\n\r\n### Loops\r\n\r\n#### While loop\r\n\r\nA conventional C-style while loop, in which the body is executed while the expression specified in parentheses evaluates to true.\r\n\r\n```javascript\r\nvar i = 0;\r\n\r\nwhile(i \u003c 10){\r\n    println(i);\r\n    i = i + 1;\r\n}\r\n```\r\n\r\n#### For loop\r\n\r\nLocks supports C-style for loops. However, it must be noted that new scopes are created only when a function is called, so a variable if declared once in a for loop, it must not be declared again.\r\n\r\n```javascript\r\n// infinite loop!\r\nfor(;;) println(\"Hello\");\r\n\r\n// Ok. Note that locks does not have a '+=' or '++' shorthand\r\nfor(var i = 0; i \u003c 10; i = i + 1){\r\n    println(\"Hello\");\r\n}\r\n\r\n// Ok.\r\nfor(i = 0; i \u003c 10; i = i + 1){\r\n    println(\"Hello\");\r\n}\r\n\r\n// ERROR! Duplicate declaration of variable 'i'\r\nfor(var i = 0; i \u003c 10; i = i + 1){\r\n    println(\"Hello\");\r\n}\r\n\r\n```\r\n\r\n### Functions\r\n\r\nFunctions in Locks are declared using the `fun` keyword. The parameters must be comma separated identifiers, and are specified in parentheses after the function name.\r\n\r\n```javascript\r\nfun add(b, c, d){\r\n    println(b + c + d);\r\n}\r\n\r\nadd(1, 3, 5);\r\n```\r\n\r\nA value can be returned at any point from a function using the `return` keyword.\r\n\r\n```javascript\r\n// \"fun fact\"! :D\r\nfun fact(n){\r\n    if(n == 1) return 1;\r\n    return n*fact(n-1);\r\n}\r\n\r\nprintln(fact(6));\r\n```\r\n\r\nNote that while functions can be declared inside functions, they cannot be returned from a function or assigned to a variable.\r\n\r\n```javascript\r\nfun a(){\r\n    // Ok.\r\n    fun b(){\r\n        return 5;\r\n    }\r\n    println(b());\r\n    return b;  // ERROR! can't return a function from within a function\r\n}\r\n\r\nvar x = a; // ERROR! can't assign a function to a variable\r\n```\r\n\r\n### Builtin functions\r\n\r\n#### IO functions\r\n\r\n- `print`: Accepts 1 argument and prints it to stdout\r\n- `println`: Accepts 1 argument and prints it to stdout, with newline\r\n- `input`: Accepts 1 argument and prints it to stdout, and accepts input from stdin\r\n\r\nFor usage of these functions, check [IO](#io).\r\n\r\n#### String and Array functions\r\n\r\n##### String\r\n\r\n- `isinteger`: Accepts a string as argument, returns true if the string is a valid integer, false otherwise\r\n\r\n##### Both\r\n\r\n- `len`: Accepts a string or an array as argument, and returns its length\r\n\r\n#### Type conversion\r\n\r\n- `int`: Accepts 1 argument, converts it to an integer, and returns it\r\n- `str`: Accepts 1 argument, converts it to a string, and returns it\r\n\r\n## The Locks VM\r\n\r\nThe Locks VM is inspired by the JVM and the Python VM.\r\n\r\n### Byte code Format\r\n\r\nByte code for the Locks VM always begins with the magic number `0x04D69686F`, followed by the constants pool count (2 bytes) followed by constants. This is then followed by the function count (2 bytes) and then the functions. Each function begins with an argument count (2 bytes) followed by the length of the function code (2 bytes).\r\n\r\nFor example:\r\n\r\n```lang-none\r\n0x4d 0x69 0x68 0x6f  // magic number\r\n\r\n0x00 0x03  // constants pool count\r\n\r\n0x08 0x48 0x65 0x6c 0x6c 0x6f 0x21 0x00       // constant 1 - string\r\n0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0xf4  // constant 2 - int\r\n0x06 0x00 0x20 0x00 0x00 0x00 0x00 0x01 0x3a  // constant 3 - float\r\n\r\n0x00 0x02  // function count\r\n\r\n// function 1\r\n0x00 0x00  // arg count\r\n0x00 0x12  // code length (in bytes)\r\n\r\n0x64 0x0 0x0\r\n0x64 0x0 0x1\r\n0x64 0x0 0x2\r\n0x10 0x03\r\n0x10 0x04\r\n0x83 0x01\r\n0x84 0x01\r\n0xff\r\n\r\n// function 2\r\n0x00 0x02  // arg count\r\n0x00 0x0a  // code length (in bytes)\r\n\r\n0x5a 0x00\r\n0x5a 0x01\r\n0x52 0x00\r\n0x52 0x01\r\n0x17\r\n0x53\r\n```\r\n\r\nThis is the code generated for:\r\n\r\n```javascript\r\n// constants to demonstrate constants pool\r\n\"Hello!\";\r\n500;\r\n3.14;\r\n\r\nfun add(a, b){\r\n    return a + b;\r\n}\r\n\r\nprintln(add(3,4));\r\n```\r\n\r\n#### Constants Pool\r\n\r\nThe constants pool stores all strings, negative integers and integers greater than 255, and floating-point numbers. Each constant is tagged to denote their type:\r\n\r\n| Datatype | Representing Tag |\r\n|----------|------------------|\r\n| Integer  | 0x03             |\r\n| Double   | 0x06             |\r\n| String   | 0x08             |\r\n\r\nNegative integers are stored in their two's complement representation. For example, `-1729` will be stored as `0xff 0xff 0xff 0xff 0xff 0xff 0xf9 0x3f`.\r\n\r\nStrings are stored as null-terminated strings. For example, `\"Hello\"` will be stored as `0x48 0x65 0x6c 0x6c 0x6f 0x21 0x00`.\r\n\r\nFloting point numbers are stored according to the following representation:\r\n![double representation](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/IEEE_754_Double_Floating_Point_Format.svg/618px-IEEE_754_Double_Floating_Point_Format.svg.png)\r\n\r\nFor example, `3.14` will be stored as `0x00 0x20 0x00 0x00 0x00 0x00 0x01 0x3a`.\r\n\r\n### Opcodes\r\n\r\n| Opcode | Name             | Description                                                                                                                                                                                                                                                                                                              |\r\n|--------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\r\n| 0xFF   | END              | Ends execution                                                                                                                                                                                                                                                                                                           |\r\n| 0x01   | LOAD_NIL         | Pushes a nil object on the operand stack of the current frame                                                                                                                                                                                                                                                            |\r\n| 0x02   | LOAD_TRUE        | Pushes a Boolean object with value \"true\" on the operand stack of the current frame                                                                                                                                                                                                                                      |\r\n| 0x03   | LOAD_FALSE       | Pushes a Boolean object with value \"false\" on the operand stack of the current frame                                                                                                                                                                                                                                     |\r\n| 0x64   | LOAD_CONST       | Pushes a constant from the constants pool on the operand stack of the current frame at index specified by its 2 byte argument                                                                                                                                                                                            |\r\n| 0x17   | BNARY_ADD        | Pops 2 items from the operand stack of the current frame, adds them, and pushes the result back onto the stack                                                                                                                                                                                                           |\r\n| 0x18   | BINARY_SUBTRACT  | Pops 2 items from the operand stack of the current frame, subtracts them, and pushes the result back onto the stack                                                                                                                                                                                                      |\r\n| 0x14   | BINARY_MULTIPLY  | Pops 2 items from the operand stack of the current frame, multiples them, and pushes the result back onto the stack                                                                                                                                                                                                      |\r\n| 0x15   | BINARY_DIVIDE    | Pops 2 items from the operand stack of the current frame, divides them, and pushes the result back onto the stack                                                                                                                                                                                                        |\r\n| 0x16   | BINARY_MODULO    | Pops 2 items from the operand stack of the current frame, performs the modulo operation, and pushes the result back onto the stack                                                                                                                                                                                       |\r\n| 0x40   | BINARY_AND       | Pops 2 items from the operand stack of the current frame, performs a logical and on the two items, and pushes the result back onto the stack. Note that unlike the Python VM, BINARY_AND performs the logical and, and not bitwise and.                                                                                  |\r\n| 0x42   | BINARY_OR        | Pops 2 items from the operand stack of the current frame, performs a logical or on the two items, and pushes the result back onto the stack. Note that unlike the Python VM, BINARY_OR performs the logical or, and not bitwise or.                                                                                      |\r\n| 0x0C   | UNARY_NOT        | Pops 1 item from the operand stack of the current frame, pushes false if the popped value is truthy, and true otherwise.                                                                                                                                                                                                 |\r\n| 0x0B   | UNARY_NEGATIVE   | Pops 1 item from the operand stack of the current frame, negates it, and pushes the result back on to the stack                                                                                                                                                                                                          |\r\n| 0x5A   | STORE_LOCAL      | Pops 1 item from the operand stack of the current frame, stores it in a local variable at index specified by 1 byte argument                                                                                                                                                                                             |\r\n| 0x61   | STORE_GLOBAL     | Pops 1 item from the operand stack of the current frame, stores it in a global variable at index specified by 1 byte argument                                                                                                                                                                                            |\r\n| 0x10   | BIPUSH           | Pushes 1 byte argument as 1 byte integer on the operand stack of the current frame                                                                                                                                                                                                                                       |\r\n| 0x52   | LOAD_LOCAL       | Pushes value of local variable at index specified by 1 byte argument on the operand stack of the current frame                                                                                                                                                                                                           |\r\n| 0x74   | LOAD_GLOBAL      | Pushes value of global variable at index specified by 1 byte argument on the operand stack of the current frame                                                                                                                                                                                                          |\r\n| 0x67   | BUILD_LIST       | Pops argument (2 bytes) number of items from the operand stack of the current frame, builds an Array object containing the items, and pushes it on the stack                                                                                                                                                             |\r\n| 0x19   | BINARY_SUBSCR    | Pops index from the operand stack of the current frame, pops array object from the stack, pushes the value at index of the array object                                                                                                                                                                                  |\r\n| 0x3C   | STORE_SUBSCR     | Pops index from the operand stack of the current frame, pops array object from the stack, pops value from the stack, stores value at index of array object                                                                                                                                                               |\r\n| 0x9F   | CMPEQ            | Pops 2 items from the operand stack of the current frame, pushes true of they are equal, false otherwise                                                                                                                                                                                                                 |\r\n| 0xA0   | CMPNE            | Pops 2 items from the operand stack of the current frame, pushes true of they are not equal, false otherwise                                                                                                                                                                                                             |\r\n| 0xA3   | CMPGT            | Pops 2 items from the operand stack of the current frame, pushes true if 2nd item is greater than 1st item, false otherwise                                                                                                                                                                                              |\r\n| 0xA1   | CMPLT            | Pops 2 items from the operand stack of the current frame, pushes true if 2nd item is less than 1st item, false otherwise                                                                                                                                                                                                 |\r\n| 0xA2   | CMPGE            | Pops 2 items from the operand stack of the current frame, pushes true if 2nd item is greater than or equal to 1st item, false otherwise                                                                                                                                                                                  |\r\n| 0xA4   | CMPLE            | Pops 2 items from the operand stack of the current frame, pushes true if 2nd item is less than or equal to 1st item, false otherwise                                                                                                                                                                                     |\r\n| 0x70   | POP_JMP_IF_TRUE  | Pops 1 item from the operand stack of the current frame, jumps to location specified by 2 byte argument if the item is truthy                                                                                                                                                                                            |\r\n| 0x6F   | POP_JMP_IF_FALSE | Pops 1 item from the operand stack of the current frame, jumps to location specified by 2 byte argument if the item is not truthy                                                                                                                                                                                        |\r\n| 0xA7   | GOTO             | Unconditional jump to location specified by 2 byte argument                                                                                                                                                                                                                                                              |\r\n| 0x83   | CALL_FUNCTION    | Saves the current state of the caller in a frame and pushes it on the call stack, sets the code of the current frame to that of the function at index specified by 1 byte argument, pops argc items from the caller's operand stack and pushes them on the callee's operand stack, and begins executing called function  |\r\n| 0x84   | CALL_NATIVE      | Looks up the function at index specified by 1 byte argument from the builtin function table, and executes it                                                                                                                                                                                                             |\r\n| 0x53   | RETURN_VALUE     | Restores instruction pointer and state of the caller function, and pushes return value on the operand stack of the caller                                                                                                                                                                                                |\r\n\r\n## Editor\r\n\r\nThe Locks Editor is a minimal text editor made with tkinter, with which you can open, edit, save, and run locks files.\r\n\r\n### Opening files\r\n\r\nA file can be opened through the `File -\u003e Open` option. Note that opening a new file will override the current open file, so make sure it is saved first.\r\n\r\n### Saving files\r\n\r\nA file can be saved through the `File -\u003e Save` or `File -\u003e Save As` option, as a text(.txt) or a locks(.lks) file.\r\n\r\n### Running Locks programs\r\n\r\nA currently open locks file can be run through `Run -\u003e Run` or `Run -\u003e Run (debug)`. `Run` will run the program through the VM, and `Run (debug)` will run the program through the tree walk interpreter.\r\n\r\nA new terminal window will be opened on Windows for code execution. Note that running the program through the VM exits the terminal as soon as execution is complete, an `input(\"\")` can be added to the end of the locks program to stop this from happening.\r\n\r\nOn linux, the locks program will execute in the terminal that the editor was run from.\r\n\r\n### Visualizing The AST from the Editor\r\n\r\nThe AST can be visualized from the editor by selecting the `Run -\u003e Visualize AST` option. This will attempt to create and render a dot file. Any error or message is shown on a separate console window. On linux, the messages are shown on the same console that the editor was run from.\r\n\r\n### Customizing\r\n\r\nThe font size and theme can be changed from `Options -\u003e Preferences`.\r\n\r\nThe default dark and light themes were inspired by the [Cyberpunk 2077](https://github.com/endormi/vscode-2077-theme) and the [Atom One light syntax theme](https://github.com/atom/atom/tree/master/packages/one-light-syntax). If you don't like either, switch to the notepad theme or create your own.\r\n\r\nYou can create your own theme files by following the format below and saving the json file in the `editor/theme` folder. Note that (as of now) the editor does not check for the validity of the theme files.\r\n\r\nTheme example: `defaultDark.json`\r\n\r\n```json\r\n{\r\n    \"name\": \"Default Dark\",\r\n    \"background\": \"#030d22\",\r\n    \"foreground\": \"#ffffff\",\r\n    \"selectBackground\": \"#35008b\",\r\n    \"inactiveselectbackground\": \"#310072\",\r\n    \"cursorColor\": \"#ee0077\",\r\n    \"keywords\": \"#ff2cf1\",\r\n    \"functionName\": \"#ffd400\",\r\n    \"strings\": \"#0ef3ff\",\r\n    \"comments\": \"#0098df\"\r\n}\r\n```\r\n\r\nNote: Syntax highlighting for multiline comments is disabled for now since it may cause other syntax highlighting problems. See [known bugs](#known-bugs).\r\n\r\n### Keyboard shortcuts\r\n\r\n- `Ctrl+o`: Open file\r\n- `Ctrl+s`: Save currently open file\r\n- `Tab` and `Shift+Tab`: Add/remove 4-space indent to selection or current line\r\n\r\n## Visualizing The AST\r\n\r\nThe interpreter can be used to visualize the AST of an input program as a graph. This can be done as follows:\r\n\r\n``` console\r\npython locks-interpreter.py \u003cpath-to-locks-file\u003e -g \u003cwrite-dot-to-file\u003e\r\n```\r\n\r\nFor example:\r\n\r\n``` console\r\npython locks-interpreter.py examples/fibonacci.lks -g fib.dot\r\n```\r\n\r\nThe interpreter will write the generated dot code to a file at the location specified by the argument (which must be a filename). It will then try to use the [QuickChart GraphViz API](https://quickchart.io/documentation/graphviz-api/) to generate and get an svg file from the dot file, use chairo to convert it to a png file, and then show the image on a window through Pillow and Tkinter. Pillow, requests, and chairo will need to be installed separately using pip for this to work. If not installed, the dot file alone will be generated. The generated code can be pasted to [GraphViz Online](https://dreampuf.github.io/GraphvizOnline/) to render it.\r\n\r\nThe AST can also be visualized from the editor by selecting the `Run -\u003e Visualize AST` option.\r\n\r\n## Known Bugs\r\n\r\n- The tree walk interpreter crashes when the lvalue of an assign statement tries to index a nested list.\r\n\r\n    ```javascript\r\n    var a = [1,2,[3,4],5]\r\n    a[2][1] = 8;  // Crash!!\r\n    ```\r\n\r\n    This works in the VM, however.\r\n\r\n- If an operand of a comparision expression with is a function, it works fine in the VM. If either operand is a function, the tree walk interpreter throws a type error. If the left operand is a function and the result of the expression is assigned to a variable, the semantic analyser throws a type error.\r\n\r\n    ``` javascript\r\n    fun a(){\r\n        print(\"hello\");\r\n    }\r\n\r\n    // works in the VM, but tree walk interpreter throws a type error\r\n    println(a == a);\r\n\r\n    // semantic analyzer throws a type error\r\n    var l = a and 4;\r\n    ```\r\n\r\n- The VM does nothing and continues with execution if there is a return statement outside a function. The tree walk interpreter throws a 'return outside function' syntax error.\r\n\r\n- Multiline comments are not correctly highlighted in the Editor. They only work when `/**/` is typed in first, and then the comment is written. When highlighted correctly, their foreground doesn't change even on change of theme. For now, syntax highlighting for multiline comments will be disabled.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1Hibiki1%2Flocks-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F1Hibiki1%2Flocks-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1Hibiki1%2Flocks-py/lists"}