Compare commits

..

2 Commits

18 changed files with 382 additions and 122 deletions

7
.gitignore vendored
View File

@ -1,4 +1,6 @@
Debug/
x86/
x64/
Release/
Build/
bin/
@ -9,9 +11,10 @@ log/
lib/
.vs/
*.nocmt.*
*.sqi
*.tmp
*.log
*.depend
*.stackdump
*.layout
*.user
x86/
x64/

View File

@ -121,6 +121,9 @@ public class Runner : IDisposable
Globals["cos"] = Obj.Create(new NativeFunction("cos",
v => new Value(Math.Cos(v[0].GetDecimal())), "v"));
Globals["sqrt"] = Obj.Create(new NativeFunction("sqrt",
v => new Value(Math.Sqrt(v[0].GetDecimal())), "v"));
Globals["exit"] = Obj.Create(new NativeFunction("exit", v => {
Environment.Exit((int)(v.FirstOrDefault().Signed));
return Value.Void;
@ -709,7 +712,9 @@ public class Runner : IDisposable
}
if (value.Is(T.Native)) {
return InvokeNative(value.Ptr.As<NativeFunction>(), argumentCount);
if (value.Ptr.As<NativeFunction>() is NativeFunction native)
return InvokeNative(native, argumentCount);
return false; // unlikely edge case, natives are always set directly via the global registry
} else if (value.Is(T.Method)) {
Method method = value.Ptr.As<Method>()!;
_stack.Set(_cursor - method.Function.ArgumentCount - 1, method.Receiver);

View File

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Version>0.0.12.632</Version>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

View File

@ -103,9 +103,12 @@ public readonly struct Value :
public bool IsFalsy => IsBool ? Bool == false : Unsigned == 0;
// another shortcut that will cost me greatly
public String? AsString() => Ptr.As<String>();
public string? GetString() => AsString()?.Value;
// edit: yes, did cost me greatly, lol. pointer was pointing to random strings in string table
// ending up with dozens of strings spat out using write(), accidentally, by giving write
// an integer (table index offset) rather than a string literal. oops.
public String? AsString() => IsString ? Ptr.As<String>() : null;
public double GetDecimal() => IsDecimal ? Decimal : (double)Signed;
public string? GetString() => AsString()?.Value;
public bool Is(T type, bool exact = true)
{

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) [2026] [David Neumaier, Qrakhen]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,17 @@
{
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}

View File

@ -0,0 +1,33 @@
{
"name": "qamp",
"displayName": "Q& Language Support by Qrakhen",
"repository": "https://git.qrakhen.net/qrakhen/qamp-vscode.git",
"publisher": "qrakhen",
"version": "0.0.1",
"engines": {
"vscode": "^1.0.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"contributes": {
"snippets": [{
"language": "qamp",
"path": "./snippets/qamp.code-snippets"
}]
},
"languages": [{
"id": "qamp",
"aliases": ["Q&", "qamp"],
"icon": { "dark": "cogwheel", "light": "cogwheel" },
"extensions": [ ".qp", ".sq", ".qamp" ],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "qamp",
"scopeName": "source.qamp",
"path": "./syntaxes/qamp.tmLanguage.json"
}]
}
}

Binary file not shown.

View File

@ -0,0 +1,27 @@
{
"Sine": {
"prefix": "sin",
"body": "sin(${1:number})",
"description": "Calculates the sine of number, assuming radians."
},
"Cosine": {
"prefix": "cos",
"body": "cos(${1:number})",
"description": "Calculates the cosine of number, assuming radians."
},
"Read": {
"prefix": "read",
"body": "read()",
"description": "Reads a line from stdin."
},
"Write": {
"prefix": "write",
"body": "write(${1:string})",
"description": "Writes string to stdout."
},
"Timestamp": {
"prefix": "time",
"body": "time()",
"description": "Returns current timestamp in microseconds."
}
}

View File

@ -0,0 +1,124 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "qamp",
"scopeName": "source.qamp",
"patterns": [
{ "include": "#comments" },
{ "include": "#strings" },
{ "include": "#keywords" },
{ "include": "#operators" },
{ "include": "#numbers" },
{ "include": "#functions" },
{ "include": "#globals" }
],
"repository": {
"globals": {
"patterns": [
{
"name": "support.function.qamp",
"match": "\\b(sin|cos|read|write|fread|fwrite|time|ftime)\\b"
},
{
"name": "support.string.qamp",
"match": "\\b(SubString|IndexOf|Split|Length)\\b"
}
]
},
"comments": {
"patterns": [
{
"name": "comment.line.double-slash.qamp",
"match": "#.*$"
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double.qamp",
"begin": "\"",
"end": "\"",
"patterns": [{ "name": "constant.character.escape.qamp", "match": "\\\\." }]
},
{
"name": "string.quoted.single.qamp",
"begin": "'",
"end": "'"
}
]
},
"keywords": {
"patterns": [
{
"name": "keyword.control.qamp",
"match": "\\b(if|else|for|while|var|do)\\b"
},
{
"name": "storage.type.function.qamp",
"match": "\\b(fq|funq)\\b"
},
{
"name": "keyword.class.qamp",
"match": "\\b(qlass|class|this|base)\\b"
},
{
"name": "keyword.control.flow.return.qamp",
"match": "<:|\\breturn\\b"
},
{
"name": "support.function.print.qamp",
"match": "\\bprint\\b|::"
}
]
},
"operators": {
"patterns": [
{
"name": "keyword.operator.assignment.qamp",
"match": "<~|=|<\\+|<&"
},
{
"name": "keyword.operator.comparison.qamp",
"match": "==|!=|<=|>=|<|>"
},
{
"name": "keyword.operator.arithmetic.qamp",
"match": "\\+|\\-|\\*|/"
},
{
"name": "keyword.operator.binary.qamp",
"match": "&|\\^|\\||~"
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.hex.qamp",
"match": "\\b0x[0-9a-fA-F]+\\b"
},
{
"name": "constant.numeric.decimal.qamp",
"match": "\\b[0-9]+\\.[0-9]+\\b|\\.[0-9]+\\b|\\b[0-9]+\\b"
}
]
},
"functions": {
"patterns": [
{
"match": "\\b(fq|funq|function)\\s+([a-zA-Z_][a-zA-Z0-9_]*)",
"captures": {
"1": { "name": "storage.type.function.qamp" },
"2": { "name": "entity.name.function.qamp" }
}
},
{
"match": "([a-zA-Z_][a-zA-Z0-9_]*)\\(",
"captures": {
"1": { "name": "entity.name.function.qamp" }
}
}
]
}
}
}

View File

@ -0,0 +1,37 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Q&",
"patterns": [
{
"name": "keyword.control.qamp",
"match": "\\b(if|else|while|return|function|fq|funq|do|for|print)\\b"
},
{
"name": "number.literal.qamp",
"match": "\\b(\\d+?)\\b"
},
{
"name": "string.quoted.double.qamp",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.qamp",
"match": "\\\\."
}
]
},
{
"name": "string.quoted.single.qamp",
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape.qamp",
"match": "\\\\."
}
]
}
],
"scopeName": "source.qamp"
}

View File

@ -17,12 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qrakhen.Qamp.Core.Tests", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qrakhen.Qamp.Tests", "Qrakhen.Qamp.Tests\Qrakhen.Qamp.Tests.csproj", "{5440D742-6149-417A-B9C8-4DEF951221E9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qrakhen.Qamp.Editor", "Qrakhen.Qamp.Editor\Qrakhen.Qamp.Editor.csproj", "{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qrakhen.Qamp.Memory", "Qrakhen.Qamp.Memory\Qrakhen.Qamp.Memory.csproj", "{A8876A55-8007-4D20-9637-2099F1B82DAE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qrakhen.TilingFrames", "Qrakhen.TilingFrames\Qrakhen.TilingFrames.csproj", "{25C7B034-34AA-44A5-A428-37942B567AC2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -87,14 +83,6 @@ Global
{5440D742-6149-417A-B9C8-4DEF951221E9}.Release|Any CPU.Build.0 = Release|Any CPU
{5440D742-6149-417A-B9C8-4DEF951221E9}.Release|x64.ActiveCfg = Release|Any CPU
{5440D742-6149-417A-B9C8-4DEF951221E9}.Release|x64.Build.0 = Release|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Debug|x64.ActiveCfg = Debug|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Debug|x64.Build.0 = Debug|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Release|Any CPU.Build.0 = Release|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Release|x64.ActiveCfg = Release|Any CPU
{BE50AA8C-7D8F-4DDA-8102-92CFCE74DA96}.Release|x64.Build.0 = Release|Any CPU
{A8876A55-8007-4D20-9637-2099F1B82DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8876A55-8007-4D20-9637-2099F1B82DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8876A55-8007-4D20-9637-2099F1B82DAE}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -103,14 +91,6 @@ Global
{A8876A55-8007-4D20-9637-2099F1B82DAE}.Release|Any CPU.Build.0 = Release|Any CPU
{A8876A55-8007-4D20-9637-2099F1B82DAE}.Release|x64.ActiveCfg = Release|Any CPU
{A8876A55-8007-4D20-9637-2099F1B82DAE}.Release|x64.Build.0 = Release|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Debug|x64.ActiveCfg = Debug|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Debug|x64.Build.0 = Debug|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Release|Any CPU.Build.0 = Release|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Release|x64.ActiveCfg = Release|Any CPU
{25C7B034-34AA-44A5-A428-37942B567AC2}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,10 +0,0 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Folder Include="Attachments\" />
</ItemGroup>
</Project>

View File

@ -1,49 +0,0 @@
# TilingFrames
## Tiling (Docking) window manager library for WPF
### Qrakhen.TilingFramess
Cool Library to have tiling panels.
Is that not cool?
I think it very much is cool.
Very nice, yes. Alpha & Beta. No Gamma or Delta. Just Alpha-Beta.
Data structure resembles a binary tree with uniform branch- and end-nodes (TilingPanels & TilingHosts).
### Node
### Panel
### Host
### Frame
### Window
### Node Structure
```cs
RootPanel
/ \
A B
/ \
Panel Host
/ \ |-Frame (Single Frame)
/ \
Panel Host
/ \ |-Frame (Tab)
/ . |-Frame (Tab)
Host
|-Frame (Tab)
|-Frame (Tab)
|-Frame (Tab)
```
Key Behaviours:
- All Panels have information about how and where their content is split in two.
- Every panel may have up to two children (Alpha/Beta), where Alpha is never null.
- Beta may not be set (In a case of a single frame with no splits, for example).
- If a child located at Alpha is detached, Beta will move to alpha, to ensure the 'Alpha is always set' paradigm.
- If a child is detached and both alpha and beta result in being null, the entire Panel is detached from its parent.
- Hosts are always at the end of the branches, everything above a Node is a Panel.
- The things you're dragging around to re-order, separate and split panels are Frames.
- Hosts contain Frames, which will be displayed as tabs if stacked atop each other, or as a single frame if only one is present.
- All mutations of the tree structure expect the root node as their first argument.
That is done so there's no two-way referencing and to keep stuff simple.

View File

@ -91,25 +91,91 @@ which should be located within your `./Build/` folder after building as describe
Here's a quick example of how you would implement virtually any library:
```cs
using Qrakhen.Qamp.Core;
using System.Math;
Value Sqrt(Value number)
// This is an intentionally bad implementation of a linked list.
[ExportType("llist")]
public class LinkedListNode : Obj
{
Assert.IsNumber(number);
[HideProperty]
public LinkedListNode? Next { get; private set; }
if (number.IsDecimal)
return Math.Sqrt(number.AsDecimal);
if (number.IsSigned)
return Math.Sqrt(number.AsSigned);
if (number.IsUnsigned)
return Math.Sqrt(number.Unsigned);
throw new Qrakhen.Qamp.Core.QampException($"Unsupported value type {value}");
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;
}
}
Injector injector = new();
injector.Register(scope: Scope.Global, name: "sqrt", params: [ ("number", ValueType.Number) ], returns: ValueType.Number);
injector.Export("desiredPath.sqi");
```
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.

View File

@ -1,5 +1,7 @@
print("\nQ& Test script.");
var now = time();
*~ how <~ 'very cool';
var _WHAT_ = "ABQ&%$#@!";
@ -11,15 +13,14 @@ var c <~ 8;
:: _WHAT_.SubString(2, 2) + ' is ' + how;
print(a * b * c * d);
if (a > d) {
:: "compare operator is sane";
} else {
:: "sanity check failed";
}
if (a > d) { :: "compare operator is sane"; }
else { :: "sanity check failed"; }
for (*~i<~1;i<=16;i++) {
:: "[" + i + "]: " + i*i;
}
for (*~i<~1;i<=16;i++) { :: "[" + i + "]: " + i * i; }
# this part is spooky as fuck, write(b) prints out random variables :x
# almost like its taking the slot index of the global register, huh...
for (;b>0;) { ::b; b--; write(b); }
fq fib(n) { if (n<2) <: 1; <: fib(n-1) + fib(n-2); }
@ -29,4 +30,19 @@ for (*~i<~0;i<16;i++) {
}
:: fibs;
:: "if you can read this, Q& probably works. Wow."
class Vector {
Vector(x, y, z) {
.~:x <~ x;
this.y = y;
this:z <~ z;
}
}
var delta = time() - now;
:: "this took " + delta + " microseconds. which are ~" + (delta / 1000) + " milliseconds.";
var content = fread("./Build/.qpb");
::typeof content;
write(content);
:: "if you can read this, Q& probably works. Wow!";

2
build
View File

@ -7,5 +7,5 @@ DATE=`date`
mkdir -p $FOUT
cp -r ./Static/ $FOUT
echo "$DEST" > "$FOUT.qpb"
echo "$date" >> "$FOUT.qpb"
echo "$DATE" >> "$FOUT.qpb"
dotnet build ./Qrakhen.Qamp.CLI/ -o $FOUT