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]
|
||||
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;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
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
Reference in a new issue