better build, global native functions (spicy C style), some nice things, some bad things
This commit is contained in:
parent
1da47d39dd
commit
1bbaa98add
|
|
@ -1,14 +0,0 @@
|
||||||
print("\nQ& Test script.");
|
|
||||||
|
|
||||||
*~ how <~ 'very cool';
|
|
||||||
var _WHAT_ = "ABQ&%$#@!";
|
|
||||||
|
|
||||||
var a = 7;
|
|
||||||
*~ b <~ 12;
|
|
||||||
var c <~ 8;
|
|
||||||
*~ d = 3;
|
|
||||||
|
|
||||||
:: _WHAT_.SubString(2, 2) + ' is ' + how;
|
|
||||||
print(a * b * c * d);
|
|
||||||
|
|
||||||
:: "if you can read this, Q& probably works. Wow."
|
|
||||||
|
|
@ -102,6 +102,69 @@ public class Runner : IDisposable
|
||||||
IO.Console.StdOut ??= options.StdOut;
|
IO.Console.StdOut ??= options.StdOut;
|
||||||
IO.Console.StdIn ??= options.StdIn;
|
IO.Console.StdIn ??= options.StdIn;
|
||||||
|
|
||||||
|
Globals["time"] = Obj.Create(new NativeFunction("time",
|
||||||
|
v => new Value(DateTime.Now.Ticks / 100)));
|
||||||
|
|
||||||
|
Globals["ftime"] = Obj.Create(new NativeFunction("ftime",
|
||||||
|
v =>
|
||||||
|
String.Make(
|
||||||
|
new DateTime(v[0].Signed * 10)
|
||||||
|
.ToString(
|
||||||
|
v[1].GetString() ??
|
||||||
|
Timestamp.DefaultFormat)),
|
||||||
|
"time",
|
||||||
|
"format"));
|
||||||
|
|
||||||
|
Globals["sin"] = Obj.Create(new NativeFunction("sin",
|
||||||
|
v => new Value(Math.Sin(v[0].GetDecimal())), "v"));
|
||||||
|
|
||||||
|
Globals["cos"] = Obj.Create(new NativeFunction("cos",
|
||||||
|
v => new Value(Math.Cos(v[0].GetDecimal())), "v"));
|
||||||
|
|
||||||
|
Globals["exit"] = Obj.Create(new NativeFunction("exit", v => {
|
||||||
|
Environment.Exit((int)(v.FirstOrDefault().Signed));
|
||||||
|
return Value.Void;
|
||||||
|
},
|
||||||
|
"code?"));
|
||||||
|
|
||||||
|
Globals["read"] = Obj.Create(new NativeFunction("read", v =>
|
||||||
|
String.Make(IO.Console.StdIn())));
|
||||||
|
|
||||||
|
Globals["write"] = Obj.Create(new NativeFunction("write", v => {
|
||||||
|
try {
|
||||||
|
if (v[0].GetString() is string content) {
|
||||||
|
IO.Console.StdOut(content);
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
return Value.Void;
|
||||||
|
},
|
||||||
|
"content"));
|
||||||
|
|
||||||
|
Globals["fread"] = Obj.Create(new NativeFunction("fread", v =>
|
||||||
|
(v[0].GetString() is string path && File.Exists(Path.GetFullPath(path))) ?
|
||||||
|
String.Make(
|
||||||
|
File.ReadAllText(
|
||||||
|
Path.GetFullPath(path))) :
|
||||||
|
Value.Void,
|
||||||
|
"path"));
|
||||||
|
|
||||||
|
Globals["fwrite"] = Obj.Create(new NativeFunction("fwrite", v => {
|
||||||
|
try {
|
||||||
|
if (v[0].GetString() is string path) {
|
||||||
|
File.WriteAllText(
|
||||||
|
path,
|
||||||
|
v[1].GetString());
|
||||||
|
} else {
|
||||||
|
return Value.False;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return Value.False;
|
||||||
|
}
|
||||||
|
return Value.True;
|
||||||
|
},
|
||||||
|
"path",
|
||||||
|
"content?"));
|
||||||
|
|
||||||
_router.Register(new ArithmeticResolver());
|
_router.Register(new ArithmeticResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -569,6 +632,27 @@ public class Runner : IDisposable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool InvokeNative(NativeFunction native, int argumentCount)
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
_logger.Method(native);
|
||||||
|
#endif
|
||||||
|
if (argumentCount != native.Arguments.Length) {
|
||||||
|
Error($"{native} expects {native.Arguments.Length} arguments, received {argumentCount}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = new Value[argumentCount];
|
||||||
|
for (int i = 0; i < argumentCount; i++) {
|
||||||
|
values[i] = Peek(-i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_stack.Decimate(_stack.Position - argumentCount - 1);
|
||||||
|
Value result = native.Target.Invoke(values);
|
||||||
|
Push(result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool Invoke(Context closure, int argumentCount)
|
private bool Invoke(Context closure, int argumentCount)
|
||||||
{
|
{
|
||||||
#if LOG
|
#if LOG
|
||||||
|
|
@ -620,19 +704,19 @@ public class Runner : IDisposable
|
||||||
private bool Invoke(Value value, int argumentCount)
|
private bool Invoke(Value value, int argumentCount)
|
||||||
{
|
{
|
||||||
if (!value.IsObj) {
|
if (!value.IsObj) {
|
||||||
Error($"Can only call values of object type! Tried to call {value.ToString(true)}", value);
|
Error($"Can only invoke non-primitive values! Tried to invoke {value.ToString(true)}", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.Is(T.Method)) {
|
if (value.Is(T.Native)) {
|
||||||
|
return InvokeNative(value.Ptr.As<NativeFunction>(), argumentCount);
|
||||||
|
} else if (value.Is(T.Method)) {
|
||||||
Method method = value.Ptr.As<Method>()!;
|
Method method = value.Ptr.As<Method>()!;
|
||||||
_stack.Set(_cursor - method.Function.ArgumentCount - 1, method.Receiver);
|
_stack.Set(_cursor - method.Function.ArgumentCount - 1, method.Receiver);
|
||||||
return Invoke(method, method.Function.ArgumentCount);
|
return Invoke(method, method.Function.ArgumentCount);
|
||||||
} else if (value.Is(T.Context)) {
|
} else if (value.Is(T.Context)) {
|
||||||
Context? context = value.Ptr.As<Context>()!;
|
Context? context = value.Ptr.As<Context>()!;
|
||||||
return Invoke(context, context.Function.ArgumentCount);
|
return Invoke(context, context.Function.ArgumentCount);
|
||||||
} else if (value.Is(T.Native)) {
|
|
||||||
throw new NotImplementedException("i dont really want globals in this language so lets see");
|
|
||||||
} else if (value.Is(T.Class)) {
|
} else if (value.Is(T.Class)) {
|
||||||
Class? @class = value.Ptr.As<Class>()!;
|
Class? @class = value.Ptr.As<Class>()!;
|
||||||
_stack.Set(_cursor - argumentCount - 1, Instantiate(@class));
|
_stack.Set(_cursor - argumentCount - 1, Instantiate(@class));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||||
|
|
||||||
|
public class Timestamp(Value timeStamp) : Native(nameof(Timestamp))
|
||||||
|
{
|
||||||
|
public static readonly string DefaultFormat = "H:m:s d.M.y";
|
||||||
|
|
||||||
|
// cheap ass workaround i know
|
||||||
|
private DateTime _dateTime = new DateTime(timeStamp.Signed * 10);
|
||||||
|
|
||||||
|
public Value Raw = timeStamp;
|
||||||
|
|
||||||
|
public Value Format(Value? format = null)
|
||||||
|
{
|
||||||
|
return String.Make(_dateTime.ToString(format?.Ptr.As<String>()?.Value ?? DefaultFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => ToString(true);
|
||||||
|
public string ToString(bool detail) => detail ?
|
||||||
|
$"[Timestamp <{_dateTime}>]" :
|
||||||
|
_dateTime.ToString(DefaultFormat);
|
||||||
|
}
|
||||||
|
|
@ -31,4 +31,16 @@ public class Function(string name, Segment segment, int outerCount, int argument
|
||||||
}
|
}
|
||||||
return result.ToArray();
|
return result.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// local c# function, so compiled inside the binary already
|
||||||
|
// cheap shortcut for global methods for now.
|
||||||
|
public class NativeFunction(string name, Func<Value[], Value> target, params string[] arguments) : Obj(ValueType.Native)
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public Func<Value[], Value> Target { get; } = target;
|
||||||
|
|
||||||
|
public string[] Arguments { get; } = arguments;
|
||||||
|
|
||||||
|
public override string ToString() => $"[NativeFunction <{Name}> ({string.Join(", ", Arguments)})]";
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@ public class Method(Function function, Value receiver) : Context(function, Value
|
||||||
{
|
{
|
||||||
public Value Receiver = receiver;
|
public Value Receiver = receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ namespace Qrakhen.Qamp.Core.Values.Objects;
|
||||||
|
|
||||||
public class String(string? value) : Obj(ValueType.String)
|
public class String(string? value) : Obj(ValueType.String)
|
||||||
{
|
{
|
||||||
|
// yea that's quite temporary
|
||||||
private static readonly Register<uint, String> _strings = new();
|
private static readonly Register<uint, String> _strings = new();
|
||||||
|
|
||||||
public string? Value = value;
|
public string? Value = value;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,11 @@ public readonly struct Value :
|
||||||
|
|
||||||
public bool IsFalsy => IsBool ? Bool == false : Unsigned == 0;
|
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;
|
||||||
|
public double GetDecimal() => IsDecimal ? Decimal : (double)Signed;
|
||||||
|
|
||||||
public bool Is(T type, bool exact = true)
|
public bool Is(T type, bool exact = true)
|
||||||
{
|
{
|
||||||
return exact ? (Type & type) == type : (Type & type) > 0;
|
return exact ? (Type & type) == type : (Type & type) > 0;
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
/// edit: if that's even possible with c#'s memory padding
|
/// edit: if that's even possible with c#'s memory padding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum ValueType
|
public enum ValueType : ushort
|
||||||
{
|
{
|
||||||
Undefined = -1,
|
Undefined = 0xFFFF,
|
||||||
Void = 0x0000,
|
Void = 0x0000,
|
||||||
Unsigned = 0x0001,
|
Unsigned = 0x0001,
|
||||||
Signed = 0x0002,
|
Signed = 0x0002,
|
||||||
|
|
@ -26,7 +26,7 @@ public enum ValueType
|
||||||
Reference = 0x1000,
|
Reference = 0x1000,
|
||||||
Pointer = 0x2000,
|
Pointer = 0x2000,
|
||||||
|
|
||||||
Object = Pointer | 0x4000,
|
Object = Pointer | 0x2000,
|
||||||
Native = Object | 0x0001,
|
Native = Object | 0x0001,
|
||||||
String = Object | 0x0002,
|
String = Object | 0x0002,
|
||||||
Function = Object | 0x0020,
|
Function = Object | 0x0020,
|
||||||
|
|
@ -36,10 +36,12 @@ public enum ValueType
|
||||||
Method = Class | Function,
|
Method = Class | Function,
|
||||||
Outer = Object | 0x0200,
|
Outer = Object | 0x0200,
|
||||||
|
|
||||||
ItemProvider = Object | 0x8000, // accessible with [n] or :n (getters / setters)
|
Complex = Object | 0x0800,
|
||||||
|
|
||||||
|
ItemProvider = Object | 0x4000, // accessible with [n] or :n (getters / setters)
|
||||||
Array = ItemProvider | 0x0001,
|
Array = ItemProvider | 0x0001,
|
||||||
List = ItemProvider | 0x0002,
|
List = ItemProvider | 0x0002,
|
||||||
Structure = ItemProvider | 0x0004,
|
Structure = ItemProvider | 0x0004,
|
||||||
|
|
||||||
Module = 0xFFFF
|
Module = 0x8000
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
print("\nQ& Test script.");
|
||||||
|
|
||||||
|
*~ how <~ 'very cool';
|
||||||
|
var _WHAT_ = "ABQ&%$#@!";
|
||||||
|
|
||||||
|
var a = 7;
|
||||||
|
*~ b <~ 12;
|
||||||
|
var c <~ 8;
|
||||||
|
*~ d = 3;
|
||||||
|
|
||||||
|
:: _WHAT_.SubString(2, 2) + ' is ' + how;
|
||||||
|
print(a * b * c * d);
|
||||||
|
|
||||||
|
if (a > d) {
|
||||||
|
:: "compare operator is sane";
|
||||||
|
} else {
|
||||||
|
:: "sanity check failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (*~i<~1;i<=16;i++) {
|
||||||
|
:: "[" + i + "]: " + i*i;
|
||||||
|
}
|
||||||
|
|
||||||
|
fq fib(n) { if (n<2) <: 1; <: fib(n-1) + fib(n-2); }
|
||||||
|
|
||||||
|
*~ fibs <~ 'fibonacci sequence:';
|
||||||
|
for (*~i<~0;i<16;i++) {
|
||||||
|
fibs = fibs + " " + fib(i);
|
||||||
|
}
|
||||||
|
:: fibs;
|
||||||
|
|
||||||
|
:: "if you can read this, Q& probably works. Wow."
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DEST='net10.0'
|
||||||
|
FOUT='./Build/'
|
||||||
|
DATE=`date`
|
||||||
|
|
||||||
|
mkdir -p $FOUT
|
||||||
|
cp -r ./Static/ $FOUT
|
||||||
|
echo "$DEST" > "$FOUT.qpb"
|
||||||
|
echo "$date" >> "$FOUT.qpb"
|
||||||
|
dotnet build ./Qrakhen.Qamp.CLI/ -o $FOUT
|
||||||
4
debug
4
debug
|
|
@ -1,5 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
DEST='net10.0'
|
source ./build && ./Build/Qrakhen.Qamp.CLI -i "$FOUT/Static/test.qp"
|
||||||
echo "\e[5mBeelding for dotnet version $DEST like it's not a big deal.\e[0m"
|
|
||||||
dotnet build ./Qrakhen.Qamp.CLI/ && ./Build/Debug/net10.0/Qrakhen.Qamp.CLI -i ./Qrakhen.Qamp.CLI/test.qp
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue