# Q& ## About A single-pass byte code interpreter with the ability to pre-compile executables into a format that can be efficiently executed by the runtime. It serves many features, which are listed a bit further down below. This would have officially been the fourth iteration of my language (sqript4), but I thought I'd stop with the numbers as people would ask what happened to the previous three languages. Q& (or Qamp for Q Ampersand) was originally made for my contributions to the Advent Of Code 2025, but I thought it's a nice and stable enough concept to be sharing it to the public anyway. ## Usage To build **Q&**, you need nothing more than a C# compiler that supports .NET10. There are .NET8 compatible versions available, but they are not recommended, as **Q&** utilizes all of the performance optimizations .NET10 has to offer. After cloning, a simple `dotnet build ./` in the root directory will suffice. You can execute pre-compiled .sqi files using `qamp.runtime.exe [parameters]`, or the REPL/CLI using `qamp.cli.exe [parameters]`. If you want to build your own source into pre-compiled instruction files, use `qamp.digest.exe ` - the digester will look for an `Init()` function declared in any of the files, and build the instructions from there. ## Language & Syntax You are free to choose between the classic sqript-style dialect `*~ q <~ 0xf;` or the standard dialect, which is strongly inspired by the C# standard: `var q = 0xf;`. All of the following examples are written in the classic dialect `--dialect=sqr` or `-d=q`. ### Syntax Most basic Usage: ```cs # this is a comment. *~ q <~ 12; # q == 12 *~ f <~ (n) <: n < 2 ? n : f(n-1) + f(n-2); # fibonacci f(12); # 233 *~ a <~ [1, 2, 3]; # a = [1, 2, 3] *~ x <~ a:0 + a:2; # x == 4 ``` ### Assignments **Q&** has two distinct ways to assign a value to a variable: - By reference `<&`, or - By value `<=`. Using the auto-assignment operator `<~`, **Q&** will choose the correct assignment based on what type the right-hand expression consists of. Primitive types will be assigned by value, any object values will be assigned by reference. This is strongly inspired by the behaviour that most interpeters implement. #### What happens if... ##### I assign an object by value? The entire object will be deep-copied and transfered to the new location. See it as a free clone method on basically anything that is considered an object. ##### I assign a primitive by reference? So, assuming that `x` is a primitive (value type), given the instruction `*~ y <& x;`, `y` will be assigned as a reference value _pointing_ to the location of `x` - somewhat like a pointer in C, but a little smarter. ##### I do not praise the god emperor of mankind? You will be duly punished. #### Variable Declaration ``` *~ q <~ 0xf; ``` #### Variable Declaration ## Customization & Extras Some more information about extending and customizing Q& to your needs. ### Implementing external Libraries Implementation is easy. Q& is written in C#, and supports basically anything you can wrap in C#. All you have to do in order to implement a library is referencing the SDK dll which should be located within your `./Build/` folder after building as described above. Here's a quick example of how you would implement virtually any library: ```cs using Qrakhen.Qamp.Core; // This is an intentionally bad implementation of a linked list. [ExportType("llist")] public class LinkedListNode : Obj { [HideProperty] public LinkedListNode? Next { get; private set; } public Value Value { get; private set; } public LinkedList(Value value) { // ...internal setup this.Value = value; } // Q& constructors, if needed, have to be explicitely declared to return a value type. [ExportConstructor] public static Value Ctor(params Value[] args) { current = this; while (current.Next != null) current = current.Next; // This simply returns a new pointer to an already existing // oject inside the heap, rather than actually create a new one. // It wraps a pointer to the provided object inside a value that // has the 'Ptr' type flag, passing it to the Q& runtime. return Obj.Create(current); } // Tell the type mapper to export this method [ExportMethod] public Value Last() { // This simply returns a new pointer to an already existing type. // The call ddoes not actually create a new object. var current = this; while (current.Next != null) { current = current.Next; return Obj.Create(); } // Value is the base type of anything in Q&. // An object is just a value of type 'Ptr' (value.IsPtr), // and primitives have their value stored in the 8 byte // buffer of the value itself (value.Data). [ExportMethod] public void Add(Value value) { var current = this; while (current.Next != null) current = current.Next; current.Next = new LinkedList(value); } // Methods that accept a primitive will automatically try // retrieve that type from the provided arguments as Values. // You may always simply declare to accept Values aswell, // which gives you some dynamic flexibility if needed. [ExportMethod] public Value? GetItem(long index) { long current = 0; var node = this; while (current < index) { current++; node = node.Next; } return node; } } ``` You may manually register all types inside an assembly by calling ``` Library:Load("mylib.dll"); ``` directly in Q&. Usage of the type described above would look somewhat like this: ``` *~ list = new llist(); list.Add(5); list.Add('test'); list.Add([1, 2, 3]); print(list.GetItem(1)); // 'test' print(list.Last()); // [ 1, 2, 3 ] *~ protected = list.Value; // will throw an exception, as we did not expose that property. ``` That's it - although this being a very simple example, more is possible. I will add a few basic implementations of very common libraries in a separate repository soon.