Most of the rewrite
This commit is contained in:
parent
f473f33521
commit
fd81f5b33b
12 changed files with 715 additions and 15 deletions
|
@ -3,18 +3,3 @@ Projects = {Automate = {Path = "."}}
|
||||||
|
|
||||||
[Workspace]
|
[Workspace]
|
||||||
StartupProject = "Automate"
|
StartupProject = "Automate"
|
||||||
|
|
||||||
[Configs.Debug.wasm32]
|
|
||||||
AllocType = "CRT"
|
|
||||||
EnableObjectDebugFlags = false
|
|
||||||
EmitObjectAccessCheck = false
|
|
||||||
|
|
||||||
[Configs.Paranoid.wasm32]
|
|
||||||
AllocType = "CRT"
|
|
||||||
EnableObjectDebugFlags = false
|
|
||||||
EmitObjectAccessCheck = false
|
|
||||||
|
|
||||||
[Configs.Test.wasm32]
|
|
||||||
AllocType = "CRT"
|
|
||||||
EnableObjectDebugFlags = false
|
|
||||||
EmitObjectAccessCheck = false
|
|
||||||
|
|
22
src/AuBytecode.bf
Normal file
22
src/AuBytecode.bf
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
namespace Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
class AuBytecode
|
||||||
|
{
|
||||||
|
public List<int64> Instructions = new .(100) {0} ~ delete _;
|
||||||
|
|
||||||
|
public List<AuValue> Constants = new .() {.() };
|
||||||
|
|
||||||
|
public Dictionary<AuValue, int64> ConstantMap = new .() ~ delete _;
|
||||||
|
public Dictionary<String, int64> RegisterMap = new .() ~ DeleteDictionaryAndKeys!(_);
|
||||||
|
public Dictionary<String, int64> FunctionMap = new .() ~ DeleteDictionaryAndKeys!(_);
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
for(var i in Constants)
|
||||||
|
i.Dispose();
|
||||||
|
delete Constants;
|
||||||
|
}
|
||||||
|
}
|
169
src/AuCompiler.bf
Normal file
169
src/AuCompiler.bf
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
namespace Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
class AuCompiler
|
||||||
|
{
|
||||||
|
public static Result<void> Compile(StringView pCode, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
///Tokenize everything and then parse the tokens one by one
|
||||||
|
List<StringView> Tokens = new .();
|
||||||
|
defer delete Tokens;
|
||||||
|
|
||||||
|
for (var line in pCode.Split('\n'))
|
||||||
|
{
|
||||||
|
if (line..TrimStart().StartsWith('#'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (var part in line.Split(' ', '\t'))
|
||||||
|
{
|
||||||
|
if (part.StartsWith('"'))
|
||||||
|
{
|
||||||
|
int tokenStart = @line.Pos + @part.Pos;
|
||||||
|
while (
|
||||||
|
@part.HasMore
|
||||||
|
&& (!part.EndsWith('"')
|
||||||
|
|| part.EndsWith("\\\""))
|
||||||
|
)
|
||||||
|
part = @part.GetNext();
|
||||||
|
int tokenEnd = @line.Pos + @part.Pos + part.Length;
|
||||||
|
Tokens.Add(pCode.Substring(tokenStart, tokenEnd - tokenStart));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Tokens.Add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i in Tokens.Reversed)
|
||||||
|
{
|
||||||
|
if (ProcessToken(i, pInstructions, pContext) case .Err)
|
||||||
|
return .Err;
|
||||||
|
Tokens.PopBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<void> ProcessToken(StringView pToken, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
if (pToken.IsEmpty)
|
||||||
|
return .Ok;
|
||||||
|
|
||||||
|
else if (pToken[0].IsNumber || pToken[0] == '-')
|
||||||
|
if(!pToken.Contains('.') && int.Parse(pToken) case .Ok(let val)) HandleNumberToken(val, pInstructions, pContext);
|
||||||
|
else if (Double.Parse(pToken) case .Ok(let val)) HandleNumberToken(val, pInstructions, pContext);
|
||||||
|
else return .Err;
|
||||||
|
else if (pToken[0] == '<')
|
||||||
|
{
|
||||||
|
HandleRegisterToken(.(pToken, 1), pInstructions, pContext);
|
||||||
|
pContext.Instructions.Add(1);
|
||||||
|
}
|
||||||
|
else if (pToken[0] == '>')
|
||||||
|
{
|
||||||
|
HandleRegisterToken(.(pToken, 1), pInstructions, pContext);
|
||||||
|
pContext.Instructions.Add(2);
|
||||||
|
}
|
||||||
|
else if (pToken[0] == '$') HandleLabelToken(.(pToken, 1), pInstructions, pContext);
|
||||||
|
else if (pToken[0] == '"') HandleStringToken(.(pToken, 1), pInstructions, pContext);
|
||||||
|
else HandleFunctionToken(pToken, pInstructions, pContext);
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleNumberToken(double pNum, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
For numeric constants we simply check wether they already exist and add them if they dont
|
||||||
|
*/
|
||||||
|
var variant = AuValue.Double(pNum);
|
||||||
|
var ret = AddConstantOrReturnConstantIndex(variant, pContext);
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
variant.Dispose();
|
||||||
|
ret = ret * -1;
|
||||||
|
}
|
||||||
|
pContext.Instructions.Add(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleStringToken(StringView pString, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
String constants are fist correctly escaped, before being added to the list of constants if they are on there
|
||||||
|
*/
|
||||||
|
|
||||||
|
String s = new .(pString);
|
||||||
|
if (s.EndsWith('"'))
|
||||||
|
s.RemoveFromEnd(1);
|
||||||
|
var escaped = s.Unescape(.. scope .());
|
||||||
|
s..Clear().Append(escaped);
|
||||||
|
|
||||||
|
var variant = AuValue.String(s);
|
||||||
|
var ret = AddConstantOrReturnConstantIndex(variant, pContext);
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
variant.Dispose();
|
||||||
|
ret = ret * -1;
|
||||||
|
}
|
||||||
|
pContext.Instructions.Add(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleLabelToken(StringView pString, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Labels in automate are basically functions
|
||||||
|
We add a 0 instruction to the list of instructions
|
||||||
|
If the function already exists we change it to point to the new definition
|
||||||
|
It it doesnt we just add a new defintion
|
||||||
|
*/
|
||||||
|
pContext.Instructions.Add(0);
|
||||||
|
var res = AddConstantOrReturnConstantIndex(AuValue.Double(pContext.Instructions.Count - 1), pContext);
|
||||||
|
if (pContext.FunctionMap.ContainsKeyAlt<StringView>(pString))
|
||||||
|
pContext.FunctionMap[scope:: .(pString)] = res > 0 ? -1 * res : res;
|
||||||
|
else
|
||||||
|
pContext.FunctionMap.Add(new .(pString), res > 0 ? -1 * res : res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleRegisterToken(StringView pString, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
if (!pContext.RegisterMap.ContainsKeyAlt<StringView>(pString))
|
||||||
|
{
|
||||||
|
var res = AddConstantOrReturnConstantIndex(AuValue.Double(pContext.RegisterMap.Count + 1), pContext);
|
||||||
|
String reg = new .(pString);
|
||||||
|
pContext.RegisterMap.Add(reg, res > 0 ? -1 * res : res);
|
||||||
|
}
|
||||||
|
pContext.Instructions.Add(pContext.RegisterMap.GetValue(scope .(pString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleFunctionToken(StringView pString, AuInstructions pInstructions, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
if (pInstructions.InstructionMap.GetValue(pString) case .Ok(let val))
|
||||||
|
pContext.Instructions.Add(val);
|
||||||
|
else if (pContext.FunctionMap.GetValue(scope .(pString)) case .Ok(let val))
|
||||||
|
{
|
||||||
|
pContext.Instructions.Add(val);
|
||||||
|
pContext.Instructions.Add(3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var variant = AuValue.String(new .(pString));
|
||||||
|
var res = AddConstantOrReturnConstantIndex(variant, pContext);
|
||||||
|
if(res > 0)
|
||||||
|
variant.Dispose();
|
||||||
|
pContext.Instructions.Add(res > 0 ? -1 * res : res);
|
||||||
|
pContext.Instructions.Add(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int64 AddConstantOrReturnConstantIndex(AuValue pToAdd, AuBytecode pContext)
|
||||||
|
{
|
||||||
|
///The constant already exists
|
||||||
|
if (pContext.ConstantMap.GetValue(pToAdd) case .Ok(let val))
|
||||||
|
return val;
|
||||||
|
|
||||||
|
///Constant doesnt exist
|
||||||
|
pContext.Constants.Add(pToAdd);
|
||||||
|
pContext.ConstantMap.Add(pToAdd, pContext.Constants.Count - 1);
|
||||||
|
return -1 * pContext.ConstantMap[pToAdd];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
126
src/AuContext.bf
Normal file
126
src/AuContext.bf
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
namespace Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Represents a runtime context
|
||||||
|
which is a snapshot of the current state of the program
|
||||||
|
It contains the instruction counter aswell as the stack and registers
|
||||||
|
If you use multiple runtime contexts you can potentially do something like multithreading with this
|
||||||
|
*/
|
||||||
|
class AuContext
|
||||||
|
{
|
||||||
|
public int64 InstructionPointer = 0;
|
||||||
|
public bool ShouldExit = false;
|
||||||
|
public bool RuntimeError = false;
|
||||||
|
public List<AuValue> Stack = new .(100);
|
||||||
|
public List<int64> CallStack = new .(30) ~ delete _;
|
||||||
|
public Dictionary<int64, AuValue> Registers = new .();
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
for(var i in Registers)
|
||||||
|
i.value.Dispose();
|
||||||
|
delete Registers;
|
||||||
|
for(var i in Stack)
|
||||||
|
i.Dispose();
|
||||||
|
delete Stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///Peek the last added object
|
||||||
|
[Inline]
|
||||||
|
public AuValue Peek()
|
||||||
|
{
|
||||||
|
if(Stack.Count > 0)
|
||||||
|
return Stack[^1];
|
||||||
|
return .();
|
||||||
|
}
|
||||||
|
|
||||||
|
///Peek the nth last added object
|
||||||
|
[Inline]
|
||||||
|
public AuValue PeekN(int pOffset)
|
||||||
|
{
|
||||||
|
if(Stack.Count > pOffset)
|
||||||
|
return Stack[^pOffset];
|
||||||
|
return .();
|
||||||
|
}
|
||||||
|
|
||||||
|
///Add a new variant to the stack
|
||||||
|
[Inline]
|
||||||
|
public void Push(AuValue pToAdd)
|
||||||
|
{
|
||||||
|
Stack.Add(pToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
for(var i in Stack)
|
||||||
|
i.Dispose();
|
||||||
|
Stack.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///Pops the highest object on the stack
|
||||||
|
[Inline]
|
||||||
|
public AuValue Pop()
|
||||||
|
{
|
||||||
|
if(Stack.Count > 0)
|
||||||
|
return Stack.PopBack();
|
||||||
|
return .();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Span<AuValue> PopN(int32 n)
|
||||||
|
{
|
||||||
|
if(Stack.Count >= n)
|
||||||
|
return .(Stack.PopBackN(n), n);
|
||||||
|
return .();
|
||||||
|
}
|
||||||
|
|
||||||
|
///Pops the highest object and automatically disposes it in the scope of it being called
|
||||||
|
public mixin Pop()
|
||||||
|
{
|
||||||
|
var val = Pop();
|
||||||
|
defer:mixin val.Dispose();
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FatalError()
|
||||||
|
{
|
||||||
|
ShouldExit = true;
|
||||||
|
RuntimeError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Run(AuInstructions pInstructions, AuBytecode pCContext)
|
||||||
|
{
|
||||||
|
while(!this.ShouldExit)
|
||||||
|
{
|
||||||
|
var current = pCContext.Instructions[this.InstructionPointer];
|
||||||
|
if(current >= 0)
|
||||||
|
{
|
||||||
|
pInstructions.Instructions[current].Invoke(pInstructions, pCContext, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
else //Push something onto the stack from our list of constants
|
||||||
|
{
|
||||||
|
var toPush = pCContext.Constants[-1 * current];
|
||||||
|
switch(toPush)
|
||||||
|
{
|
||||||
|
case .Double(let val): this.Push(.Double(val));
|
||||||
|
case .String(let val): this.Push(.String(new .(val)));
|
||||||
|
case .Variant(let val): this.Push(.Variant(val));
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.InstructionPointer++;
|
||||||
|
if(!(this.InstructionPointer < pCContext.Instructions.Count))
|
||||||
|
return 0; //All instructions are done executing
|
||||||
|
}
|
||||||
|
if(RuntimeError)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
64
src/AuInstructions.bf
Normal file
64
src/AuInstructions.bf
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
namespace Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
class AuInstructions
|
||||||
|
{
|
||||||
|
public enum InstructionsLoadFlags : uint32
|
||||||
|
{
|
||||||
|
None = 0, //No instructions except stuff the compiler needs
|
||||||
|
Core = 1, //All of the core instructions
|
||||||
|
Math = _*2, //Lots of additional math instructions
|
||||||
|
IO = _*2, //Instructions for working with files and directories
|
||||||
|
Meta = _*2, //UNSAFE: Instructions that can change instructions and are generally unsafe to use on user input
|
||||||
|
|
||||||
|
All = Core | Math | IO | Meta //All available instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///Stores the raw data of all available instructions
|
||||||
|
public List<delegate void(AuInstructions set, AuBytecode context, AuContext data)> Instructions = new .(100) {
|
||||||
|
new (a,b,c) => {},
|
||||||
|
new => Automate.Instructions.Buildins.PushRegister,
|
||||||
|
new => Automate.Instructions.Buildins.PopRegister,
|
||||||
|
new => Automate.Instructions.Buildins.CallFunction,
|
||||||
|
new => Automate.Instructions.Buildins.CallFunctionString,
|
||||||
|
}~ DeleteContainerAndItems!(_);
|
||||||
|
|
||||||
|
///Maps the name of instructions to their index
|
||||||
|
public Dictionary<StringView, int64> InstructionMap = new .(100) ~ delete _;
|
||||||
|
|
||||||
|
|
||||||
|
public this(InstructionsLoadFlags pFlags)
|
||||||
|
{
|
||||||
|
if(pFlags.HasFlag(.Core))
|
||||||
|
Automate.Instructions.Core.AddCoreInstructions(this);
|
||||||
|
if(pFlags.HasFlag(.Math))
|
||||||
|
Automate.Instructions.Math.AddMathInstructions(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Attempt to add a new instruction
|
||||||
|
public Result<void> AddInstruction(StringView pName, delegate void(AuInstructions set, AuBytecode context, AuContext data) pInstruction)
|
||||||
|
{
|
||||||
|
if(InstructionMap.ContainsKey(pName))
|
||||||
|
return .Err;
|
||||||
|
Instructions.Add(pInstruction);
|
||||||
|
InstructionMap.Add(pName, Instructions.Count-1);
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Remove all instructions
|
||||||
|
public void ClearInstructions()
|
||||||
|
{
|
||||||
|
for(var i in Instructions)
|
||||||
|
delete i;
|
||||||
|
InstructionMap.Clear();
|
||||||
|
Instructions.Add(new (a,b,c) => {});
|
||||||
|
Instructions.Add(new => Automate.Instructions.Buildins.PushRegister);
|
||||||
|
Instructions.Add(new => Automate.Instructions.Buildins.PopRegister);
|
||||||
|
Instructions.Add(new => Automate.Instructions.Buildins.CallFunction);
|
||||||
|
Instructions.Add(new => Automate.Instructions.Buildins.CallFunctionString);
|
||||||
|
}
|
||||||
|
}
|
31
src/AuValue.bf
Normal file
31
src/AuValue.bf
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
namespace Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
enum AuValue : IHashable, IDisposable
|
||||||
|
{
|
||||||
|
case String(String val);
|
||||||
|
case Double(double val);
|
||||||
|
case Variant(Variant val);
|
||||||
|
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
switch (this)
|
||||||
|
{
|
||||||
|
case .String(var val): return val.GetHashCode();
|
||||||
|
case .Double(var val): return val.GetHashCode();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
switch(this)
|
||||||
|
{
|
||||||
|
case .String(var val): delete val;
|
||||||
|
case .Variant(var val): val.Dispose();
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/Extensions.bf
Normal file
18
src/Extensions.bf
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
namespace System.Collections;
|
||||||
|
|
||||||
|
extension List<T>
|
||||||
|
{
|
||||||
|
[Checked]
|
||||||
|
public T* PopBackN(int32 n)
|
||||||
|
{
|
||||||
|
Runtime.Assert(mSize - n >= 0);
|
||||||
|
return &mItems[mSize -= n];
|
||||||
|
}
|
||||||
|
|
||||||
|
[Unchecked]
|
||||||
|
public T* PopBackN(int32 n)
|
||||||
|
{
|
||||||
|
Runtime.Assert(mSize - n >= 0);
|
||||||
|
return &mItems[mSize -= n];
|
||||||
|
}
|
||||||
|
}
|
81
src/Instructions/Buildins.bf
Normal file
81
src/Instructions/Buildins.bf
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
namespace Automate.Instructions;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
class Buildins
|
||||||
|
{
|
||||||
|
|
||||||
|
///Push the current value of a register onto the stack
|
||||||
|
public static void PushRegister(AuInstructions set, AuBytecode context, AuContext data)
|
||||||
|
{
|
||||||
|
var register = data.Pop!();
|
||||||
|
switch(register)
|
||||||
|
{
|
||||||
|
case .Double(let val):
|
||||||
|
if(data.Registers.GetValue((.)val) case .Ok(let value))
|
||||||
|
{
|
||||||
|
switch(value)
|
||||||
|
{
|
||||||
|
case .Double(let p):
|
||||||
|
data.Push(.Double(p));
|
||||||
|
case .String(let p):
|
||||||
|
data.Push(.String(new .(p)));
|
||||||
|
case .Variant(let p):
|
||||||
|
data.Push(.Variant(p));
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Pop the upper value of the stack into a register
|
||||||
|
public static void PopRegister(AuInstructions set, AuBytecode context, AuContext data)
|
||||||
|
{
|
||||||
|
if(data.Pop!() case .Double(let register))
|
||||||
|
{
|
||||||
|
var val = data.Pop!();
|
||||||
|
if(data.Registers.ContainsKey((.)register))
|
||||||
|
data.Registers[(.)register].Dispose();
|
||||||
|
switch(val)
|
||||||
|
{
|
||||||
|
case .Double(let v):
|
||||||
|
data.Registers[(.)register] = .Double(v);
|
||||||
|
case .String(let v):
|
||||||
|
data.Registers[(.)register] = .String(new .(v));
|
||||||
|
case .Variant(let v):
|
||||||
|
data.Registers[(.)register] = .Variant(v);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CallFunction(AuInstructions set, AuBytecode context, AuContext data)
|
||||||
|
{
|
||||||
|
data.CallStack.Add(data.InstructionPointer);
|
||||||
|
var func = data.Pop!();
|
||||||
|
switch(func)
|
||||||
|
{
|
||||||
|
case .Double(let val):
|
||||||
|
data.InstructionPointer = (.)val;
|
||||||
|
default:
|
||||||
|
data.FatalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CallFunctionString(AuInstructions set, AuBytecode context, AuContext data)
|
||||||
|
{
|
||||||
|
data.CallStack.Add(data.InstructionPointer);
|
||||||
|
var func = data.Pop!();
|
||||||
|
switch(func)
|
||||||
|
{
|
||||||
|
case .String(let val):
|
||||||
|
if(context.FunctionMap.GetValue(val) case .Ok(let index) && context.Constants[-1 * index] case .Double(let value))
|
||||||
|
data.InstructionPointer = (.)value;
|
||||||
|
else
|
||||||
|
data.FatalError();
|
||||||
|
default:
|
||||||
|
data.FatalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
src/Instructions/Core.bf
Normal file
66
src/Instructions/Core.bf
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
namespace Automate.Instructions;
|
||||||
|
|
||||||
|
using Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
class Core
|
||||||
|
{
|
||||||
|
public static void AddCoreInstructions(AuInstructions pSet)
|
||||||
|
{
|
||||||
|
pSet.AddInstruction("echo", new => Echo);
|
||||||
|
pSet.AddInstruction("return", new => Return);
|
||||||
|
pSet.AddInstruction("call", new => Call);
|
||||||
|
pSet.AddInstruction("if", new => If);
|
||||||
|
pSet.AddInstruction("equals", new => Equals);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Echo(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
var res = pContext.Pop!();
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case .String(let val): Console.WriteLine(val);
|
||||||
|
case .Double(let val): Console.WriteLine(val);
|
||||||
|
case .Variant(let val): Console.WriteLine(val);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Return(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
if(pContext.CallStack.Count >= 1)
|
||||||
|
pContext.InstructionPointer = pContext.CallStack.PopBack();
|
||||||
|
else
|
||||||
|
pContext.ShouldExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Equals(AuInstructions pSet, AuBytecode pInstructions, AuContext pContext)
|
||||||
|
{
|
||||||
|
switch(pContext.Pop!())
|
||||||
|
{
|
||||||
|
case .Double(let val): if(pContext.Pop!() case .Double(let r) && val == r) pContext.Push(.Double(1));
|
||||||
|
case .String(let val): if(pContext.Pop!() case .String(let r) && val == r) pContext.Push(.Double(1));
|
||||||
|
case .Variant(let val): if(pContext.Pop!() case .Variant(let r) && val == r) pContext.Push(.Double(1));
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void If(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
if(pContext.Pop!() case .Double(let val) && val > 0)
|
||||||
|
if(pContext.Pop!() case .Double(let jmp))
|
||||||
|
pContext.InstructionPointer += (.)jmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Call(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
if(pContext.Pop!() case .String(let val) && pCContext.FunctionMap.GetValue(val) case .Ok(let index) && pCContext.Constants[-1 * index] case .Double(let value))
|
||||||
|
{
|
||||||
|
pContext.CallStack.Add(pContext.InstructionPointer);
|
||||||
|
pContext.InstructionPointer = (.)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/Instructions/InstructionGenerator.bf
Normal file
37
src/Instructions/InstructionGenerator.bf
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
namespace Automate.Instructions;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
class InstructionGenerator : Compiler.Generator
|
||||||
|
{
|
||||||
|
public override String Name => "New Instruction"; // This is was the generator will show up as in the "Generator" dropdown
|
||||||
|
|
||||||
|
public override void InitUI()
|
||||||
|
{
|
||||||
|
AddEdit("name", "Class Name", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Generate(String outFileName, String outText, ref Flags generateFlags)
|
||||||
|
{
|
||||||
|
var name = mParams["name"];
|
||||||
|
if (name.EndsWith(".bf", .OrdinalIgnoreCase))
|
||||||
|
name.RemoveFromEnd(3);
|
||||||
|
|
||||||
|
outFileName.Append(name);
|
||||||
|
outText.AppendF($"""
|
||||||
|
namespace {Namespace};
|
||||||
|
|
||||||
|
using Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
class {scope String(name)..Replace(' ', '_')}
|
||||||
|
{{
|
||||||
|
public static void Instruction_{scope String(name)..Replace(' ', '_')}(AuInstructions set, AuBytecode context, AuContext data)
|
||||||
|
{{
|
||||||
|
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
82
src/Instructions/Math.bf
Normal file
82
src/Instructions/Math.bf
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
namespace Automate.Instructions;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
class Math
|
||||||
|
{
|
||||||
|
public static void AddMathInstructions(AuInstructions pSet)
|
||||||
|
{
|
||||||
|
pSet.AddInstruction("add", new => Add);
|
||||||
|
pSet.AddInstruction("sub", new => Sub);
|
||||||
|
pSet.AddInstruction("mult", new => Mult);
|
||||||
|
pSet.AddInstruction("div", new => Div);
|
||||||
|
pSet.AddInstruction("sqr", new => Sqr);
|
||||||
|
pSet.AddInstruction("sqrt", new => Sqrt);
|
||||||
|
pSet.AddInstruction("pow", new => Pow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Add(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
Span<AuValue> arr = pContext.PopN(2);
|
||||||
|
if(arr[0] case .Double(let lhs) && arr[1] case .Double(let rhs))
|
||||||
|
pContext.Push(.Double(lhs + rhs));
|
||||||
|
|
||||||
|
for(var i in arr)
|
||||||
|
i.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Sub(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
Span<AuValue> arr = pContext.PopN(2);
|
||||||
|
if(arr[0] case .Double(let lhs) && arr[1] case .Double(let rhs))
|
||||||
|
pContext.Push(.Double(lhs - rhs));
|
||||||
|
|
||||||
|
for(var i in arr)
|
||||||
|
i.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Mult(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
Span<AuValue> arr = pContext.PopN(2);
|
||||||
|
if(arr[0] case .Double(let lhs) && arr[1] case .Double(let rhs))
|
||||||
|
pContext.Push(.Double(lhs * rhs));
|
||||||
|
|
||||||
|
for(var i in arr)
|
||||||
|
i.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Div(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
Span<AuValue> arr = pContext.PopN(2);
|
||||||
|
if(arr[0] case .Double(let lhs) && arr[1] case .Double(let rhs))
|
||||||
|
pContext.Push(.Double(lhs / rhs));
|
||||||
|
|
||||||
|
for(var i in arr)
|
||||||
|
i.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Sqr(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
var arr = pContext.Pop!();
|
||||||
|
if(arr case .Double(let lhs))
|
||||||
|
pContext.Push(.Double(lhs * lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Sqrt(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
var arr = pContext.Pop!();
|
||||||
|
if(arr case .Double(let lhs))
|
||||||
|
pContext.Push(.Double(System.Math.Sqrt(lhs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Pow(AuInstructions pSet, AuBytecode pCContext, AuContext pContext)
|
||||||
|
{
|
||||||
|
Span<AuValue> arr = pContext.PopN(2);
|
||||||
|
|
||||||
|
if(arr[0] case .Double(let lhs) && arr[1] case .Double(let rhs))
|
||||||
|
pContext.Push(.Double(System.Math.Pow(lhs, rhs)));
|
||||||
|
|
||||||
|
for(var i in arr)
|
||||||
|
i.Dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,24 @@
|
||||||
namespace Automate;
|
namespace Automate;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
|
public static void Main(String[] args)
|
||||||
|
{
|
||||||
|
String text = new .("");
|
||||||
|
defer delete text;
|
||||||
|
File.ReadAllText("example.au", text);
|
||||||
|
AuInstructions set = new .(.All);
|
||||||
|
defer delete set;
|
||||||
|
var code = AuCompiler.Compile(text, set, .. new .());
|
||||||
|
defer delete code;
|
||||||
|
AuContext context = new .();
|
||||||
|
defer delete context;
|
||||||
|
context.Run(set, code);
|
||||||
|
//Console.Read();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue