{"id":40830166,"url":"https://github.com/harrand/psyc","last_synced_at":"2026-04-09T00:06:05.109Z","repository":{"id":232389136,"uuid":"783672704","full_name":"harrand/psyc","owner":"harrand","description":"Psy - a systems programming language, because we didn't have enough already","archived":false,"fork":false,"pushed_at":"2026-04-04T21:38:08.000Z","size":2366,"stargazers_count":3,"open_issues_count":11,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-04T21:50:19.938Z","etag":null,"topics":["compiler","programming-language"],"latest_commit_sha":null,"homepage":"","language":"C","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/harrand.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-08T10:54:24.000Z","updated_at":"2026-03-24T19:54:58.000Z","dependencies_parsed_at":"2024-04-24T14:09:24.183Z","dependency_job_id":"0e162aa5-1f90-45bd-b6f4-dc8311d3893d","html_url":"https://github.com/harrand/psyc","commit_stats":null,"previous_names":["harrand/psyc"],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/harrand/psyc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrand%2Fpsyc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrand%2Fpsyc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrand%2Fpsyc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrand%2Fpsyc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/harrand","download_url":"https://codeload.github.com/harrand/psyc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrand%2Fpsyc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31579061,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"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":["compiler","programming-language"],"created_at":"2026-01-21T22:21:34.351Z","updated_at":"2026-04-09T00:06:03.077Z","avatar_url":"https://github.com/harrand.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Psyc\n\nPsyc is a small, minimal-dependency compiler for the Psy programming language.\n\n# Psy Programming Language \u003ca name=\"intro\"\u003e\u003c/a\u003e\n\nPsy is a systems programming language. It is intended to have the best of C:\n- Simple, procedural, statically-typed code.\n- Manual memory management.\n- Structs and functions, but not classes/ctors/dtors/virtuals\n- The number of ways to initialise a variable should be countable on one hand.\n- Act as a \"portable assembly\".\n\nbut without:\n- Implicit conversions (though you can explicitly opt-in).\n- Array-to-pointer-decay.\n- Macros.\n- Declaration order requirements.\n- Translation units.\n- Strict aliasing \u0026 restrictive object representation rules (i.e type-punning is fully allowed).\n- External build instructions. All psy programs are built by running the compiler on a single .psy file. No exceptions.\n- Default variable mutability.\n- Extraneous implicit link dependencies.\n\nTake C, apply all of these opinionated changes, and you have Psy. I will now write vast swathes of text describing the language in more detail.\n\n## Table of Contents\n0. [Psy Programming Language](#intro)\n1. [Programs](#programs)\n2. [Build Regions](#region)\n3. [Functions](#functions)\n\t- [Defining basic functions](#basic_functions)\n4. [Types](#types)\n\t- [Type Qualifiers](#type_qualifiers)\n\t- [Primitive Types](#type_prim)\n\t- [Pointer Types](#type_ptr)\n\t- [Array Types](#type_array)\n\t- [Enum Types](#type_enum)\n\t- [Struct Types](#type_struct)\n\t- [Type Conversions](#type_conv)\n\t\t- [Primitive Conversions](#type_conv_prim)\n\t\t- [Struct Conversions](#type_conv_struct)\n\t\t- [Enum Conversions](#type_conv_enum)\n   \t\t- [Pointer Conversions](#type_conv_ptr)\n   \t\t- [Qualifier Conversions](#type_conv_qual)\n       \t- [Type Casting](#type_cast)\n5. [Values](#values)\n   \t- [Literal Values](#val_lit)\n   \t- [Named Values](#val_named)\n\t- [Zero Value](#val_zero)\n\t- [Block Initialisers](#val_blkinit)\n6. [Variables](#vars)\n   \t- [Global Variables](#var_glob)\n   \t- [Local Variables](#var_loc)\n\n# 1) Programs \u003ca name=\"programs\"\u003e\u003c/a\u003e\n\nThere is no concept of a \"translation unit\", \"module\", or \"header\" in Psy. There are source files and build files.\n\n## Source Files \u003ca name = \"source_files\"\u003e\u003c/a\u003e\nA source file is simply a text file with the file extension '.psy'.\n\n## Build Files \u003ca name = \"build_files\"\u003e\u003c/a\u003e\n\nA source file is a build file if it contains one or more [build regions](#region).\n\n## Building Programs\nCompiling a program will yield *one* of the following:\n- one compiled object file (.o/.obj)\n- one executable (.exe/.elf)\n- one static library (.a/.lib)\n\nTo build program, you must invoke the compiler (i.e psyc) and pass it the relative path of a file. That file must be a build file, and must contain a build region pertaining to the *build region* you have passed.\n\n### Examples\n\n```psyc foo.psy```\n\nThis specifies a build file named 'foo.psy'. This filename will be treated as a path relative to the current working directory, and must exist otherwise the compiler will emit an error.\n\nNo build region has been specified, so the default build region (named `default` will be invoked). If foo.psy does not have a build region named `default` then the compiler will emit an error.\n\n```psyc foo.psy -b debug```\n\nSimilar as before, but a build region named `debug` has been passed instead of relying on the default. If foo.psy does not have a build region named `debug` then the compiler will emit an error.\n\n# 2) Build Regions \u003ca name=\"region\"\u003e\u003c/a\u003e\nBuild regions are a special construct that don't really exist in other languages. Put simply, build regions are just like your build scripts in other languages, except:\n\n- They are in the same language as the rest of your program.\n- They are essentially a function that is invoked at compile-time.\n\nIt's a bit jarring for people who are used to separating their build process from their actual program, so let's jump straight into an example:\n\n```\n== default ==\n{\n\texecutable(\"foo\");\n\toptimization(3);\n\tprebuild_command(\"echo building foo...\");\n\tadd_source_file(\"foo.psy\");\n\n\tstatic_if(_win32)\n\t{\n\t\tadd_link_library(\"User32.lib\");\n\t}\n}\n```\n\nThis is a build region named `default` within some a file called 'a.psy'. Because that file contains a build region, it is officially a [build file](#build_files).\n\nBuild regions are always invoked at compile-time, either by:\n- Being passed to the compiler directly (e.g `psyc a.psy -b default`)\n- Being invoked by another build region.\n\nThis means that, given:\n`psyc a.psy -b default`\nThen this region will be invoked at compile-time by the compiler.\n- Note that 'default' is a special name - if no region name is specified via the `-b` flag then 'default' will be used. In this case, `psyc a.psy` works the same.\n- The output will be an executable named 'foo'. The file extension is chosen automatically by the compiler - a sane default depending on your platform (e.g .exe for windows, .elf for linux). There is currently no way to modify the extension.\n- The optimization level is 3, which is the equivalent of `-O3` for other compilers, i.e maximum optimization. It must be a value between 0-3.\n- During the build, before the output file is generated, the command `echo building foo...` will be invoked in a shell and its output is fed through to stdout.\n- The file `foo.psy` will be compiled.\n- If the host process is running on Windows, then:\n\t- The final executable `foo.exe` will link against `User32.lib`.\n\nImportant Note: `add_source_file` will not invoke any build regions within the file that you added. To do that, you will want the `add_build_file` build instruction.\n\nBuild regions can also invoke other build regions by calling them like a function (with no arguments).\n\n# 3) Functions \u003ca name=\"functions\"\u003e\u003c/a\u003e\n\nA function consists of:\n- A name.\n- Zero or more parameters (default parameter values are not supported), each with their own name and type.\n- A return type.\n- An implementation surrounded by braces, or markup describing the function as `extern`.\n\nA function marked as `extern` means that the implementation of the function is not defined in any part of the program, but one of the link dependencies contains the implementation instead.\n\n### Defining basic functions \u003ca name=\"basic_functions\"\u003e\u003c/a\u003e\nThe following code defines a function named `my_function_name`. It takes no parameters, and returns nothing (`v0` is the equivalent of `void` in C):\n```\nmy_function_name : func(-\u003e v0)\n{\n\t// code goes here\n};\n```\nNote that the return type is within the parentheses - this is a syntactical choice that seems odd at first. In actuality, it removes the necessity for arcane syntax for function pointers, but more on that later.\n\nCalling the function is just like you would expect:\n```\nmy_function_name();\n```\nNote that you cannot call a function within the global scope. That is - you can only call a function within another function body.\nIn a function that returns `v0`, there is no need to return at the end of the function. In all other cases, you *must* return a value.\n\nThe following code defines a function named `double_value`. It takes a single parameter, doubles it, and returns the result.\n```\ndouble_value : func(number : s32 -\u003e s32)\n{\n\treturn number + number;\n};\n```\n\nThe following function doubles the value `5` and stores it in a new variable called `result`:\n```\nresult ::= double_value(5);\n```\n\n# 4) Types \u003ca name=\"types\"\u003e\u003c/a\u003e\nPsy is a statically-typed and strongly-typed language. This means that:\n- The type of all variables are known by the compiler at compile-time.\n- Typing rules are strict. Unlike languages such as C, implicit conversions are disabled by default - you must explicitly opt-into this.\n  \t- This means for example that a `u32` is not implicitly convertible to a `s64` or even a `s32`.\n\nThere are a small handful of type qualifiers available in Psy. Learn what these are first, or you will run into endless issues and confusion coming from C.\n\n### Type Qualifiers \u003ca name=\"type_qualifiers\"\u003e\u003c/a\u003e\nA type can have zero or more qualifiers. Qualifiers appear at the end of the type's name.\n| Type Qualifier         | C Equivalent      | Explanation                                                                    |\n| :--------------------- | :---------------: | :----------------------------------------------------------------------------- |\n| none                   | `const`           | Everything is immutable by default, like Rust but unlike C.                    |\n| `mut`                  |                   | The variable is mutable - its value can be changed after initialisation.       |\n| `weak`                 | none              | Types that are marked `weak` will be subject to *implicit conversions* so long as the conversion is possible.   |\n| `static`               | `constexpr` (C++) | The variable must be a compile-time constant, or a compile error will occur.   |\n\nNote that a type can have multiple qualifiers. Here are some examples of various types:\n- `u64` - immutable, no implicit conversions, not a compile-time constant.\n- `f32 mut` - mutable, no implicit conversions, not a compile-time constant.\n- `u8 mut? mut weak` - pointer type. implicit conversions allowed, mutable. the pointee is also mutable.\n\n ### Primitive Types \u003ca name=\"type_prim\"\u003e\u003c/a\u003e\n There are a number of primitive types:\n | Primitive Type         | C Equivalent | Description                            |\n| :---------------- | :----------: | :------------------------------------- |\n| s64               |   int64_t    | 64-bit signed integer.                 |\n| s32               |   int32_t    | 32-bit signed integer.                 |\n| s16               |  int16_t     | 16-bit signed integer.                 |\n| s8                |  int8_t      | 8-bit signed integer.                  |\n| u64               |  uint64_t    | 64-bit unsigned integer.               |\n| u32               |  uint32_t    | 32-bit unsigned integer.               |\n| u16               |  uint16_t    | 16-bit unsigned integer.               |\n| u8                |  uint8_t     | 8-bit unsigned integer.                |\n| bool              |  _Bool (C99)        | `true`/`false` value of implementation-defined size.            |\n| f64               |  double      | 64-bit floating-point number. IEEE-754 |\n| f32               |  float       | 32-bit floating-point number. IEEE-754 |\n| v0                |  void        | Represents no value. Zero size.        |\n\n### Pointer Types \u003ca name=\"type_ptr\"\u003e\u003c/a\u003e\nPointers work similarly to C pointers, but the syntax is slightly different. The best way to explain pointers is by example:\n```\nmain : func(-\u003e s32)\n{\n\tmy_value : s64 mut := 5;\n\tmy_pointer : s64 mut? := ref my_value;\n\n\t// equivalent to '*(my_pointer) = 0' in C:\n\t[my_pointer] = 0;\n\treturn 0;\n};\n```\nWithin a typename, pointer-ness is represented by the question-mark `?` symbol. It directly proceeds the base type representing the pointee.\n\n- The `ref` keyword is equivalent to the 'address-of' operator (\u0026) in C. `ref x` in Psy is equivalent to `\u0026x` in C.\n- Dereferencing has different syntax. Surrounding an expression with brackets i.e `[foo]` is a dereference of the lvalue foo. It is derived from intel syntax assembly.\n- Pointer arithmetic does not overload integer arithmetic; there is a special offseting `#` operator which is identical to C pointer arithmetic in all other ways.\n```\n\tints_begin : s32? := get_pointer_to_64_ints();\n\tfirst_int ::= [ints_begin];\n\talso_first_int ::= [ints_begin # 0];\n\tsecond_int ::= [ints_begin # 1];\n\t// \"ints_begin + 1\" is an error because you cant add an integer to a pointer. if you want this you almost certainly mean \"ints_begin # 1\"\n```\nInfact, there is no array-index-syntax at all. You can offset arrays aswell and it will yield a pointer to the n'th element in that array.\n\nIn C, you have function pointers, which are explicitly pointers. In Psy, you can have function references, which are not pointers:\n```\n// normal function definition\nmy_cool_function : func(-\u003e v0)\n{\n\t// code...\n};\n\n// later on in main\nmain : func() -\u003e s32 weak\n{\n\t// function reference variable.\n\tmy_function_ref : func(-\u003e v0) := my_cool_function;\n\t// you can let the compiler determine the type for you:\n\tthe_same_function_ref ::= my_cool_function;\n\tmy_function_ref(); // calls my_cool_function.\n};\n```\nFunction reference conversion rules are simple. A function reference will implicitly convert to any other function type if it is marked as `weak`, aswell as `u64` (which will yield the address of the function).\n\n### Array Types \u003ca name=\"type_array\"\u003e\u003c/a\u003e\nArrays contain one or more elements of the same type, contiguously.\n\ni.e `u64[3]` is an array of three `u64`s. Note that array lengths don't have to be integer literals, they can be derived from any statically-known value. For example:\n\n```\nmy_constant : u64 static := 60;\narr : u8[my_constant]; // array of 60 u8s\nu8_bytes : u8[sizeof u64]; // array of 8 u8s\n```\n\n### Enum Types \u003ca name=\"type_enum\"\u003e\u003c/a\u003e\nEnums in Psy are similar to `enum class` in C++11. The syntax is slightly different.\n```\nwindow_flags : enum\n{\n\t.none := 0x0000;\n\t.opengl := 0x0001;\n\t.vulkan := 0x0002;\n};\n\n// later on in a function:\nmy_flag : window_flags := window_flags.opengl;\nvalue ::= my_flag@s64; // 1\n```\n\nNote that enums are implemented via `s64` under-the-hood, i.e they are 64-bit. Because of this, enums can convert *only* to `s64`. To convert to different integer types you will have to convert to `s64` initially i.e `window_flags.opengl@s64@u8`.\n\n### Struct Types \u003ca name=\"type_struct\"\u003e\u003c/a\u003e\nStructs in Psy are virtually identical to that of C. Structs must be defined as new types, and then can be used as a type for variables. A syntax very similar to C/C++20 designated initialisers can be used to initialise a struct value.\n\n#### Declaring a new struct\n```\nmy_struct : struct\n{\n\t// data members go here.\n\tmy_data_member : s32;\n};\n```\n- You cannot pre-declare structs, as there is no need to do so.\n- Recursive-structs are illegal. That is, `mystruct::data_member` can never be of type `mystruct`. Pointers are allowed however (e.g a data member can be of type `mystruct?`), but not arrays.\n\nThe syntax for creating a variable of a struct type is intuitive and similar to that of C:\n```\nmyvar1 : my_struct mut;\n// note that setting data members after initialisation like this requires the variable to be mutable.\nmyvar1.my_data_member = 5;\n\n// block initialiser:\nmyvar1 ::= my_struct\n{\n\t.my_data_member := 5;\n};\n```\n\n### Type Conversions \u003ca name=\"type_conv\"\u003e\u003c/a\u003e\nWithout the `weak` qualifier, no implicit type conversions are available to you.\n```\nmy_int : u64 := 5;\nmy_int2 : s64 := my_int; // error.\n```\nIf either type `A` or `B` are `weak`, then the following type conversion rules are in effect:\n#### Primitive Conversions \u003ca name=\"type_conv_prim\"\u003e\u003c/a\u003e\n- If A and B are *numeric primitives*, conversion is allowed.\n- If A and B are `s64` and an *enum* respectively, then conversion is allowed (and vice-versa).\n- If A and B are `u64` and a *pointer* or *function reference* respectively, then conversion is allowed (and vice-versa).\n- If A is a `bool` and B is a *numeric primitive*, conversion is allowed (and vice-versa)\n- If A is a `v0`, no form of type conversion is allowed.\n#### Struct Conversions \u003ca name=\"type_conv_struct\"\u003e\u003c/a\u003e\n- Struct types do not convert to anything else.\n#### Enum Conversions \u003ca name=\"type_conv_enum\"\u003e\u003c/a\u003e\n- If A is an enum type and B is `s64`, then conversion is allowed.\n- Enums do not convert to anything else.\n#### Pointer Conversions \u003ca name=\"type_conv_ptr\"\u003e\u003c/a\u003e\n- Pointer types can be freely converted to other pointer types. There is no strict aliasing and no semantic object lifetimes, so type-punning via pointer conversions is allowed.\n### Qualifier Conversions \u003ca name=\"type_conv_qual\"\u003e\u003c/a\u003e\n- You can add/remove `weak`ness in a conversion.\n- You can remove but not add `mut`ness in a conversion.\n- You can remove but not add `static`ness in a conversion.\n\n### Type Casting \u003ca name=\"type_cast\"\u003e\u003c/a\u003e\nYou have now learned about the various possible type conversions. No form of conversion is done without the `weak` qualifier. This is so that these conversions don't happen unless you ask for them - an attempt to produce more predictable code. However, if you want to opt-into these conversions, then it should be easy.\n\nCasting is the act of explicitly applying `weak`ness to a value's type, and allowing it to undergo a conversion. It is done using the `@` symbol. It is a different approach to C and C++. Here's a very basic example:\n```\nmy_int : u64 := 5;\n// my_int2 : s64 := my_int; // you haven't asked for implicit conversions, this is an error.\nmy_int2 : s64 := my_int@s64; // ok. you have casted my_int to s64. my_int2 == 5;\n```\nIn this case, `my_int@s64` is a binary operator (the casting operator). On the left of the `@` symbol is the value you want to convert. On the right of the symbol is the typename you want to convert to.\nThe equivalent in C would be:\n```c\nuint64_t my_int = (uint64_t)5;\nint64_t my_int2 = (int64_t)my_int;\n```\nNote that in this C example the casts are unnecessary, as these types convert implicitly already.\n\nI wanted to provide an additional quality-of-life compromise for those who like to opt into these conversions. Instead of having to `@type_name_goes_here` every single time, you have a few further options:\n```\nmy_int : u64 weak := 5;\nmy_int2 : s64 := my_int; // ok. my_int was explicitly defined with the weak qualifier, this variable will continually opt into implicit conversions.\n```\nWhat if you want to \"apply weakness\" to an existing variable? You can do so using this very arcane syntax:\n```\nmy_int : u64 := 5;\nmy_int@_ // this is the same as my_int@u64 weak. or in general, value@_ is equivalent to value@type_of_value weak\n```\n\nThis will allow you to be very selective in where you opt-into implicit conversions, and makes it easy to do so when you don't need the very strict type safety rules.\n```\nmy_int2 : s64 := my_int@_;\n// my_int remains a strongly-typed u64. the \"apply weakness\" idiom only affects the expression it is used in -- it doesnt magically change the type qualifier of the variable forevermore.\n```\n\n# 5) Values \u003ca name=\"values\"\u003e\u003c/a\u003e\nValues represent a stored permutation of bits, representative of a given type. Unlike C, values of a given type have no such concept of a lifetime - only memory has a lifetime. For this reason, the notion of constructors and destructors do not exist in Psy. Values are used to initialise variables, re-assign mutable variables, and pass/return from functions.\n\n## Literal Values \u003ca name=\"val_lit\"\u003e\u003c/a\u003e\nLiteral values are values restricted to certain types, and are known at compile time. Literal values can be used to initialise `static` variables.\n`5` is a literal value, and so is `\"my awesome string literal!\"`. `my_function()` does not yield a literal value, as functions compute their values at runtime.\n\nStruct initialisers can be literal values, but only if every initialiser is a literal value. For example, the following struct initialiser is a literal value:\n```\nanimal\n{\n\t.type := animal_type.tiger;\n\t.name := \"bob\";\n};\n```\n\nAs such, it can be used to initialise a `animal static`:\n```\nbob_the_tiger : animal static := animal\n{\n\t.type := animal_type.tiger;\n\t.name := \"bob\";\n};\n```\n\nThe following struct initialiser is not a literal value, as one of its initialisers is the result of a non-static function call:\n```\nnew_world ::= world\n{\n\t.name := \"My New World\";\n\t.seed := generate_random_seed();\n};\nworld_cpy : world static := new_world; // error: cannot convert world to world static.\n```\n\n## Named Values \u003ca name=\"val_named\"\u003e\u003c/a\u003e\nNamed Values (otherwise known as lvalues in C) are values that have an identifiable location in memory. All variables are named values.\n\n## Zero Value \u003ca name=\"val_zero\"\u003e\u003c/a\u003e\nThe `zero` value is a special keyword that can be compared/assigned/initialised to any type. The zero value representation is comprised entirely of zeroes.\n\nYou can use it to represent a \"null pointer\":\n```\nmy_pointer : u64? mut := zero;\n```\n\nOr zero-initialise a variable\n```\nfoo : complex_struct_type := zero;\nenum_value ::= zero@my_enum_type;\n```\n\nI don't know why this isn't a default in all languages.\n\n## Block Initialisers \u003ca name=\"val_blkinit\"\u003e\u003c/a\u003e\nBlock initialisers are the best way to initialise multiple data members of a new struct/array value at once, as opposed to setting them manually. It is valid to not initialise every single data member of the struct. However, the data members you don't set in the struct initialiser will be of indeterminate value.\n\nBlock initialisers start with the name of the type you are initialising, and then zero or more [designated initialisers](desiginit) surrounded by braces.\n\n# 6) Variables \u003ca name=\"vars\"\u003e\u003c/a\u003e\nVariables in Psy are very similar to other C-like languages. Variables are named values that are of a given type.\n\n### Global Variables \u003ca name=\"var_glob\"\u003e\u003c/a\u003e\nGlobal variables are variables whose the lifetime of its memory matches that of the program's runtime and are visible across the whole program. Global variables do not have to be initialised initially, but if they are given an initialiser, that initialiser must be a literal value.\n\n### Local Variables \u003ca name=\"var_loc\"\u003e\u003c/a\u003e\nLocal variables are variables that are limited to a scope. Their lifetime semantics exactly match that of C.\n\n# 6) Statements \u003ca name=\"stmt\"\u003e\u003c/a\u003e\nStatements represent the main building blocks of a Psy program. Each statement compiles down to a sequential list of zero or more instructions.\n\nSome statements are purely a compile-time mechanism and do not generate any code.\n\n### Declaration Statements \u003ca name=\"stmt_decl\"\u003e\u003c/a\u003e\nDeclaration statements are the primary way to define variables. The syntax of a declaration statement is as follows:\n```\n(1)\ndecl_name : typename;\n(2)\ndecl_name : typename := init_expr;\n(3)\ndecl_name ::= init_expr;\n(4)\ndecl_name : funcdef_expr\n{\n\t...\n};\n(5)\ndecl_name : funcdef_expr extern;\n```\nThe behaviour of (1) is as follows:\n* Allocate memory on the stack, enough to store a value of type `typename`.\n* If this statement is within a function implementation block, then this is a local variable, and the variable `decl_name` is now available to proceeding code within the block.\n  \t* If it is outside of a function implementation block and a top-level statement within the source file, then it represents a global variable. The variable `decl_name` is now available to all proceeding code in the source file, aswell as any code that adds this source file in its *build metaregion*.\n* The variable has an indeterminate value.\nExample:\n```\nmyvar : u32;\n```\n\nThe behaviour of (2) is identical to (1), except that the expression `init_expr` is treated as an initialiser. The variable now has that value.\nExample:\n```\nmyvar : u32 := 500;\n```\n\nThe behaviour of (3) is similar to (2), except that the type of the variable is deduced automatically by the `init_expr` initialiser. The type of the variable will exactly match that of the initialiser, including *type qualifiers*.\nExample:\n```\nmyvar ::= 500;\n// note: myvar is of type (s64 static weak)\n```\n\nBoth (4) and (5) are only used to declare *functions*.\n(4) Declares a function, and provides an implementation block for the function.\nExample:\n```\nmain : func(-\u003e s32 weak)\n{\n\thello_world();\n\treturn 0;\n};\n```\n\n(5) Declares a function, but indicates that the implementation of the function lives elsewhere. The linker is expected to locate this implementation after compilation. You should use this to declare functions from other libraries (.lib/.o) that you wish to link against and call in your program.\nExample:\n```\nwglGetProcAddress : func(unnamedParam1 : u8? -\u003e u64 weak) extern;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharrand%2Fpsyc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharrand%2Fpsyc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharrand%2Fpsyc/lists"}