{"id":23270305,"url":"https://github.com/amari-calipso/opal-lang","last_synced_at":"2025-08-21T03:31:47.695Z","repository":{"id":50490833,"uuid":"443180325","full_name":"amari-calipso/opal-lang","owner":"amari-calipso","description":"A programming language based on Python and Cython","archived":false,"fork":false,"pushed_at":"2024-12-08T20:17:26.000Z","size":661,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-08T03:01:37.742Z","etag":null,"topics":["compiler","cython","language-design","language-engineering","programming-language","python","python3","transpiler"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amari-calipso.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-12-30T20:40:29.000Z","updated_at":"2024-12-08T20:17:08.000Z","dependencies_parsed_at":"2024-02-15T02:28:46.893Z","dependency_job_id":"4dbf9b64-7d87-4eef-8d9b-1a2a7c226b7c","html_url":"https://github.com/amari-calipso/opal-lang","commit_stats":null,"previous_names":["amari-calipso/opal-lang"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/amari-calipso/opal-lang","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amari-calipso%2Fopal-lang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amari-calipso%2Fopal-lang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amari-calipso%2Fopal-lang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amari-calipso%2Fopal-lang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amari-calipso","download_url":"https://codeload.github.com/amari-calipso/opal-lang/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amari-calipso%2Fopal-lang/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271420466,"owners_count":24756568,"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","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","cython","language-design","language-engineering","programming-language","python","python3","transpiler"],"created_at":"2024-12-19T18:49:29.622Z","updated_at":"2025-08-21T03:31:47.302Z","avatar_url":"https://github.com/amari-calipso.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿![](logo.png)thanks to aphitorite for the beautiful logo!\n\n# opal\nopal is a transcompiled programming language based on Python and Cython.\n\n# Compiler usage\n[ ] = optional\n* To compile to a Python `.py` file: `opal pycompile input_file [output_file]`\n* To compile to a Cython `.pyx` file: `opal pyxcompile input_file [output_file]`\n* To compile to a Cython module: `opal compile input_file [output_file]`\n* To compile to an executable: `opal release build_file` or `opal pyrelease build_file` (if the program is `--nocompile`). Note that this requires an internet connection to fetch and install dependencies to the target. An opal build file is structured like a [ianthe project file](https://github.com/amari-calipso/ianthe);\n* To directly run opal source: `opal file_name`\n# Command line arguments\n- `--type-mode`\n\t- Selects a default typing mode for the file. Options are:\n\t\t- `hybrid`: The default one. Forces the type when it doesn't create problems, checks otherwise;\n\t\t- `check`: Checks types. Some conversions won't be automatic (for example, assigning a `tuple` to a `list` typed variable won't convert it automatically);\n\t\t- `force`: Always forces types. Can break programs as forced typing can't always be performed;\n\t\t- `none`: Uses dynamic typing for all variables.\n\t- **Usage**: --type-mode mode\n- `--disable-notes`\n\t- Disables notes during compilation\n\t- **Usage**: --disable-notes\n- `--dir`\n\t- Specifies a custom `HOME_DIR` variable.\n\t- **Usage**: --dir path\n- `--static`\n\t- Treats every variable as it cannot change types. Useful for optimization purposes.\n\t- **Usage**: --static\n- `--nostatic`\n\t- Specifies that a program cannot be compiled with the `--static` flag. It's not meant to be used via terminal.\n- `--nocompile`\n\t- Specifies that a program cannot be compiled. Useful for programs that use Python features that are not included in Cython. It's not meant to be used via terminal.\n- `--require`\n\t- Specifies a minimum version of opal that the program requires to run. It's not meant to be used via terminal.\n- `--compile-only`\n\t- Specifies that a program can only be compiled. Useful for programs that use Cython instructions or features. It's not meant to be used via terminal.\n- `--module`\n\t- Specifies that a program is a module. It's not meant to be used via terminal.\n- `--debug`\n\t- Saves the Cython annotations file when compiling for debugging purposes.\n\t- **Usage**: --debug\n# Installation\nTo properly run opal code, you will need to install the Python modules listed in requirements.txt.\n\nopal only supports Python 3.10 and higher.\n\nOnce files are downloaded on your machine, run `opalc.py build` to build the standard library and the runner executable.\n# Hello World!\n```\npackage opal: import *;\n\nmain {\n    IO.out(\"Hello World!\\n\");\n}\n```\n\n# Statements and keywords\n## Defining new items - the `new` statement\nThe `new` statement uses the following syntax:\n```\nnew itemType itemName\n```\n`new` will accept as types:\n- Python integrated types;\n- Custom defined types;\n- `dynamic`\n- opal specific keywords.\n\nExample:\n```\n# this defines the variable and assigns to it\nnew int aNumber = 2;\n\n# this only defines the variable\nnew str name;\n\n# var can accept any type\nnew dynamic var;\n```\n\n### opal specific keywords\n#### `function`\nCreates a function. Example:\n```\nnew function functionName(arg0, arg1) {\n\t# your code here\n}\n```\nThe types of a function's parameter can be specified...\n```\nnew function functionName(arg0: int, arg1: str) {\n\t# your code here\n}\n```\n... default arguments can be defined...\n```\nnew function functionName(arg0: int = 2 + 2, arg1 = \"hi\") {\n\t# your code here\n}\n```\n... and return types can be specified.\n```\nnew function add(a: int, b: int) int {\n\treturn a + b;\n}\n```\n#### `class`\nCreates a class. Example:\n```\nnew class ClassName {\n\t# your code here\n}\n```\nClasses can also inherit content from one or more parent classes:\n```\nnew class ClassName : ParentClassA, ParentClassB {\n\t# your code here\n}\n```\n#### `method`\nCreates a method and passes it the `this` variable, which refers to the class the method is in. `this` is equivalent to Python's `self`. The syntax is the same as a normal function.\n#### `staticmethod`\nCreates a method with a `@staticmethod` decorator. The syntax is the same as a normal function.\n#### `classmethod`\nCreates a method with a `@classmethod` decorator, and passes it the `this` variable. The syntax is the same as a normal function.\n#### `record`\nCreates a basic class containing the specified properties. Example:\n```\nnew record RecordName(arg0, arg1, arg2);\n```\nRecords can also inherit from classes, using the following syntax:\n```\nnew class ParentClass {}\n\nnew record RecordName(arg0, arg1, arg2) \u003c- ParentClass;\n```\n\n## Conditional statements\n### `if`\n`if` statements are equivalent to Python's:\n```\nif someCondition {\n\t# your code here\n} elif someOtherCondition {\n\t# some other code here\n} else {\n\t# do something else\n}\n```\n### `match`\n`match` statements have two implementations. The default one is equivalent to Python's `match` statement:\n```\nmatch aVariable {\n\tcase aValue {\n\t\t# aVariable == aValue\n\t}\n\tcase 2 {\n\t\t# aVariable == 2\n\t}\n\tdefault {\n\t\t# aVariable is not in any of the cases\n\t\t# the default statement should always be last\n\t\t# (or second to last in case a\n\t\t# found statement is used)\n\t}\n\tfound {\n\t\t# this code will execute if any of the cases is met\n\t\t# the found statement should always be last\n\t}\n}\n```\nThe other `match` implementation consists in an `elif` chain. It's accessible by specifying the operator to be used.\n```\nmatch:(!=) aVariable {\n\t# cases here\n}\n```\nif no operator is specified (`match:()`), `==` will be used by default.\n\nNOTE: since Cython doesn't support Python's `match` statement, opal will always fall back to the `elif` chain implementation when compiling.\n### Loops\n#### `while`\n```\nwhile someCondition {\n\t# your code here\n}\n```\n#### `do`\n`do` statements implement a do-while loop:\n```\ndo {\n\t# your code here\n\n\t# the condition will be checked at the end\n\t# of each iteration\n} while someCondition;\n```\nThis syntax is also valid and equivalent:\n```\ndo someCondition {\n\t# your code here\n}\n```\n#### `repeat`\nRepeats code a certain amount of times. Can be either a constant or a variable.\n```\nrepeat times {\n\t# repeating code\n}\n```\n#### `for`\n`for` loops can use either Python syntax...\n```\nfor item in list {\n\t# do something\n}\n\nfor i in range(0, 10) {\n\t# do something else\n}\n```\n... or a C-like syntax:\n```\nfor i = 0; i \u003c 10; i++ {\n\t# do something\n}\n```\nVariables in for loops don't have to be defined separately.\n\nAny of these loops can use `break` and `continue` statements.\n### Exception handling\nopal's exception handling follows Python's syntax, with different keywords.\n```\ntry {\n\t# something that might give an error\n}\n# if a ValueError occurs, do nothing\nignore ValueError;\ncatch Exception as e {\n\t# something went wrong\n} success {\n\t# no error occurred\n\t# you can also use the \"else\" keyword instead of \"success\"\n}\n```\nTo throw exceptions, you can use the `throw` statement, which is equivalent to Python's `raise`.\n### Importing modules\n```\nimport aModule;\n\npackage anotherModule: import item0 as myItem, item1;\n# this is equivalent to:\n# from anotherModule import item0 as myItem, item1\n\npackage aModule: import *;\n# this is equivalent to:\n# from aModule import *\n```\n### Classes\nClass methods can be made abstract. if a class contains an abstract method, the class must be declared abstract as well:\n```\nabstract: new class AnAbstractClass {\n\tnew method add(a, b) {\n\t\treturn a + b;\n\t}\n\n\tabstract: new method anAbstractMethod();\n}\n```\n#### `property`\nYou can create get-set methods for properties by creating a `property`:\n```\nnew class MyClass {\n\tnew method __init__(a) {\n\t\tthis.a = a;\n\t}\n\n\tproperty myProperty {\n\t\tget {\n\t\t\treturn this.a;\n\t\t}\n\t\tset {\n\t\t\tthis.a = value;\n\n\t\t\t# the \"value\" variable name can be changed:\n\t\t\t# set(myValue) {\n\t\t\t#     this.a = myValue;\n\t\t\t# }\n\t\t}\n\t\tdelete {\n\t\t\tdel this.a;\n\t\t}\n\t}\n}\n```\nAny of the methods can be omitted. For example, if the `set` method is not defined, the property will be read-only. Property methods can be set as abstract. A property method can also be defined outside of a `property` statement:\n```\nnew class myClass {\n\tnew method __init__(a) {\n\t\tthis.a = a;\n\t}\n\n\tproperty myProperty {\n\t\tget {\n\t\t\treturn this.a;\n\t\t}\n\t\tdelete {\n\t\t\tdel this.a;\n\t\t}\n\t}\n\n\tset\u003cmyProperty\u003e(myValue) {\n\t\tthis.a = myValue;\n\t}\n}\n```\n### `main`\nThe `main` statement acts as syntax sugar for the form `if __name__ == \"__main__\":`.\n```\nmain {\n\t# this code will only be executed if the script\n\t# is not imported\n}\n\nmain() {\n\t# using brackets generates a main function.\n\n\t# defining one is not mandatory, but it's\n\t# generally good practice. only one main\n\t# function can be defined\n}\n```\n### `use`\nCreates an identifier. This is necessary as every identifier mentioned at the beginning of an expression statement must be known at compile-time.\nFor example:\n```\nnew function a(x) {\n\tb(x - 1);\n}\n\nnew function b(x) {\n\tif x \u003c 2 {\n\t\ta(x);\n\t}\n}\n```\nHere, the compiler will give us an error:\n```\nerror (in test.opal: a(), line 2, pos 4): unknown statement or identifier\n 1 | new function a(x) {\n 2 |     b(x - 1);\n   |     ^\n 3 | }\n 4 |\n 5 | new function b(x) {\n```\nTo solve this, we can create the identifier ourselves:\n```\nuse b;\n\nnew function a(x) {\n\tb(x - 1);\n}\n\nnew function b(x) {\n\tif x \u003c 2 {\n\t\ta(x);\n\t}\n}\n```\n### `namespace`\nCreates a namespace. Effectively just a class that can't inherit from other classes and can't be instantiated.\n```\nnamespace MyNamespace {\n\t# your code here\n}\n```\n### `enum`\nCreates a set of variables contaning distinct constants:\n```\nenum MyEnum {\n\tCONST0, CONST1, CONST2\n}\n\n# MyEnum.CONST0 == 0\n# MyEnum.CONST1 == 1\n# ...\n```\nThe values of each constant can be chosen when defining the `enum`:\n```\nenum MyEnum {\n\tCONST0 = \"hi\",\n\tCONST1 = 2,\n\tCONST2 = 3.14\n}\n```\n`enum`s can also be defined with no name. In that case, the constants get created as actual variables hidden behind no namespace:\n```\nenum {\n\tCONST0, CONST1, CONST2\n}\n\n# you can now access the variables directly\n# for example:\nnew int myVariable = CONST0 + CONST1;\n```\n### `unchecked`\nThe `unchecked` flag is used to ignore typing on an assignment or skip checks on other statements. Statements to which the `unchecked` flag can be applied are:\n- `repeat`: skips the conversion to an absolute int;\n- `return`: ignores type checking.\nExample:\n```\nnew int a = 2 + 2;\nunchecked: a += 2;\n\nunchecked: repeat a {\n\t# your code here\n}\n\nnew function add(a: int, b: str | int) int {\n\tif type(b) is int {\n\t\tunchecked: return a + b;\n\t}\n\n\treturn a + int(b);\n}\n```\n### `static`\nThe `static` flag is used to indicate whether a variable or a block of variables will not change type. This is used to apply optimizations during compilation. Example:\n```\nstatic {\n\tnew int a;\n\tnew float b = 2.0;\n}\n\nstatic: new int c = 3;\n\nstatic:\nnew function myFunction() {\n\t# every variable here will be static\n}\n\nstatic:\nnamespace Test {\n\t# every variable here will be static\n}\n```\n### `inline`\nThe `inline` flag tries to inline an optimizable function during compilation. The compiler will throw an error if the function to be inlined is not optimizable.\n```\ninline:\nnew function add(a: int, b: int) int {\n\treturn a + b;\n}\n```\n### `global`\nThe `global` flag is used to declare an object in the global scope.\n```\nnew function aFunction() {\n\tglobal: new int a = 2, b = 3;\n\n\tglobal:\n\tnew function anotherFunction() {\n\t\t# do something\n\t}\n}\n\n# a, b, and anotherFunction will be visible here with a \"use\" statement\n```\n### Python equivalents\nSome statements are direct equivalents of Python statements or functions. Here's a list of opal statements that haven't been mentioned yet and their Python equivalents:\n```\n  opal   | Python\n--------------------\nasync    | async\nawait    | await\nwith     | with\nsuper    | super()\ndel      | del\nassert   | assert\nyield    | yield\nglobal   | global\nexternal | nonlocal\n```\nopal supports decorators, using the same syntax as Python:\n```\n@myDecorator;\nnew function myFunction() {}\n```\n# Precompiler\n## Comments\nComments are marked with the `#` symbol and extend until a newline is found.\n## Statements\n### `$define`\nDefines a constant.\n```\n$define constantName constantContent\n```\n### `$pdefine`\nDefines a constant that is only visible to the precompiler.\n```\n$pdefine constantName constantContent\n```\nopal will automatically create some \"pconstants\" you can use:\n- `HOME_DIR`: points to the base directory of the given file;\n- `CY_COMPILING`: a `bool` that indicates whether the compiler is compiling in Cython mode;\n- `RELEASE_MODE`: a `bool` that indicates whether the compiler is compiling in release mode;\n- `TARGET_FILE`: a `str` that points to the file opal is generating. It's `None` when opal is directly running code.\n### `$include`\nIncludes a Python or opal file inside an opal file. Expects a `str` or path-like argument (it gets evaluated using Python's `eval`). Usage of the `os` module is allowed and recommended, especially to join directories and filenames.\n```\n$include os.path.join(HOME_DIR, \"myFile.opal\")\n```\n### `$includeDirectory`\nIncludes every `.py` and `.opal` file in a given directory. Expects a `str` or path-like argument.\n```\n$includeDirectory os.path.join(HOME_DIR, \"myFolder\")\n```\n### `$macro`\nDefines a macro. A macro is a basic function that gets called with no overhead, since its body is copy-pasted into calls. Avoid using this too often since it can quickly increase the result file size. The body of the macro is anything between the `$macro` statement and an `$end` statement. Macros can be defined with no arguments...\n```\n$macro sayHi\n\tIO.out(\"Hi!\\n\");\n$end\n```\n... or with arguments. Arguments do not accept types and a default value cannot be set.\n```\n$macro add(a, b)\n\tnew int result = a + b;\n$end\n```\nMacros are called using the `$call` statement:\n```\n$call sayHi\n$call add(2, 4)\n```\n### `$if`\nExports a block of code (all the way until an `$end` statement) if a condition is `True`.\n```\npackage opal: import *;\n\n$define GREET_USER True\n$if GREET_USER\n\tIO.out(\"Hi, user!\\n\");\n$end\n```\nAn `$else` statement is also available:\n```\npackage opal: import *;\n\n$define GREET_USER True\n$if GREET_USER\n\tIO.out(\"Hi, user!\\n\");\n$else\n\tIO.out(\"Sorry, user. No greeting this time :(\\n\");\n$end\n```\n\nThe same action can also be performed through the `comptime` statement, though it's much slower. `$if` is useful for both simplicity and faster compile times, especially when working with large blocks of code.\n### `$comptime`\nDefines a block of code (all the way until an `$end` statement) that will run during compilation. If an exception is thrown during this stage, the compiler will throw an error. In combination with the `$export` and `$exportBlock` statements, it can be used for conditional code generation. Example:\n```\n$define USE_CUPY False\n\n$comptime\n\tif USE_CUPY {\n\t\t$export import cupy as numpy;\n\t} else {\n\t\t$exportBlock\n\t\t\timport numpy;\n\t\t\t?\"running with numpy\";\n\t\t$end\n\t}\n$end\n```\n\nThe `COMPTIME_EXPORT_VARS` global dictionary can be used to create variables that can be read by export blocks. For example:\n```\n$define ADDING_WATER_DROPLETS True\n\n$comptime\n\tif ADDING_WATER_DROPLETS {\n\t\t$export new int ONE_PLUS_ONE = 1;\n\t} else {\n\t\tCOMPTIME_EXPORT_VARS[\"onePlusOneResult\"] = str(1 + 1);\n\t\t$export new int ONE_PLUS_ONE = onePlusOneResult;\n\t}\n$end\n```\n### `$nocompile`\nTells the precompiler to directly transcribe code to the result until a `$restore` statement. In practice, it allows to use Python or Cython code inside opal. Code in `$nocompile`-`$restore` blocks should be put on a \"null indentation\", for example:\n```\nif a != b {\n\tif a \u003c b {\n\t\t$nocompile\n\nfor i in range(a, b):\n\tif i \u003e 2:\n\t\tprint(i)\n\n\t\t$restore\n\t}\n}\n```\nThis is needed because opal will add to the base indentation an inferred indentation, that is based on the code logic. This allows to directly import Python or Cython source files with no syntax errors.\n### `$embed`\nDirectly transcribes a line of code to the compiled result. Useful to avoid the `$nocompile`-`$restore` syntax for one-liners.\n```\nif a != b {\n\tif a \u003c b {\n\t\tfor i in range(a, b) {\n\t\t\tif i \u003e 2 {\n\t\t\t\t$embed print(i)\n\t\t\t}\n\t\t}\n\t}\n}\n```\n### `$args`\nPasses the compiler some default arguments. Supported arguments are:\n```\n--static, --nostatic, --nocompile, --compile-only, --type-mode, --require\n```\nExample:\n```\n$args [\"--static\", \"--type-mode\", \"check\", \"--require\", \"2023.11.9\"]\n```\n### `$cy`\nCreates Cython decorators if the compiler is transcompiling to Cython. Avoids errors when running a program in \"Python mode\". It uses the following syntax:\n```\n$cy flag_name value\n```\nand translates to:\n```\n@cython.flag_name(value)\n```\n... For example:\n```\n$cy nonecheck False\n$cy cdivision True\ninline:\nnew function divide(a: float, b: float) float {\n\treturn a / b;\n}\n```\n### `$cdef`\nApplies the Cython `cdef` keyword to the next element when possible or forces a C definition on unknown types. For example:\n```\n$cdef\nnew function add(a: int, b: int) int {\n\treturn a + b;\n}\n\n$embed from cpython.mem cimport PyMem_Malloc, PyMem_Free\nnew function mallocTest() {\n\tuse PyMem_Malloc, PyMem_Free;\n\n\t$cdef\n\tnew (int*) memory = \u003cint*\u003ePyMem_Malloc(20 * sizeof(int));\n\n\tmemory[0] = 2;\n\tPyMem_Free(memory);\n}\n```\n# Operators\nSince opal directly passes expressions to Python, that is, it doesn't parse them, Python operators are all usable, with\na few additions:\n- `!`: Equivalent to Python's `not`. If used at the beginning of a line with a variable name, it will invert the state of that variable:\n```\n!variable; # is equivalent to variable = !variable;\n\nnot variable; # this also produces the same result\n```\n- `||`: Equivalent to Python's `or`;\n- `\u0026\u0026`: Equivalent to Python's `and`;\n- `?`: It's used for debugging purposes. It prints the given expression and returns it:\n```\nmyFunction(a, ?(b), c);\n# the content of b will be printed\n\n?c;\n# the content of c will be printed\n```\n- `\u003c-`: It's used to convert variables to a type during an assignment:\n```\nnew int a = 2;\n# type of a is int\n\nfloat \u003c- a = 3;\n# type of a is float\n\ndynamic \u003c- a = Vector(2, 3);\n# type of a is dynamic\n```\nTyping used with the arrow operator follows the same rules as types in the new statement.\n- `++` and `--`: They work as increments (respectively `+= 1` and `-= 1`). They are only allowed as statements, that is,\nthey can't be used inside expressions. They can be used inside the first and last parts of a C-like for statement, and\ninside an inline type conversion (arrow operator). These syntaxes are all valid:\n```\nnew int var = 0;\nvar++;\nvar--:\n\n--var; # this \"operator-first\" syntax is only allowed as a statement alone,\n# that is, for example, it won't work in a for loop.\n++var;\n\nfloat \u003c- var++;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famari-calipso%2Fopal-lang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famari-calipso%2Fopal-lang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famari-calipso%2Fopal-lang/lists"}