{"id":16921812,"url":"https://github.com/bugoverdose/yail","last_synced_at":"2025-04-11T16:43:43.204Z","repository":{"id":109989193,"uuid":"581955734","full_name":"bugoverdose/yail","owner":"bugoverdose","description":"Yet Another Interpreted Language","archived":false,"fork":false,"pushed_at":"2023-09-20T07:11:52.000Z","size":1377,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-25T12:53:29.617Z","etag":null,"topics":["evaluator","go","interpreter","lexer","parser"],"latest_commit_sha":null,"homepage":"","language":"Go","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/bugoverdose.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-25T03:08:52.000Z","updated_at":"2024-03-21T00:52:36.000Z","dependencies_parsed_at":"2025-02-19T20:42:36.854Z","dependency_job_id":null,"html_url":"https://github.com/bugoverdose/yail","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/bugoverdose%2Fyail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bugoverdose%2Fyail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bugoverdose%2Fyail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bugoverdose%2Fyail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bugoverdose","download_url":"https://codeload.github.com/bugoverdose/yail/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248442423,"owners_count":21104181,"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":["evaluator","go","interpreter","lexer","parser"],"created_at":"2024-10-13T19:53:12.924Z","updated_at":"2025-04-11T16:43:43.176Z","avatar_url":"https://github.com/bugoverdose.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# YAIL: Yet Another Interpreted Language\n\nYail is a simple interpreted language built with Go.\n\n## Quick Start (for Mac)\n\nRun the following command in your terminal for quick installation.\n\n```shell\ncurl -o /usr/local/bin/yail 'https://raw.githubusercontent.com/bugoverdose/yail/master/build/yail' \u0026\u0026 chmod 755 /usr/local/bin/yail\n```\n\nAfter installation, you can just run `yail` anywhere to start the *interactive mode*. \nTo exit the *interactive mode*, just type `q` or `exit` command and press enter.\nCopy and paste each of the lines below to if you are stuck.\n\n```shell\nyail\nval x = \"Hello World!\";\nx;\nexit\n```\n\nIf you want to delete the program, just run the command below.\n\n```shell\nrm -rf /usr/local/bin/yail\n```\n\n## Variables\n\n### Identifier format\n\nThe name of the variables, or `identifiers`, must follow the following rules.\n\n1. The identifier should be a string with at least one character.\n2. The first character should be an alphabet(`a`-`Z`) or an underscore(`_`).\n3. The rest of the characters should be alphabets(`a`-`Z`), numbers(`0`-`9`), or an underscore(`_`).\n4. The reserved keywords used by Yail can not be used as an identifier(`var`, `return`, etc).\n\n```kotlin\n// allowed\nvar a = 1;\nvar _ = true;\nvar a_b_2 = 3;\n\n// not allowed\nvar 1a = 1; // starts with a number\nvar a b = 2; // whitespace included\nvar val = 3; // val is a keyword\nvar 변수 = 4; // non-ASCII characters are not allowed\n```\n\n### Variable binding\n\nThere are two ways of assigning local variables, using the `var` and `val` keywords. The basic rule is similar to\nKotlin. But there are some differences.\n\n1. You can't specify the type of the variable.\n2. It's possible to reassign the same declared identifier with different data types.\n3. Each assignment statement must end with a semicolon(`;`).\n\n```kotlin\nvar a = 5;\nval b = 20;\n\nval c = 10; // [ERROR] missing token: ;\n```\n\nThe `var` keyword stands for `variable` assignment. Variables defined with the `var` keyword can be reassigned. Remember\nto omit the `val` and `var` keyword for reassigning already declared identifiers.\n\n```kotlin\nvar a = 5;\na = 10;\na = true;\n\nvar a = 20; // [ERROR] given identifier 'a' is already declared\n```\n\nRead-only local variables are defined using the `val` keyword, which stands for `value` assignment. If you try to\nreassign the value-assigned variable with another value, the interpreter will throw an error during the evaluation\nprocess.\n\n```kotlin\nval b = 10;\nb = 20; // [ERROR] can not reassign variables declared with 'val'\n```\n\n## Data types\n\nCurrently, Yail has six data types: integer, boolean, string, array, hash map and null.\n\nAs mentioned above, variables defined with the `var` keyword can be reassigned with a different data type.\n\n```kotlin\nval x = 5;\nval y = true;\nvar z = null;\nz = 10;\nz = false;\n```\n\n### Basic Operations\n\nAll the following operations are supported.\n\n- basic arithmetic operations(`+`, `-`, `*`, `/`, `%`) for integers\n- negative prefix(`-`) for integers\n- basic comparison operations(`==`, `!=`, `\u003c=`, `\u003e=`, `\u003c`, `\u003e`)\n- not prefix(`!`) for reversing a boolean\n- grouping(`()`) for changing the priority of operations\n\n```kotlin\n5 + 5; // 10\n5 - 5; // 0\n5 * 5; // 25\n5 / 5; // 1\n5 % 5; // 0\n\n5 == 5; // true\n5 != 5 // false\n5 \u003c= 5 // true\n5 \u003e= 5 // true\n10 \u003e 5 // true\n10 \u003c 5 // false\n\n!false; // true\n\n1 + 2 * 3; // 7\n(1 + 2) * 3; // 9\n```\n\n### Strings\n\nA string is a sequence of characters wrapped by quotation marks(`\"`). Any ASCII characters can be used as content, even\nif it can not be used for identifiers.\n\n`+` operator can be used for concatenating multiple strings to return a new string. Also, builtin function `len` can be\nused for counting the length of the string, which is the number of characters including all the whitespace.\n\n```kotlin\nval a = \"Hello\";\nval b = \"World!\";\nval c = a + \" \" + b;\nc; // Hello World!\n\nlen(\"\"); // 0\nlen(\"abc123#$%^\"); // 10\n```\n\n### Arrays\n\nAn array is a list of elements wrapped by brackets(`[`, `]`). Any type of data can be used as an element and arrays in\nYail can contain elements with different data types.\n\nEach element can be accessed based on its index. If the given index is out of range, null would be returned instead of\nthrowing an error.\n\n```kotlin\nval arr = [1, \"two\", 3 + 3];\n\narr[0]; // 1\narr[1]; // \"two\"\narr[2]; // 6\narr[3]; // null\narr[-1] // null\n```\n\nMany builtin functions are supported for arrays.\n\n- `len` returns the number of elements in the array.\n- `head` returns the first element in the array without changing the array.\n- `tail` returns the last element in the array without changing the array.\n- `push` and `pushleft` each adds a new element as the new last or first element in the array.\n- `pop` and `popleft` each removes the last or first element in the array.\n\n```kotlin\nval arr = [1, 2, 3];\nlen(arr); // 3\nhead(arr); // 1\ntail(arr); // 3\narr; // [1, 2, 3]\n\npush(arr, 10); arr; // [1, 2, 3, 10]\npushleft(arr, 20); arr; // [20, 1, 2, 3, 10]\npop(arr); arr; // [20, 1, 2, 3]\npopleft(arr); arr; // [1, 2, 3]\n```\n\n### Hash Map\n\nA hash map consists of multiple key-value pairs wrapped by curly brackets(`{`, `}`).\nOnly hashable data types can be used for keys, which are strings, integers, and booleans.\nAny data type can be used for values including arrays, functions, and another hash maps.\n\nEach value can be accessed based on the corresponding key.\nIf the given key does not exist, null would be returned instead of throwing an error.\n\n```kotlin\nval map = { \"one\": 1, true: [10, 20, 30], 100: { \"a\": 1, \"b\": 2 }, \"f\": func(x) { x * x }};\n\nmap[\"one\"]; // 1\nmap[\"two\"]; // null;\n\nmap[true]; // [10, 20, 30]\nmap[true][0]; // 10\n\nmap[100]; // { a: 1, b: 2 }\nmap[100][\"b\"]; // 2\n\nval square = map[\"f\"];\nsquare(10); // 100\n```\n\n## Conditional Expressions\n\nBasic `if` and `else` keywords are supported. When the conditions are met, multiple statements inside a selected block\nare consecutively executed.\n\n```kotlin\nif (true) { val x = 10; }\nx; // 10\n\nif (5 \u003e 10) { val a = 10; } else { val b = 15; val c = 20; }\na; // [ERROR] identifier not found: a\nb; // 15\nc; // 20\n```\n\nIt's important to understand that `if` and `if-else` statements are actually expressions because they always return a\nvalue.\n\n1. If a block is executed, the value of the last expression is returned.\n2. If the executed block ends with a statement, it returns `null`.\n3. If no block is executed, the if expression returns `null`\n\n```kotlin\nval x = if (false) { 10 } else { 20 };\nx; // 20\n\nvar y = if (false) { 10 };\ny; // null\n\nval z = if (true) { y = 15; };\nz; // null\n```\n\n## Functions\n\nTo support functional programming, all functions are first-class citizens in Yail.\n\nThis means that they are expressions, so you must assign the function to an identifier to call them.\n\n```kotlin\nval f = func(x) { x + 3; };\nf(5); // 8\nf(6); // 9\n```\n\nThis also means that it's possible to implement higher order functions, functions that take another functions as\narguments or return a function.\n\n```kotlin\nval callTwoTimes = func(x, f) { \n    f(f(x)); \n};\n\ncallTwoTimes(2, func(x) { x * x; }); // 16\ncallTwoTimes(3, func(x) { x * x; }); // 81\ncallTwoTimes(1, func(x) { x + 10; }); // 21\n```\n\n### Scopes\n\nWhen you try to use an identifier inside a function body, evaluator looks up the identifier following these steps.\n\n1. If it's the name of a parameter or a variable declared inside the function, the evaluator uses the bound value.\n2. If it's not one of them, it searches the outer scope.\n3. The 2nd step is repeated until it reaches the outermost scope.\n\n```kotlin\nvar i = 5; \nval useLocalVariableI = func() {\n    return i;\n};\nval useLocalVariableInsideFunction = func() {\n    val i = 15;\n    return i;\n};\nval returnParameterI = func(i) {\n    return i;\n};\n\nuseLocalVariableI(); // 5\nuseLocalVariableInsideFunction(); // 15\nreturnParameterI(10); // 10\ni; // 5\n\ni = 30;\n\nuseLocalVariableI(); // 30\nuseLocalVariableInsideFunction(); // 15\nreturnParameterI(10); // 10\ni; // 30\n```\n\nHowever, you can not reassign the variables that was declared at the outer scope from inside the function.\n\n```kotlin\nvar i = 5; \nval reassignFunc = func() {\n    i = 10; \n}; \nreassignFunc(); // [ERROR] identifier not found: 'i'\n```\n\n### Closures\n\nYail also supports closures, functions that captures the environment on the moment it was declared.\n\nFor example, `closure` function captures the environment that binds the `x` identifier to the argument `2`\nwhen `higherOrderFunc` function is called. After that, when `closure` function is called, it uses the captured\nenvironment instead of using the environment of the scope it is being called. Therefore, `closure` function still\ninterprets `x` as `2`, even though `x` is bound `1000` on the scope it is being called.\n\n```kotlin\nval higherOrderFunc = func(x) {\n    func(y) { x + y };\n};\n\nval closure = higherOrderFunc(2);\nval x = 1000;\nclosure(5); // 7\nx; // 1000\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbugoverdose%2Fyail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbugoverdose%2Fyail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbugoverdose%2Fyail/lists"}