{"id":20230123,"url":"https://github.com/lochbrunner/chop-specs","last_synced_at":"2026-03-06T12:32:28.966Z","repository":{"id":96227511,"uuid":"129132374","full_name":"lochbrunner/chop-specs","owner":"lochbrunner","description":"Chop Language Specifications","archived":false,"fork":false,"pushed_at":"2023-03-27T14:11:04.000Z","size":73,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-03T13:31:33.131Z","etag":null,"topics":["language-modeling","llvm-ir","specification"],"latest_commit_sha":null,"homepage":"","language":null,"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/lochbrunner.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":"2018-04-11T17:47:11.000Z","updated_at":"2023-02-11T15:30:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"9bb85687-a9f8-4f93-a6a1-997847ce692a","html_url":"https://github.com/lochbrunner/chop-specs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lochbrunner/chop-specs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lochbrunner%2Fchop-specs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lochbrunner%2Fchop-specs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lochbrunner%2Fchop-specs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lochbrunner%2Fchop-specs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lochbrunner","download_url":"https://codeload.github.com/lochbrunner/chop-specs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lochbrunner%2Fchop-specs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30176230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T11:48:51.886Z","status":"ssl_error","status_checked_at":"2026-03-06T11:48:51.460Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["language-modeling","llvm-ir","specification"],"created_at":"2024-11-14T07:38:24.593Z","updated_at":"2026-03-06T12:32:28.934Z","avatar_url":"https://github.com/lochbrunner.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Chop Language Specifications\n\n## Motivation\n\nA typical day of a software engineer is often wasted with either fighting against the compiler, (e.g. unnessary type annotation is wrong, hard to understand compiler error messages) or late occuring bugs (e.g. a typo in a dynamicly typed language causes an experiment to fail).\nThis language tries to free software engineers from long and tidious debugging sessions and over complicated source code.\n\nAs it is often hard to predict which design choice might be better, there are sometimes mulitple redundant features in this language that addresses one single problem.\nAfter it turned out that one of those does not provide any real benefit, it might been dropped in the future.\n\n\u003e Combine the top features of existing programming languages into one consistent and non-verbose and plausible programming language.\n\n* System language (inspired by Rust)\n* Powerful but simple language: Unifies the syntax of similar use cases to be consistent with minimal exceptions.\n* Extendable by the User: Using the same language for program, meta-programming and build configuration\n* The complexity of the source code should be linear in the complexity of the problem.\n* One language for shell scripting and system programing. (Unification of Bash, Python and C++)\n\nAll features of that language are specified by examples.\n\n## Addressed Pain Points\n\n* Runtime dispatching makes it hard follow the code path. Compile time dispatching might be a solution.\n* Configuration managment is mostly a diffcult tradeoff. (E.g. overwriting, forwarding, ...)\n* Adding valueable debug information at different layers of a callstack for thrown an exception.\n* Difficult and limited macro definition syntax. \n\n## Features\n\n* Static and structural typed (Most type and lifetime annotations can be omitted due to inferring capability of the compiler)\n* Meta programming should look and feel as the *runtime* code. With language server support\n* Zero runtime cost abstraction (-\u003e No *GC*)\n* Few keywords and syntactical exceptions.\n* Allows expressive code (less boilerplate than *rust*)\n* Also suitable for creating proprietary and/or certified libraries (using secret store)\n* Consistent and easy build and dependency management.\n* Generating docs out of the code (empowered by meta-programming)\n* Experimental: Dynamic memory allocation on the stack (bind to the scope)\n\nTools\n\n* Compiler (no need for linter)\n* REPL\n* Formatter\n* Language Server\n\nInspired by\n\n* C: The syntactical base\n* rust: move semantic, borrowing and lifetime\n* Go: syntax and module system\n* Scala: syntax\n* JavaScript (TypeScript): module system, syntax\n\nSee [Proof of Concept](https://github.com/lochbrunner/chop-compiler) implementation.\n\n## Examples\n\n### Variables\n\nDefine and declare a local variable:\n\n```code\nx := 1\n```\n\nwith explicit type\n\n```code\nx := cast\u003cint32\u003e(1)    // or\nx := 1.as\u003cint32\u003e       // or\nx: int32 := 1\n```\n\nDefine a public variable:\n\n```code\nx :+ 1\n```\n\nwhich can be accessed from outside the block:\n\n```code\na := {b:+12}.b  // a is now 12\n```\n\n#### Alternative\n\n```code\n.x := 1\n```\n\n### Mutable variables\n\n```code\nmut x := 1      // declaration\nx \u003c- 2          // assignment\n```\n\n\u003e Note: `\u003c-` is just an operator defined for integers. For instance sending messages to a channel.\n\u003e This could be have other behavior for other types.\n\n### Shadowing\n\nInspired by rust\n\n```code\na := \"12.34\"\na := parse(a)       // Shadows the variable declaration above\n```\n\n### Ownership, Borrowing and Box\n\nTaken from rust.\n\n### Numbers\n\nThese lines are equivalent\n\n```code\na := 12\na := {\n    foo(2)  // Doing some computation\n    4       // Gets ignored here\n    12      // Last expression gets returned as a default\n}\n```\n\n### Strings\n\n```code\na := \"Hello, World\"\n```\n\nString-interpolation (Scala)\n\n```code\na:= s\"Hello $name ${obj.foo}\"\n```\n\nGets expanded to\n\n```code\na:= \"Hello \" + name.to_string + obj.foo.to_string\n```\n\nUsing different formatters\n\n```code\na:= \"Today is ${date|\"YYYY/MM/DD\"d}\"\n```\n\nWhere `\"YYYY/MM/DD\"d` creates a function which formats the given date into a string or object which contains the `to_string` method. This must be registered via:\n\n```code\npostfix d := (code: str) =\u003e (date: Date) =\u003e {\n    // Some code returning the formated date string\n}\n```\n\nor:\n\n```code\nString.d := (code: str) =\u003e (date: Date) =\u003e {\n    // Some code returning the formated date string\n}\n```\n\nWhich defines the method `.d` to Strings.\n\nString concatenation\n\n```code\na := \"Hello \"\nb := \"World!\"\nc := a + b\n```\n\n### Alias\n\nYou can give many \"things\" an alias name, which get resolved at compile time\n\n```code\nx = 12\ny :- x                      // This is an alias for x\n\ny \u003c- 14\nstderr.write(x)             // Prints 14 to the std err\n```\n\n### Objects\n\nAn object is nothing else than a scope with public variables.\n\n```code\nobj := {\n    a :+ 12\n    b :+ a * 3\n}\n```\n\nor alternativly:\n\n```code\nobj := {\n    .a := 12\n    .b := a * 3\n}\n```\n\nof\n\n```code\nfactory(arg: int) := {\n    a :+ arg\n    b :+ arg * 3\n}\n\nobj := factory(12)\n\n```\n\nAnonymous members\n\n```code\nbase = {\n    a :+ 12\n    b :+= a * 3\n}\n\nobj = {\n    ...base\n    c :+ 4\n    d :+ \"Hello\"\n}\n```\n\nhere `obj` is equivalent to\n\n```code\nobj := {\n    a :+ 12\n    b :+ a * 3\n    c :+ 4\n    d :+ \"Hello\"\n}\n```\n\n### Special Method: Destructor\n\nIn order to specify the behavior when some object lifetime reaches it's end.\n\n```code\nobj := {\n    ~ :+ () =\u003e {\n        // Do some clean up stuff\n    }\n}\n```\n\n#### Open Point on Movement and object construction\n\n```code\ni := 12\nobj := {\n    a :+ i\n}\n```\n\nIs `i` then moved into the object and no longer valid?\n\n## Enums\n\nEnums can either be implemented as integers (C++) or as strings (Typescript).\n\nThe representation are always strings\n\n```code\ntype MyEnum = \"One\" | \"Two\" | \"Three\"\n```\n\nIt is possible to use them for pattern matching (see later).\n\n```code\n\ntype MyEnumA = \"One\" | \"Two\" | \"Three\"\ntype MyEnumB = \"Four\" | \"Five\" | \"Six\"\n\nx: MyEnumA | MyEnumB\n// assign some stuff to x\n\ny := match x {\n    case a: MyEnumA =\u003e fooA(a)\n    case b: MyEnumB =\u003e fooB(b)\n}\n```\n\n\u003e Note: Consider using the type constraints as values too. Using meta programming.\n\n## Builtin Types\n\n* Integral types\n  * `i8`\n  * `i16`\n  * `i32`\n  * `i64`\n  * `u8`\n  * `u16`\n  * `u32`\n  * `u64`\n* Floating point types\n  * `f32`\n  * `f64`\n\n## Arrays\n\n```code\na := i32[10]\nb := i32[n]         // Figure out, if this is possible\n```\n\n\u003e Are arrays always extendable?\n\n## Containers\n\nShould be implemented as \"template\" types in **chop** itself.\n\n* String: `string`\n* String Builder: `string_builder` ?\n* Hash map: `map\u003cType\u003e`\n* C++ `std::vector` : `vector`\n\n## Named Types\n\nOr Interfaces\n\n```code\ntype MyType = {\n    a: i32\n    b: string\n    c: {\n        d: i32\n    }\n}\n```\n\nAlternative syntax\n\n```code\nMyType :- {\n    a: i32\n    b: string\n    c: {\n        d: i32\n    }\n}\n```\n\nAnother alternative syntax\n\n```code\nMyType :- {\n    pub a: int\n    pub(1) b: string\n    c: {\n        d: int\n    }\n}\n```\n\nWhile `1` is the number of scope levels.\n\nExtending types\n\n```code\ntype MyExtendedType = {\n    d: float32\n    ...MyType\n}\n```\n\n\nQuestions: Is this possible?\nProblems:\n\n* Difference between types and scopes:\n  * In types everything is public. Really? Consider scoping of Rust.\n\n### Methods\n\nTypes have a special mutability that allows to extend (non virtual) methods.\n\n```code\nMyType :- {\n    a: i32\n}\n\nMyType.foo :- (self, b: i32) =\u003e self.a + b\n\nobj := {a:+ 43}\nstdout obj.foo(21)\n```\n\n### Combining types\n\nHaving\n\n```code\ntype TypeA = {\n    a: i32\n    c: i32\n}\n\ntype TypeB = {\n    b: i32\n    c: i32\n}\n```\n\nthen\n\n```code\ntype TypeAAndB = TypeA \u0026 TypeB\n```\n\nresults in\n\n```code\ntype TypeAAndB = {\n    a: i32\n    b: i32\n    c: i32\n}\n```\n\nand\n\n```code\ntype TypeAorB = TypeA | TypeB\n```\n\nresults in\n\n```code\ntype TypeAorB = {\n    c: i32\n}\n```\n\n\u003e Note you can not create space for every composed type as value on the stack. The full power of composed type are only available when they are of shared ownership.\n\n### Constraints on types\n\n```code\ntype Evens = 2*i with i: int32\n```\n\n### Object Destructuring\n\nUsing alias for destructuring\n\n```code\ntype SampleType = {\n    a: i32\n    b: string\n    c: {\n        d: float\n    }\n}\n\nobj: SampleType = ...\n{a} := obj                  // a is moved out of obj\n{a} :- obj                  // a is now a short descriptor for obj.a\n// With renaming\n{x :- a, y :- c.d} :- obj\n```\n\n## Dimensional Analysis\n\nInspired by: [nholthaus/units](https://github.com/nholthaus/units)\n\nDefining units as\n\n```code\nunit\u003cu32\u003e Duration { // Supports only u32\n    s\n}\n\nunit Mass {\n    kg\n}\n\nunit Length {\n    m\n}\n\nunit Force {\n    N,\n    kg*m/s/s\n}\n```\n\nThe dimension `force` is introduced with units abbreviation `N` which is equal to the previous defined units `kg*m/s/s`.\nThey are applied automatic to each numerical primitive.\nDimensions get computed automatically when using the operators `+`, `-`, `*` and `/`.\n\n```code\nfoo := (force: Force\u003cint32\u003e) =\u003e {\n    //...\n}\n\n// Calling\nfoo(12N)\n\n// or\nlet l = 13m\nlet m = 3kg\nlet t = 3s\n\nfoo(m*l/t/t)\n```\n\nDimensional analysis is performed during compile time.\n\n\u003e Note: Can this feature be introduced using meta programming?\n\nPossible solution: Each token which can not be parsed with standard tokenizer get tried to match with registered extension implemented via meta programming.\n\n\u003e Open point: Should this be constrained in order to increase readability of the code?\n\n## Functions\n\n```code\nfoo := (a: i32) =\u003e {\n    a * a\n}\n```\n\nwith explicit type\n\n```code\nfoo: i32 -\u003e i32 := (a: i32) =\u003e {\n    a * a\n}\n```\n\nor\n\n```code\nfoo(a: i32) := {\n    a * a\n}\n```\n\nor simply\n\n```code\nfoo(a: i32) := a * a\n```\n\nYou can create template function when using the `any` type\n\n```code\nfoo(a: any) := {\n    a * a\n}\n```\n\n\u003e The keyword `any` can be omitted in most situations due this does not provide useful information.\n\u003e\n\u003e Note: If the given type has no definition for the `*` operator, you get a compiler error.\n\n```code\nfoo(a: any) := {\n    a * a\n}\n\ns := foo(\"Hello\")       // Compiler error\nt := foo(3)             // Ok\n```\n\nUsing a type as anonymous argument:\n\n```code\ntype Argument = {a: i32}\nfoo := (Argument) =\u003e {\n    a * a\n}\n```\n\nis not the same as\n\n```code\ntype Argument = {a: i32}\nfoo := (arg: Argument) =\u003e {\n    arg.a * arg.a\n}\n```\n\n\u003e Hint: You can skip the curly bracket if there is only one expression.\n\n### Syntactical Sugar\n\n#### Block as argument\n\n\u003e Under discussion\n\n```code\ndo_twice(code: Body) := {\n    code\n    code\n}\n```\n\nPossible use case implementing of *defer*.\n\n#### Leaving round brackets\n\nSimilar to Groovy\n\n\u003e Under discussion\n\n```code\nprint := (text) =\u003e {\n    // ...\n}\n\n\n// Usage\nprint \"Hello, World!\"\n```\n\n### Generic functions\n\n\u003e Note: By default the functions have generic argument types.\nThey get constraint by the compiler identifying their use.\nThis means that all constraints must be available in the intermediate language description of the libraries.  \n\n### Higher order functions\n\n```code\nfoo := (arg1: i32) =\u003e (arg2: i32) =\u003e arg1 * arg2\n```\n\n### Argument binding\n\n```code\nfoo := (arg1: i32) =\u003e (arg2: i32) =\u003e arg1 * arg2\nfoo1 := foo(12)\n```\n\n### Scope of Parameters\n\nBy default parameters have block scope and therefor it uses \"call by value\"\n\n```code\nfoo := (x: i32) =\u003e {}\n\nfaa := (x: \u0026i32) =\u003e {}\n\ni := 12\nj := 13\nfoo(i.clone)    // A copy of i gets moved to foo\nfoo(i)          // i itself gets moved to foo\nfoo(i)          // error: i was moved before\nfaa(\u0026j)         // j gets borrowed\n```\n\n### Extensions\n\n```code\nMyType.foo := (a: i32) =\u003e {\n    this.a = a\n}\n```\n\nAssigning extensions to multiple types:\n\n```code\n(MyType1 | MyType2).foo := (a: i32) =\u003e {\n    this.a = a\n}\n```\n\n\u003e Note Extensions are immutable. Which means you can not assign an extension function with the same name and signature to type.\n\n```code\nMyType.foo \u003c- (a:i32) =\u003e {}     // error \u003c- to undeclared foo is not allowed\n```\n\nVirtual functions are only allowed to instances and not to types.\n\n### Operators\n\n\u003e type `#` precedence operator-name `:=` or `:+` `(` argument(s) `)` `=\u003e` definition.\n\nWith\n\n* **type** is one of `infix`,  `postfix` or `prefix`\n* **precedence** specifies the order of evaluation compared to other operators. Must be `SUM`, `PRODUCT` or `EXPONENTIAL`. With a leading `\u003c` or `\u003e` you can specify the precedence one lower or higher than the specified one.\n\nExample:\n\n```code\ninfix#SUM + := (left, right) =\u003e left.unwrap + right.unwrap\n```\n\nWhich can be attached to each type which has `+` operation defined.\n\n\u003e Hint: This can be used for creating iterators used by for loops.\n\n### Experimental\n\n#### Constructor Sugar\n\nInspired by Scala's primary constructor.\n\nInstead of creating a object with:\n\n```code\nfactory := (a, b) =\u003e {\n    a :+ a\n    b :+ b\n    c :+ a + b\n}\n```\n\nWrite\n\n```code\nfactory := (a:+, b:+) =\u003e {\n    c :+ a + b\n}\n```\n\nWhere `a` and `b` gets captured.\n\n#### Batch processing\n\n```code\ntransform := (x) =\u003e x * 2 + 3\n\na,b := transform(3,5)\n// a = 9\n// b = 13\n```\n\nBetter\n\n```code\ntransform := _ * 2 + 3\n\na,b := transform(3,5)\n// Or\na,b := (3,5)*2+3\n// a = 9\n// b = 13\n```\n\n## Piping\n\n**Experimental!**\n\nInspired by Unix Pipes\n\n**Needs refinement**\n\n### Channels\n\n```code\nmy_channel: channel\u003ci32\u003e\n\nfoo := () =\u003e {\n    result: i32;\n    // Do some magic\n    // ...\n    result\n}\n\nlazy my_channel \u003c\u003c foo()\n// Nothing happened so far\n\ni :\u003c\u003c my_channel       // Here foo gets called\n```\n\nUsing as a generator\n\n```code\nfibonacci := () =\u003e {\n    {receiver, sender} := channel\u003ci32\u003e::new\n    i = 0\n    j = 1\n\n    // The lazy loop gets only evaluated when the someone reads from the channel\n    lazy loop {\n        t := i + j\n        i \u003c- j\n        j \u003c- t\n        sender \u003c\u003c t                 // This line triggers the lazy loop\n    }\n    receiver\n}\n\nfor value in fibonacci.iter.take(5) {\n    stderr.print(value)\n}\n```\n\nOr is it better to use `yield return` ?\n\nPrints the first five Fibonacci numbers to the standard error.\n\n### Pipe compositions\n\nUnnamed pipe:\n\n```code\ncomposition := foo | faa | fuu\n```\n\nWhich is the same as\n\n```code\ncomposition := (arg1 : ArgType1) =\u003e {\n    fuu(faa(foo(arg1)))\n}\n```\n\nUsing space is equivalent to newline:\n\n```code\ncomposition :=\n    foo\n    | faa\n    | fuu\n```\n\nCreating a switch:\n\n```code\n// this function has 2 unnamed output pipes\nswitch: FooOutputType -\u003e \u00262 := (input: FooOutputType) =\u003e {\n    loop {\n        i :\u003c\u003c input\n        if ...\n            \u00260 \u003c\u003c ...        // Write to first pipe\n        else\n            \u00261 \u003c\u003c ...        // Write to second pipe\n    }\n}\n\ncomposition :=\n    foo\n    | switch\n    \\ fuu       // Uses output of the first pipe of the switch\n      | faa     // Uses the output of fuu. Note: faa is not \"multi-piped\"\n    \\ fee       // Uses the output of the second pipe of the switch\n```\n\nHints:\n\nYou can *name* the unnamed pipes\n\n```code\nmy_pipe :- \u00261;\nmy_pipe \u003c\u003c ...\n```\n\nAccessing the pipes dynamically\n\n```code\nfoo := () =\u003e {\n    i := 0\n    \u0026$i \u003c\u003c ..       // You have to specify the number of output pipes when using this\n}\n```\n\nReturning named pipes:\n\n```code\nswitch: FooOutputType -\u003e \u00262 := (input: FooOutputType) =\u003e {\n    loop {\n        i :\u003c\u003c input\n        if ...\n            good \u003c\u003c 12        // Undeclared pipes are output types automatically\n        else\n            bad \u003c\u003c 34\n    }\n}\n\ncomposition :=\n    foo\n    | switch    // Compiler knows that switch has these two *output* pipes\n    \\bad sorry\n    \\good hurray\n\n```\n\n\u003e Note: Can this be archived with Monads?\n\n### Implementation\n\n\u003e Pipes are defined via ordinary operator definitions\n\n## Environment Variables\n\n* Inspired by unix shell\n* Can be used for *dependency injection*\n* Keywords: `set` and `require`\n\n### Motivation\n\nForwarding parameters though a long\n\n### Examples\n\n```code\nfoo(x) =  {\n    require a: logger: (string) =\u003e void\n    require a: i32\n    logger(\"Entering foo\")\n    b := a              // Accessing variable of caller\n}\n\n{   // Defining a new scope\n    set logger(msg: string) := stderr.write(msg.toString)\n    set a := 12\n    foo(12);\n}\n```\n\n\u003e TODO: Using alternative syntax `:\u003e` and `:\u003c` ?\n\nSourcing\n\n```code\nlazy env := {\n    set logger = (msg: string) =\u003e stderr.write(msg.toString)\n}\n\n{\n    source env  // Getting the logger\n    logger(\"Hello, World!\")\n}\n\n```\n\n\u003e TODO: Can be converged with the `:-` operator ala: replace `lazy env := {...}` with `env :- {...}` ?\n\n### Alternative\n\nUse `**kwargs` concept from Python, but type checked and not implemented as a dictionary.\n\nMaybe something like this:\n\n```code\nbar := (...kwargs) =\u003e {\n    b: i32 := kwargs.b\n}\n\nfoo := (a: i32, ...kwargs) =\u003e {\n    bar(..kwargs)\n}\n\nfoo(a=1, b=2)\n```\n\n## Control Statements\n\nDeclaration inside condition\n\n```code\nif x := foo() \u003e 0 {     // x is immutable\n    stderr.write(x);\n}\n```\n\nNaming blocks with `:-` get executed directly.\nThey can be used for accessing with `break`, `continue` and `goto`.\n\n```code\nnamed_block :- {\n    // So something\n}\n```\n\n```code\nouter_loop :- for i in [1..10] {\n    inner_loop :- for j = [1..i] {\n        if ... continue inner_loop;\n        if ... break outer_loop;\n    }\n}\n```\n\n**Consequence**\n\n```code\na :- if x :+ foo() \u003e 0 {}\nx = a.x                     // x has now the value of foo()\n```\n\n## Pattern Matching\n\n```code\ny := match x {\n    t: Type1 =\u003e t.foo()            // Match concrete type\n    s: any \u0026 {m: i32} =\u003e s.m       // `x` contains integer member `m`\n    u: any \u0026 {m: 12} =\u003e 34         // `x` member `m` has value `12`\n    x \u003e 10 =\u003e 36                   // `x` is larger than 10\n}\n```\n\nNote the syntax is very similar to function definitions.\nTherefore you can create runtime dispatcher like that.\n\n```code\nfoo_caller := (t: Type1) =\u003e t.foo() \nm_accessor := (s: any \u0026 {m: i32}) =\u003e s.m\nspecial_m_member := (u: any \u0026 {m: 12}) =\u003e 34\ngreater_than := (x \u003e 10) =\u003e 36\n\ny := match x {\n    foo_caller\n    m_accessor\n    special_m_member\n    greater_than\n}\n\ngeneric_foo := match {\n    foo_caller\n    m_accessor\n    special_m_member\n    greater_than\n}\n```\n\n## Module Concept\n\nGoal: Merge EcmaScript5 module concept with access-level concept of objects.\n\nThe module concept is similar to that of EcmaScript5.\n\nThe source files or IL files of each library defines its own module.\n\nYou can import other modules either if their are available as source or as IL files with the function `import`:\n\nExample: Importing local file *./package/module.chop*\n\n```code\nmodule_x :- import ./package/module_x     // The extension is skipped\n```\n\n`import` does not need be implemented in the compiler itself. It is implemented in a default imported module using meta-programming.\nYou can think of that as if the compiler would insert a `{` in the first line and `}` at the last line of the imported file and paste them into the importing file.\n\nThis means the imported file gets its own scope named *module_x* here and therefore only the declarations marked as `public` (`internal` see later) can be used here.\n\nSimilar to the Unix path convention you can import \"global\" modules when you leaf the `./` prefix of the module name. Then the compiler tries to find that file at some specific paths.\n\nNote that you can rename imported modules via\n\n```code\nnew_module_name :- import old_module_name\n```\n\nIt is also possible to import modules from public repositories. For instance\n\n```code\nmodule_x :- import www.github.com/publisher/package/module_x     // The extension is skipped\n```\n\nEven if the source code is not public, it is also possible to import the IR code of the package without limitations.\n\n### Creating bundles\n\nUnfortunately it is not convenient to import a bunch of modules only to use several functionalities of on library.\n\nTo avoid the author of the library can bundle there functionality via re-imports.\n\nThe main_module might look as:\n\n```code\nsub_module_a :+ import ./sub_module_a\nsub_module_b :+ import ./sub_module_b\n```\n\nThis can be imported as\n\n```code\nimport ./main_module\n\nlet x:= main_module.foo_a\n```\n\nYou can make them public under a new name\n\n```code\nimport ./sub_module_a\n\npublic feature_a := sub_module_a\n```\n\nIf one module has the name *index.ext* it gets implicit imported when you specify the containing folder in the import statement.\n\nFor instance you have the following folder structure in your library:\n\n```text\nmy_library\n|- index.ext\n|- sub_module_a\n|  |- index.ext\n|  |- any_sub_sub_module.ext\n.\n.\n.\n```\n\nIn the root *index.ext* you can import the \"folder\" *./sub_module_a* which implicit would import *./sub_module_a/index.ext*.\n\nThe client code would import the library via\n\n```code\nimport my_library\n```\n\ncan have access to all public elements of the whole library.\n\n### Internal modules\n\nIn order to safe IP you can hide internal code with the keyword `internal`.\n\n`internal` declarations are not public from JL files.\n\n\u003e TODO: It might be better that everything must be marked explicit as public.\n\n## Meta-Programming\n\nThis is the most notable feature of that language.\nIt should allow to extend the language in an easy and powerful way, without introducing too much new syntax.\n\nSome ideas:\n\n* Using `$` as prefix? Pro: the `$` Symbol means always go one meta-layer deeper: `a := \"env: $$$USER\"` is the shell environment variable of the compiler process placed in a string of the compiled program.\n* Replacing code generators. ~~(e.g. no need for `protoc` anymore)~~\n* Annotating code with custom qualifiers, which checking (e.g. `real-time` or `license`; or guaranties safety to a norm *ISO26262*)\n* It should also be possible to read and write files during compilation with the standard File API. Use Cases: Generating schemas and documents during compiling out of the code.\n\n### Motivation\n\n1. Compiler development is time consuming and needs a big portion of domain knowledge.\nIn many cases only a few new features are needed.\nExtending the compiler using the very similar syntax as for the main language should lower the barrier.\n1. The creativity of the Open-Source community has come up with many innovative ideas that were implemented as programming libraries. What if we could leverage the same amount of creativity and productivity to build an amazing compiler?\n1. Moving logic from run-time to compile-time has several advantages:\n    1. Faster at runtime.\n    1. Earlier catch of bugs.\n    1. More information can be exposed to the IDE.\n\n### Examples\n\nExample: Writing a JSON serializer\n\nThe type to serialize\n\n```code\ntype MyType = {\n    a: i32\n    b: string\n    c: {\n        d: i32\n        e: float\n    }\n}\n```\n\nThe serializer\n\n```code\njsonify(obj) = {\n    json: = \"{\\n\"\n    type := $obj.type       // With $ you can access compiler information of a variable or any other symbol\n    // type is now a compiler variable (similar to constexpr in C++)\n    member_loop :- $for {name :- key} in type.members {     // Done in compile-time Note \"type.members\" is hashmap\n        json += s\"\\\"$name\\\": \"\n        json += match member.type {                 // Match gets evaluated during compile-time\n            case i32 | float: $obj[name]            // toString get optional called\n            case string: s\"\\\"${$obj[name]}\\\"\"\n            case object: jsonify($obj[name])\n        }\n        if !member_loop.isLast                      // Accessing for loops internal states (only allowed because type.members support random access to its items)\n            json += \",\\n\"\n    }\n    json + \"\\n}\"\n}\n```\n\n\u003e Note: The for loop gets executed by the compiler as far it can.\n\u003e This is similar to C++ template programming, but it acts on an intermediate code representation.\n\u003e When using the prefix `$` you can have access to the same information as the compiler uses generating the target code.\n\nUsage\n\n```code\nobj: MyType = ...\njson := jsonify(obj)        // Not that the compiler will evaluate the template here. (Type Caching possible)\n```\n\n### Custom Annotations\n\n**Needs refinement**\n\n```code\nfoo_realtime(x: i32) = @realtime {\n    x+2\n}\n\nfoo_no_realtime(x: i32) = {\n    // Doing some stuff like\n    // dynamic memory allocation/de-allocation\n    // Calling non real-time functions\n    // Loops with dynamic number cycles\n}\n\nfoo() = @realtime {\n    foo_no_realtime      // Compiler Error: Function, which calls no realtime\n                         // function, can not be realtime anymore\n}\n```\n\nImplementation via meta-programming: tbd\n\n## Certification\n\nIn order to simplify safety, security or realtime certifications, the compiler supports several tooling.\n\nEach function has a secrets store which can store some X-critical tags.\nThese tags can only be set by an authority.\nThe compiler can verify the correctness of the tags in local secret store by that authority.\n\nThe authority can define rules in which can be used to derive these tags to other functions.\n\n### Injecting custom compiler information into to IL\n\nYou can access compiler variables directly with the `$$` prefix.\n\nLibrary code\n\n```code\n$$vendor = \"My Inc\"\n```\n\nThis variable is not visible to the compiler back-end (e.g. LLVM) but it can be used by the compiler front-end when importing it. In contrast to `$a`.\n\n```code\nimport ./my_lib\n\nlib_vendor := $$my_lib.vendor\n```\n\n\u003e Note `$_[\"a\"]` is the same as `$a`  \n\u003e Note: Compiler implementation detail: `$` is a hashmap where all compiler relevant information about that scope is stored.  \n\u003e TODO: Is is it also possible to archive that with `const` which declares variables which are only visible by the compiler front-end?\n\n## Code sanitizing\n\nIn order to avoid cryptic, verbose and unreadable compiler errors known from some C++ templates, the author of meta-functions should be able to check the arguments and create custom error messages on invalid arguments.\n\n## Developer Experience\n\n* The compiler should detect as much type (and lifetime) information out of the code as possible in order to reduce the amount of annotations written by the developer and make the code more concise.\n\n## Use Cases\n\n### Objects of different type in a vector\n\n```c++\nclass Base{\n public:\n  virtual foo() = 0; \n};\n\nclass A : public Base{\n public:\n  foo() override { /* ... */};\n private:\n  int a;\n};\n\nclass B : public Base{\n public:\n  foo() override { /* ... */};\n private:\n  int b,c;\n};\n\nint main(int, char**) {\n    std::vector\u003cBase*\u003e v;\n    v.push_back(new A());\n    v.push_back(new B());\n\n    for(auto item : v) {\n        item-\u003efoo();\n    }\n    return 0;\n}\n```\n\n```code\ntype Base {\n    foo : () =\u003e void;\n}\n\ncreate_a := () =\u003e {\n    a :+ ...\n    foo :+ () =\u003e ...\n}\n\ncreate_b := () =\u003e {\n    b :+ ...\n    c :+ ...\n    foo :+ () =\u003e ...\n}\n\ncreate_c := () =\u003e {\n    fii :+ () =\u003e ...\n}\n\npostfix .faa := (obj) =\u003e obj.foo  // Compiler knows that obj must have member foo\n\nv := Vector\u003cBox\u003cBase\u003e\u003e::new()\n\nv.push(Box.new(create_a))      // Compiler aligns memory layout to Base here\nv.push(Box.new(create_b))      // Compiler aligns memory layout to Base here\nv.push(Box.new(create_c))      // error: member foo is missing\n\ncreate_c.faa                    // error: member foo is missing\n\nfor item in v.iter {\n    item.unwrap.foo             // Brackets () are optional\n    item.unwrap.faa\n}\n```\n\n### Async/Await or Event loops\n\n**[TODO]**\n\n### Encapsulation\n\n```c++\nclass A {\n private:\n  int a;\n public:\n  A(): a(0) {}\n  int inc() {\n   return a++;\n  }\n};\n\nA obj;\nint a = obj.inc();\nint b = obj.a;              // error: a is private          \n\n```\n\n```chop\nA := {\n  new :+ () =\u003e {\n      mut a :+ 0        // How to make this protected? another syntax ?\n  }\n  postfix .inc :+ (obj) =\u003e {\n      obj.a++\n  }\n}\n\nobj := A.new            // Should this be mut obj := A.new ?\na := obj.inc\nb := obj.a              // no error :(\n```\n\n**[TODO]**\n\n## Notes on Compiler Implementation\n\n### Intermediate Language\n\n* Format:\n  * binary\n  * fast searchable\n* Motivation:\n  1. Caching parsers work\n  1. Storing function's signature with predicates\n  1. Protecting IP for proprietary libraries\n* Can be translated to LLVM-IR\n* No runtime code optimization (this gets done by LLVM back-end)\n\n## Shell\n\nWith config in `~.choprc` as\n\n```config\nimport unix\n```\n\nThis should provide you a Unix like shell experience\n\n```code\nls\n```\n\nwhere the result type of `unix.ls` implements the interface\n\n```code\ntype ConsoleOutout {\n    progress: () -\u003e f32,\n    result: string\n}\n```\n\n### Summary\n\nThe Unix shell command `ls` is nothing else than a public function in the module unix which returns a type that can be displayed on the console.\n\nAdvantages:\n\n* One language for each kind of task: All language features in shell scripts.\n* Avoid subprocess calls\n* One can use the same function in other programs as well and the function writer does not have to take care about formatting such as progress bar painting and other complex user interactions.\n\n## Open points\n\n* Default access modifier `public` or `private` ?\n  * Suggestion: `private`\n* Abbreviation:\n  * `public` vs `-\u003e`\n  * `require x: Type` vs `-\u003e x: Type` or something else?\n\n\n## Other Pain-Points to trackle\n\n### Debugging:\n\n* Very large stacktrace\n* Missing context / function arguments in stacktrace\n* Cryptical displayed representation of variables.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flochbrunner%2Fchop-specs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flochbrunner%2Fchop-specs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flochbrunner%2Fchop-specs/lists"}