real initial commit
This commit is contained in:
parent
c1e4dbcf02
commit
b3363d3f5d
52 changed files with 2073 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
*.dll
|
||||
command_examples.txt
|
||||
screen.txt
|
||||
.vscode/
|
||||
bin/
|
||||
obj/
|
||||
Resources/
|
16
Engine.csproj
Normal file
16
Engine.csproj
Normal file
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Sayers.SDL2.Core" Version="1.0.11" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
4
Engine.csproj.user
Normal file
4
Engine.csproj.user
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup />
|
||||
</Project>
|
25
Engine.sln
Normal file
25
Engine.sln
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Engine", "Engine.csproj", "{C33BE1C6-5FB0-44EC-935F-9E307963A8DF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C33BE1C6-5FB0-44EC-935F-9E307963A8DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C33BE1C6-5FB0-44EC-935F-9E307963A8DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C33BE1C6-5FB0-44EC-935F-9E307963A8DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C33BE1C6-5FB0-44EC-935F-9E307963A8DF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FA1AF6AE-3E75-40AC-8795-FD3959110D5B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
51
Game.cs
Normal file
51
Game.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using KumiScript.Renderer;
|
||||
using SDL2;
|
||||
|
||||
public class EngineWindow
|
||||
{
|
||||
internal ushort width {get; private set;}
|
||||
internal ushort height {get; private set;}
|
||||
internal string title {get; private set;}
|
||||
public EngineWindow(ushort horizontalResolution, ushort verticalResolution, string windowTitle)
|
||||
{
|
||||
width = horizontalResolution;
|
||||
height = verticalResolution;
|
||||
title = windowTitle;
|
||||
|
||||
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO) < 0)
|
||||
throw new Exception("SDL2 Video init failed!");
|
||||
|
||||
if (SDL_image.IMG_Init(SDL_image.IMG_InitFlags.IMG_INIT_PNG) < 0)
|
||||
throw new Exception("SDL2 Image init failed!");
|
||||
}
|
||||
|
||||
public void show()
|
||||
{
|
||||
SDLWindow window = new SDLWindow(width, height, title);
|
||||
SDLRenderer renderer = new SDLRenderer(window);
|
||||
bool mainLoop = true;
|
||||
SDL.SDL_Event e;
|
||||
|
||||
Scene s = new Scene(renderer);
|
||||
SceneElement background = new SceneElement(new Background("Resources/Backgrounds/test.png", renderer), 0, 0);
|
||||
SceneElement seiba = new SceneElement(new Sprite("Resources/Sprites/test.png", renderer), 0, 0);
|
||||
s.AddElement(background);
|
||||
s.AddElement(seiba);
|
||||
|
||||
while (mainLoop)
|
||||
{
|
||||
while (SDL.SDL_PollEvent(out e) > 0)
|
||||
{
|
||||
switch (e.type)
|
||||
{
|
||||
case SDL.SDL_EventType.SDL_QUIT:
|
||||
mainLoop = false;
|
||||
break;
|
||||
}
|
||||
renderer.Clear();
|
||||
s.DrawScene();
|
||||
renderer.SwapBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
0
LICENSE.txt
Normal file
0
LICENSE.txt
Normal file
14
Program.cs
Normal file
14
Program.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript {
|
||||
|
||||
class KumiScript {
|
||||
static void Main (string[] args) {
|
||||
Console.WriteLine(System.IO.Directory.GetCurrentDirectory());
|
||||
EngineWindow engineWindow = new EngineWindow(800, 600, "KumiScript Unicode");
|
||||
engineWindow.show();
|
||||
/*ReadEvalPrintLoop repl = new ReadEvalPrintLoop(Console.OpenStandardInput(), Console.OpenStandardOutput());
|
||||
repl.Loop();*/
|
||||
}
|
||||
}
|
||||
}
|
83
interpreter/Environment.cs
Normal file
83
interpreter/Environment.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class Environment
|
||||
{
|
||||
readonly Environment? _outer;
|
||||
readonly Dictionary<Symbol, Expression> _bindings;
|
||||
public Environment()
|
||||
{
|
||||
_bindings = new Dictionary<Symbol, Expression>(SymbolComparer.GetInstance());
|
||||
}
|
||||
public Environment(Environment outer)
|
||||
{
|
||||
_bindings = new Dictionary<Symbol, Expression>(SymbolComparer.GetInstance());
|
||||
_outer = outer;
|
||||
}
|
||||
|
||||
public Expression Lookup(Symbol symbol)
|
||||
{
|
||||
Expression? result;
|
||||
_bindings.TryGetValue(symbol, out result);
|
||||
|
||||
if (result is not null)
|
||||
return result;
|
||||
|
||||
if (_outer is null)
|
||||
throw new InterpreterUnboundSymbolException();
|
||||
|
||||
return _outer.Lookup(symbol);
|
||||
}
|
||||
|
||||
public void AddSymbol(Symbol symbol, Expression value)
|
||||
{
|
||||
_bindings.Add(symbol, value);
|
||||
return;
|
||||
}
|
||||
|
||||
public void RedefineSymbol(Symbol symbol, Expression value)
|
||||
{
|
||||
if (_bindings.ContainsKey(symbol))
|
||||
{
|
||||
_bindings.Remove(symbol);
|
||||
_bindings.Add(symbol, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_outer is null)
|
||||
throw new InterpreterUnboundSymbolException(symbol.ToString());
|
||||
|
||||
_outer.RedefineSymbol(symbol, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal class SymbolComparer : IEqualityComparer<Symbol>
|
||||
{
|
||||
private static SymbolComparer? _instance;
|
||||
private SymbolComparer()
|
||||
{
|
||||
}
|
||||
|
||||
public static SymbolComparer GetInstance()
|
||||
{
|
||||
if (_instance is null)
|
||||
_instance = new SymbolComparer();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public bool Equals(Symbol? x, Symbol? y)
|
||||
{
|
||||
if (x is not Symbol || y is not Symbol)
|
||||
return false;
|
||||
|
||||
return x.Equals(y);
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] Symbol obj)
|
||||
{
|
||||
return obj.ToString().GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
101
interpreter/InterpreterException.cs
Normal file
101
interpreter/InterpreterException.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
[Serializable]
|
||||
internal class InterpreterInvalidApplicationException : Exception //trying to invoke procedure with wrong args
|
||||
{
|
||||
public InterpreterInvalidApplicationException()
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterInvalidApplicationException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterInvalidApplicationException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected InterpreterInvalidApplicationException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class InterpreterInvalidInvocationException : Exception //trying to invoke non-procedure as procedure
|
||||
{
|
||||
public InterpreterInvalidInvocationException()
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterInvalidInvocationException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterInvalidInvocationException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected InterpreterInvalidInvocationException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class InterpreterUnboundSymbolException : Exception //try to lookup unbound symbol
|
||||
{
|
||||
public InterpreterUnboundSymbolException()
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterUnboundSymbolException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterUnboundSymbolException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected InterpreterUnboundSymbolException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class InterpreterInvalidDefinitionException : Exception //broken definition of procedure
|
||||
{
|
||||
public InterpreterInvalidDefinitionException()
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterInvalidDefinitionException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterInvalidDefinitionException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected InterpreterInvalidDefinitionException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class InterpreterTypingException : Exception //wrong type of arg
|
||||
{
|
||||
public InterpreterTypingException()
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterTypingException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InterpreterTypingException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected InterpreterTypingException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
267
interpreter/LispPrimitives.cs
Normal file
267
interpreter/LispPrimitives.cs
Normal file
|
@ -0,0 +1,267 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class LispPrimitives
|
||||
{
|
||||
public static Expression Lambda(ListExpression args, Environment env)
|
||||
{
|
||||
Expression car = args.Car();
|
||||
ListExpression rest = args.Cdr();
|
||||
|
||||
ListExpression? head = car as ListExpression;
|
||||
if (head is null)
|
||||
throw new InterpreterInvalidDefinitionException();
|
||||
|
||||
List<Expression> headl = head.GetMembers();
|
||||
List<Symbol> arg_names = new List<Symbol>();
|
||||
for (int i = 0; i < headl.Count; i++)
|
||||
{
|
||||
SymbolExpression? argi = headl[i] as SymbolExpression;
|
||||
if (argi is null)
|
||||
throw new InterpreterInvalidDefinitionException();
|
||||
|
||||
arg_names.Add(argi.GetSymbol());
|
||||
}
|
||||
|
||||
Expression body = rest.Car();
|
||||
return new ProcedureExpression(new LispProcedure(arg_names, body, env));
|
||||
}
|
||||
|
||||
public static NumberExpression Plus(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
decimal acc = 0;
|
||||
for (int i = 0; i < argl.Count; i++)
|
||||
{
|
||||
NumberExpression? argin = argl[i] as NumberExpression;
|
||||
if (argin is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
acc += argin.GetValueAsFloat();
|
||||
}
|
||||
|
||||
return NumberFactory.NormalizeFloat(acc);
|
||||
}
|
||||
|
||||
public static NumberExpression Minus(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count == 0)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
NumberExpression? argn0 = argl[0] as NumberExpression;
|
||||
if (argn0 is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
decimal acc = argn0.GetValueAsFloat();
|
||||
if (argl.Count == 1)
|
||||
return NumberFactory.NormalizeFloat(1 - acc);
|
||||
|
||||
for (int i = 1; i < argl.Count; i++)
|
||||
{
|
||||
NumberExpression? argin = argl[i] as NumberExpression;
|
||||
if (argin is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
acc -= argin.GetValueAsFloat();
|
||||
}
|
||||
return NumberFactory.NormalizeFloat(acc);
|
||||
}
|
||||
|
||||
public static NumberExpression Times(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count < 2)
|
||||
throw new InterpreterInvalidInvocationException();
|
||||
|
||||
NumberExpression? arg0 = argl[0] as NumberExpression;
|
||||
if (arg0 is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
decimal f = arg0.GetValueAsFloat();
|
||||
for (int i = 1; i < argl.Count; i++)
|
||||
{
|
||||
NumberExpression? argn = argl[i] as NumberExpression;
|
||||
if (argn is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
f *= argn.GetValueAsFloat();
|
||||
}
|
||||
return NumberFactory.NormalizeFloat(f);
|
||||
}
|
||||
|
||||
public static NumberExpression DividedBy(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count != 2)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
NumberExpression? arg0 = argl[0] as NumberExpression;
|
||||
if (arg0 is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
NumberExpression? arg1 = argl[1] as NumberExpression;
|
||||
if (arg1 is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
return NumberFactory.NormalizeFloat(arg0.GetValueAsFloat() / arg1.GetValueAsFloat());
|
||||
}
|
||||
|
||||
public static NumberExpression Modulus(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count != 2)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
NumberExpression? arg0 = argl[0] as NumberExpression;
|
||||
if (arg0 is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
NumberExpression? arg1 = argl[1] as NumberExpression;
|
||||
if (arg1 is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
return NumberFactory.NormalizeFloat(arg0.GetValueAsFloat() % arg1.GetValueAsFloat());
|
||||
}
|
||||
|
||||
|
||||
public static Expression Quote(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.GetMembers();
|
||||
if (argl.Count != 1)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
return argl[0];
|
||||
}
|
||||
|
||||
public static Expression Define(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.GetMembers();
|
||||
if (argl.Count != 2)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
SymbolExpression? binding = argl[0] as SymbolExpression;
|
||||
if (binding is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
Symbol name = binding.GetSymbol();
|
||||
Expression definition = argl[1].Eval(env);
|
||||
env.AddSymbol(name, definition);
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
public static Expression Car(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count != 1)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
ListExpression? list = argl[0] as ListExpression;
|
||||
if (list is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
return list.Car();
|
||||
}
|
||||
|
||||
public static ListExpression Cdr(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count != 1)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
ListExpression? list = argl[0] as ListExpression;
|
||||
if (list is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
return list.Cdr();
|
||||
}
|
||||
|
||||
public static ProperListExpression Cons(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count != 2)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
Expression car = argl[0];
|
||||
ListExpression? cdr = argl[1] as ListExpression;
|
||||
if (cdr is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
return cdr.Cons(car);
|
||||
}
|
||||
|
||||
public static Expression Quit(ListExpression args, Environment env)
|
||||
{
|
||||
System.Environment.Exit(0);
|
||||
return new SymbolExpression(new Symbol("bye"));
|
||||
}
|
||||
|
||||
public static Expression Cond(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.GetMembers();
|
||||
for (int i = 0; i < argl.Count; i ++)
|
||||
{
|
||||
ProperListExpression? conditional = argl[i] as ProperListExpression;
|
||||
if (conditional is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
Expression antecedent = conditional.Car();
|
||||
Expression consequent = conditional.Cdr().Car();
|
||||
if (!(antecedent.Eval(env) is NilExpression))
|
||||
return consequent.Eval(env);
|
||||
}
|
||||
return NilExpression.GetInstance();
|
||||
}
|
||||
|
||||
public static Expression Eq(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.EvalMembers(env);
|
||||
if (argl.Count != 2)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
if (argl[0].Equals(argl[1]))
|
||||
return TrueExpression.GetInstance();
|
||||
|
||||
return NilExpression.GetInstance();
|
||||
}
|
||||
|
||||
public static Expression Set(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> argl = args.GetMembers();
|
||||
if (argl.Count != 2)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
SymbolExpression? binding = argl[0] as SymbolExpression;
|
||||
if (binding is null)
|
||||
throw new InterpreterTypingException();
|
||||
|
||||
Symbol name = binding.GetSymbol();
|
||||
Expression definition = argl[1].Eval(env);
|
||||
env.RedefineSymbol(name, definition);
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
public static Environment RegisterPrimitives()
|
||||
{
|
||||
Environment result = new Environment();
|
||||
result.AddSymbol(new Symbol("lambda"), new ProcedureExpression(new PrimitiveProcedure(Lambda)));
|
||||
result.AddSymbol(new Symbol("quote"), new ProcedureExpression(new PrimitiveProcedure(Quote)));
|
||||
result.AddSymbol(new Symbol("define"), new ProcedureExpression(new PrimitiveProcedure(Define)));
|
||||
result.AddSymbol(new Symbol("car"), new ProcedureExpression(new PrimitiveProcedure(Car)));
|
||||
result.AddSymbol(new Symbol("cdr"), new ProcedureExpression(new PrimitiveProcedure(Cdr)));
|
||||
result.AddSymbol(new Symbol("cons"), new ProcedureExpression(new PrimitiveProcedure(Cons)));
|
||||
result.AddSymbol(new Symbol("quit"), new ProcedureExpression(new PrimitiveProcedure(Quit)));
|
||||
result.AddSymbol(new Symbol("cond"), new ProcedureExpression(new PrimitiveProcedure(Cond)));
|
||||
result.AddSymbol(new Symbol("+"), new ProcedureExpression(new PrimitiveProcedure(Plus)));
|
||||
result.AddSymbol(new Symbol("-"), new ProcedureExpression(new PrimitiveProcedure(Minus)));
|
||||
result.AddSymbol(new Symbol("*"), new ProcedureExpression(new PrimitiveProcedure(Times)));
|
||||
result.AddSymbol(new Symbol("/"), new ProcedureExpression(new PrimitiveProcedure(DividedBy)));
|
||||
result.AddSymbol(new Symbol("%"), new ProcedureExpression(new PrimitiveProcedure(Modulus)));
|
||||
result.AddSymbol(new Symbol("eq"), new ProcedureExpression(new PrimitiveProcedure(Eq)));
|
||||
result.AddSymbol(new Symbol("set!"), new ProcedureExpression(new PrimitiveProcedure(Set)));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
46
interpreter/LispProcedure.cs
Normal file
46
interpreter/LispProcedure.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using System.DirectoryServices;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class LispProcedure : Procedure
|
||||
{
|
||||
readonly List<Symbol> _parameters;
|
||||
readonly Expression _body;
|
||||
readonly Environment _closureEnv;
|
||||
public LispProcedure(List<Symbol> parameters, Expression body, Environment closureEnv)
|
||||
{
|
||||
_parameters = parameters;
|
||||
_body = body;
|
||||
_closureEnv = closureEnv;
|
||||
}
|
||||
|
||||
public override Expression ApplyWithArgs(ListExpression args, Environment env)
|
||||
{
|
||||
List<Expression> evaluatedArgs = args.EvalMembers(env);
|
||||
if (_parameters.Count != evaluatedArgs.Count)
|
||||
throw new InterpreterInvalidApplicationException();
|
||||
|
||||
Environment inner = MapArgs(evaluatedArgs, _closureEnv);
|
||||
return _body.Eval(inner);
|
||||
}
|
||||
|
||||
private Environment MapArgs(List<Expression> args, Environment env)
|
||||
{
|
||||
Environment inner = new Environment(env);
|
||||
for (int i = 0; i < _parameters.Count; i++)
|
||||
inner.AddSymbol(_parameters[i], args[i]);
|
||||
|
||||
return inner;
|
||||
}
|
||||
|
||||
public override bool IsPrimitive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Concat("λ(", string.Join(' ', _parameters), ")");
|
||||
}
|
||||
}
|
||||
}
|
27
interpreter/PrimitiveProcedure.cs
Normal file
27
interpreter/PrimitiveProcedure.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class PrimitiveProcedure : Procedure
|
||||
{
|
||||
public delegate Expression PrimitiveDelegate(ListExpression args, Environment env);
|
||||
readonly PrimitiveDelegate _function;
|
||||
public PrimitiveProcedure(PrimitiveDelegate function)
|
||||
{
|
||||
_function = function;
|
||||
}
|
||||
|
||||
public override Expression ApplyWithArgs(ListExpression args, Environment env)
|
||||
{
|
||||
return _function(args, env);
|
||||
}
|
||||
|
||||
public override bool IsPrimitive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _function.ToString();
|
||||
}
|
||||
}
|
||||
}
|
12
interpreter/Procedure.cs
Normal file
12
interpreter/Procedure.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public abstract class Procedure
|
||||
{
|
||||
public Procedure()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract Expression ApplyWithArgs(ListExpression args, Environment env);
|
||||
public abstract bool IsPrimitive();
|
||||
}
|
||||
}
|
46
interpreter/ReadEvalPrintLoop.cs
Normal file
46
interpreter/ReadEvalPrintLoop.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using KumiScript.Reader;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class ReadEvalPrintLoop
|
||||
{
|
||||
Stream _stdin;
|
||||
Stream _stdout;
|
||||
public ReadEvalPrintLoop(Stream stdin, Stream stdout)
|
||||
{
|
||||
_stdin = stdin;
|
||||
_stdout = stdout;
|
||||
}
|
||||
|
||||
public void Loop()
|
||||
{
|
||||
Lexer lexer = new Lexer(_stdin);
|
||||
Parser parser = new Parser(lexer);
|
||||
StreamWriter streamWriter = new StreamWriter(_stdout);
|
||||
Environment top = LispPrimitives.RegisterPrimitives();
|
||||
|
||||
while (true) //this thing is ugly but it's just a little test
|
||||
{
|
||||
Expression expr = parser.NextTopLevelExpression();
|
||||
try
|
||||
{
|
||||
Expression result = expr.Eval(top);
|
||||
streamWriter.Write(string.Format("{0}\n", result.ToString()));
|
||||
streamWriter.Flush();
|
||||
} catch (Exception ex) {
|
||||
if (ex is InterpreterInvalidApplicationException
|
||||
or InterpreterInvalidDefinitionException
|
||||
or InterpreterInvalidInvocationException
|
||||
or InterpreterTypingException
|
||||
or InterpreterUnboundSymbolException)
|
||||
{
|
||||
streamWriter.WriteLine(ex);
|
||||
streamWriter.Flush();
|
||||
continue;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
interpreter/Symbol.cs
Normal file
21
interpreter/Symbol.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class Symbol
|
||||
{
|
||||
readonly string _name;
|
||||
public Symbol(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public bool Equals(Symbol s)
|
||||
{
|
||||
return s.ToString() == _name;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
}
|
12
interpreter/expression/Expression.cs
Normal file
12
interpreter/expression/Expression.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public abstract class Expression
|
||||
{
|
||||
public Expression()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract Expression Eval(Environment env);
|
||||
public abstract bool Equals(Expression expr);
|
||||
}
|
||||
}
|
41
interpreter/expression/FloatExpression.cs
Normal file
41
interpreter/expression/FloatExpression.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class FloatExpression : NumberExpression
|
||||
{
|
||||
readonly decimal _value;
|
||||
public FloatExpression(decimal f)
|
||||
{
|
||||
_value = f;
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
NumberExpression? nexpr = expr as NumberExpression;
|
||||
if (nexpr is null)
|
||||
return false;
|
||||
|
||||
return nexpr.GetValueAsFloat() == _value;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
public override decimal GetValueAsFloat()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public override int GetValueAsInt()
|
||||
{
|
||||
return (int) _value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
42
interpreter/expression/IntegerExpression.cs
Normal file
42
interpreter/expression/IntegerExpression.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class IntegerExpression : NumberExpression
|
||||
{
|
||||
readonly int _value;
|
||||
public IntegerExpression(int n)
|
||||
{
|
||||
_value = n;
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
NumberExpression? nexpr = expr as NumberExpression;
|
||||
if (nexpr is null)
|
||||
return false;
|
||||
|
||||
return nexpr.GetValueAsFloat() == _value;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override decimal GetValueAsFloat()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public override int GetValueAsInt()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
15
interpreter/expression/ListExpression.cs
Normal file
15
interpreter/expression/ListExpression.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public abstract class ListExpression : Expression
|
||||
{
|
||||
public ListExpression()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract Expression Car();
|
||||
public abstract ListExpression Cdr();
|
||||
public abstract ProperListExpression Cons(Expression expr);
|
||||
public abstract List<Expression> EvalMembers(Environment env);
|
||||
public abstract List<Expression> GetMembers();
|
||||
}
|
||||
}
|
13
interpreter/expression/ListFactory.cs
Normal file
13
interpreter/expression/ListFactory.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class ListFactory
|
||||
{
|
||||
public static ListExpression MakeList(List<Expression> expressions)
|
||||
{
|
||||
if (expressions.Any())
|
||||
return new ProperListExpression(expressions);
|
||||
|
||||
return NilExpression.GetInstance();
|
||||
}
|
||||
}
|
||||
}
|
58
interpreter/expression/NilExpression.cs
Normal file
58
interpreter/expression/NilExpression.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class NilExpression : ListExpression
|
||||
{
|
||||
private static NilExpression? _instance;
|
||||
private NilExpression()
|
||||
{
|
||||
}
|
||||
|
||||
public static NilExpression GetInstance()
|
||||
{
|
||||
if (_instance is null)
|
||||
_instance = new NilExpression();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public override Expression Car()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override ListExpression Cdr()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override ProperListExpression Cons(Expression expr)
|
||||
{
|
||||
return new ProperListExpression(new List<Expression> {expr});
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
return expr is NilExpression;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override List<Expression> EvalMembers(Environment env)
|
||||
{
|
||||
return new List<Expression>();
|
||||
}
|
||||
|
||||
public override List<Expression> GetMembers()
|
||||
{
|
||||
return new List<Expression>();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
}
|
||||
}
|
12
interpreter/expression/NumberExpression.cs
Normal file
12
interpreter/expression/NumberExpression.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public abstract class NumberExpression : Expression
|
||||
{
|
||||
public NumberExpression()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract decimal GetValueAsFloat();
|
||||
public abstract int GetValueAsInt();
|
||||
}
|
||||
}
|
15
interpreter/expression/NumberFactory.cs
Normal file
15
interpreter/expression/NumberFactory.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class NumberFactory
|
||||
{
|
||||
public static NumberExpression NormalizeFloat(decimal f)
|
||||
{
|
||||
//TODO: Handle overflows
|
||||
int i = (int) f;
|
||||
if (i == f)
|
||||
return new IntegerExpression(i);
|
||||
|
||||
return new FloatExpression(f);
|
||||
}
|
||||
}
|
||||
}
|
51
interpreter/expression/ProcedureExpression.cs
Normal file
51
interpreter/expression/ProcedureExpression.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class ProcedureExpression : Expression
|
||||
{
|
||||
readonly Procedure _proc;
|
||||
readonly bool _branching;
|
||||
public ProcedureExpression(Procedure p)
|
||||
{
|
||||
_proc = p;
|
||||
_branching = false;
|
||||
}
|
||||
|
||||
public ProcedureExpression(Procedure p, bool branching)
|
||||
{
|
||||
_proc = p;
|
||||
_branching = branching;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public Expression Apply(ListExpression args, Environment env)
|
||||
{
|
||||
return _proc.ApplyWithArgs(args, env);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (_proc.IsPrimitive())
|
||||
return string.Format("#Primitive<{0}>", _proc.ToString());
|
||||
|
||||
return string.Format("#Procedure<{0}>", _proc.ToString());
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
ProcedureExpression? pe = expr as ProcedureExpression;
|
||||
if (pe is null)
|
||||
return false;
|
||||
|
||||
return _proc.Equals(pe._proc);
|
||||
}
|
||||
|
||||
public Procedure GetProcedure()
|
||||
{
|
||||
return _proc;
|
||||
}
|
||||
}
|
||||
}
|
76
interpreter/expression/ProperListExpression.cs
Normal file
76
interpreter/expression/ProperListExpression.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class ProperListExpression : ListExpression
|
||||
{
|
||||
readonly List<Expression> _values;
|
||||
public ProperListExpression(List<Expression> expressions)
|
||||
{
|
||||
_values = expressions;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
ProcedureExpression? rator = Car().Eval(env) as ProcedureExpression;
|
||||
if (rator is null)
|
||||
throw new InterpreterInvalidInvocationException();
|
||||
|
||||
ListExpression rand = Cdr();
|
||||
return rator.Apply(rand, env);
|
||||
}
|
||||
|
||||
public override List<Expression> EvalMembers(Environment env)
|
||||
{
|
||||
List<Expression> result = new List<Expression>();
|
||||
for (int i = 0; i < _values.Count; i++)
|
||||
result.Add(_values[i].Eval(env));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override List<Expression> GetMembers()
|
||||
{
|
||||
return _values;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Concat("(",
|
||||
String.Join(' ', (object[]) _values.ToArray()),
|
||||
")");
|
||||
}
|
||||
|
||||
public override Expression Car()
|
||||
{
|
||||
if (_values.Count == 0)
|
||||
return this;
|
||||
|
||||
return _values.First();
|
||||
}
|
||||
|
||||
public override ListExpression Cdr()
|
||||
{
|
||||
if (_values.Count == 0)
|
||||
return this;
|
||||
|
||||
List<Expression> rest = new List<Expression>(_values);
|
||||
rest.RemoveAt(0);
|
||||
return ListFactory.MakeList(rest);
|
||||
}
|
||||
|
||||
public override ProperListExpression Cons(Expression expr)
|
||||
{
|
||||
List<Expression> consd = new List<Expression>(_values);
|
||||
consd.Insert(0, expr);
|
||||
return new ProperListExpression(consd);
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
ProperListExpression? lexpr = expr as ProperListExpression;
|
||||
if (lexpr is null)
|
||||
return false;
|
||||
|
||||
return lexpr.GetMembers().SequenceEqual(_values);
|
||||
}
|
||||
}
|
||||
}
|
30
interpreter/expression/StringExpression.cs
Normal file
30
interpreter/expression/StringExpression.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class StringExpression : Expression
|
||||
{
|
||||
string _value;
|
||||
public StringExpression(string str)
|
||||
{
|
||||
_value = str;
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
StringExpression? se = expr as StringExpression;
|
||||
if (se is null)
|
||||
return false;
|
||||
|
||||
return _value == se._value;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
}
|
35
interpreter/expression/SymbolExpression.cs
Normal file
35
interpreter/expression/SymbolExpression.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class SymbolExpression : Expression
|
||||
{
|
||||
readonly Symbol _value;
|
||||
public SymbolExpression(Symbol s)
|
||||
{
|
||||
_value = s;
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
SymbolExpression? sy = expr as SymbolExpression;
|
||||
if (sy is null)
|
||||
return false;
|
||||
|
||||
return _value.Equals(sy._value);
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return env.Lookup(_value);
|
||||
}
|
||||
|
||||
public Symbol GetSymbol()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
33
interpreter/expression/TrueExpression.cs
Normal file
33
interpreter/expression/TrueExpression.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class TrueExpression : Expression
|
||||
{
|
||||
private static TrueExpression? _instance;
|
||||
private TrueExpression()
|
||||
{
|
||||
}
|
||||
|
||||
public static TrueExpression GetInstance()
|
||||
{
|
||||
if (_instance is null)
|
||||
_instance = new TrueExpression();
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public override bool Equals(Expression expr)
|
||||
{
|
||||
return expr is TrueExpression;
|
||||
}
|
||||
|
||||
public override Expression Eval(Environment env)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "t";
|
||||
}
|
||||
}
|
||||
}
|
43
loader/KSMetaParser.cs
Normal file
43
loader/KSMetaParser.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace KumiScript.Loader
|
||||
{
|
||||
public class KSMetaParser
|
||||
{
|
||||
readonly string _path;
|
||||
readonly StreamReader _streamReader;
|
||||
readonly Dictionary<string, int> _properties;
|
||||
public KSMetaParser(string path)
|
||||
{
|
||||
_path = path;
|
||||
_streamReader = new StreamReader(File.OpenRead(path));
|
||||
_properties = new Dictionary<string, int>(8);
|
||||
ParseFile();
|
||||
}
|
||||
|
||||
private void ParseFile()
|
||||
{
|
||||
while (!_streamReader.EndOfStream)
|
||||
{
|
||||
string? line = _streamReader.ReadLine();
|
||||
if (line is null)
|
||||
continue;
|
||||
|
||||
line = Regex.Replace(line, "\\s+", string.Empty);
|
||||
string[] kvp = line.Split(":", 2);
|
||||
int v;
|
||||
if (!int.TryParse(kvp[1], out v))
|
||||
throw new Exception("Bad file!");
|
||||
|
||||
_properties.Add(kvp[0], v);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetAttribute(string name)
|
||||
{
|
||||
int v = 0;
|
||||
_properties.TryGetValue(name, out v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
38
parser/AtomToken.cs
Normal file
38
parser/AtomToken.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class AtomToken : Token
|
||||
{
|
||||
readonly string _value;
|
||||
public AtomToken(string value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public override Expression Accept(ITokenVisitor tokenVisitor)
|
||||
{
|
||||
return tokenVisitor.VisitAtom(this);
|
||||
}
|
||||
|
||||
public virtual Expression ToExpression()
|
||||
{
|
||||
decimal f;
|
||||
if (decimal.TryParse(_value, out f))
|
||||
return NumberFactory.NormalizeFloat(f);
|
||||
|
||||
if (_value == "null")
|
||||
return NilExpression.GetInstance();
|
||||
|
||||
if (_value == "t")
|
||||
return TrueExpression.GetInstance();
|
||||
|
||||
return new SymbolExpression(new Symbol(_value));
|
||||
}
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
}
|
21
parser/EndOfFileToken.cs
Normal file
21
parser/EndOfFileToken.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using KumiScript.Reader;
|
||||
|
||||
namespace KumiScript.Interpreter
|
||||
{
|
||||
public class EndOfFileToken : Token
|
||||
{
|
||||
public EndOfFileToken()
|
||||
{
|
||||
}
|
||||
|
||||
public override Expression Accept(ITokenVisitor tokenVisitor)
|
||||
{
|
||||
return tokenVisitor.VisitEoF(this);
|
||||
}
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
return "EOF";
|
||||
}
|
||||
}
|
||||
}
|
151
parser/Lexer.cs
Normal file
151
parser/Lexer.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class Lexer
|
||||
{
|
||||
Stack<Token> _tokenStack;
|
||||
readonly StreamReader _streamReader;
|
||||
|
||||
public Lexer(Stream stream)
|
||||
{
|
||||
_tokenStack = new Stack<Token>(16);
|
||||
_streamReader = new StreamReader(stream);
|
||||
}
|
||||
|
||||
public Token NextToken()
|
||||
{
|
||||
if (_tokenStack.IsEmpty())
|
||||
return LexFromStream();
|
||||
|
||||
return _tokenStack.Pop();
|
||||
}
|
||||
|
||||
public Token PeekToken()
|
||||
{
|
||||
Token t = NextToken();
|
||||
PushToken(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public void PushToken(Token token)
|
||||
{
|
||||
_tokenStack.Push(token);
|
||||
return;
|
||||
}
|
||||
|
||||
private Token LexFromStream()
|
||||
{
|
||||
int c = GetChar();
|
||||
|
||||
while (char.IsWhiteSpace((char) c))
|
||||
c = GetChar();
|
||||
|
||||
if (c == ';')
|
||||
{
|
||||
while ((c = GetChar()) != '\n');
|
||||
c = GetChar();
|
||||
}
|
||||
|
||||
if (c == -1)
|
||||
return new EndOfFileToken();
|
||||
if (c == '(')
|
||||
return new ParenthesisToken(true);
|
||||
if (c == ')')
|
||||
return new ParenthesisToken(false);
|
||||
if (c == '"')
|
||||
return LexString();
|
||||
if (isspec(c))
|
||||
return new SpecialToken((char) c);
|
||||
|
||||
return LexGeneric(c);
|
||||
}
|
||||
|
||||
private Token LexString()
|
||||
{
|
||||
List<char> chars = new List<char>();
|
||||
int c = GetChar();
|
||||
|
||||
while (c != '"')
|
||||
{
|
||||
if (c == '\\')
|
||||
c = GetChar();
|
||||
|
||||
chars.Add((char) c);
|
||||
c = GetChar();
|
||||
if (c == -1)
|
||||
throw new Exception("Unexpected EOF!");
|
||||
}
|
||||
|
||||
return new StringToken(new string(chars.ToArray()));
|
||||
}
|
||||
|
||||
private Token LexGeneric(int c)
|
||||
{
|
||||
List<char> chars = new List<char>();
|
||||
chars.Add((char) c); //NOTE: The language server is WRONG! List<char>((char) c) BREAKS! **** you m$
|
||||
|
||||
int p = PeekChar();
|
||||
while (!char.IsWhiteSpace((char) p) && !isspecparen(p) && p != -1)
|
||||
{
|
||||
c = GetChar();
|
||||
chars.Add((char) c);
|
||||
p = PeekChar();
|
||||
}
|
||||
|
||||
return new AtomToken(new string(chars.ToArray()));
|
||||
}
|
||||
|
||||
private static bool isspec(int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '#':
|
||||
return true;
|
||||
case '\'':
|
||||
return true;
|
||||
case '\\':
|
||||
return true;
|
||||
case '`':
|
||||
return true;
|
||||
case ',':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool isspecparen(int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '(':
|
||||
return true;
|
||||
case ')':
|
||||
return true;
|
||||
case '#':
|
||||
return true;
|
||||
case '\'':
|
||||
return true;
|
||||
case '\\':
|
||||
return true;
|
||||
case '`':
|
||||
return true;
|
||||
case ',':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int GetChar()
|
||||
{
|
||||
return _streamReader.Read();
|
||||
}
|
||||
|
||||
private int PeekChar()
|
||||
{
|
||||
return _streamReader.Peek();
|
||||
}
|
||||
}
|
||||
}
|
25
parser/ParenthesisToken.cs
Normal file
25
parser/ParenthesisToken.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class ParenthesisToken : Token
|
||||
{
|
||||
public readonly bool _leftParen;
|
||||
public ParenthesisToken(bool lp)
|
||||
{
|
||||
_leftParen = lp;
|
||||
}
|
||||
|
||||
public override Expression Accept(ITokenVisitor tokenVisitor)
|
||||
{
|
||||
return tokenVisitor.VisitParen(this);
|
||||
}
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
if (_leftParen)
|
||||
return "(";
|
||||
return ")";
|
||||
}
|
||||
}
|
||||
}
|
25
parser/Parser.cs
Normal file
25
parser/Parser.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class Parser
|
||||
{
|
||||
Lexer _lexer;
|
||||
public Parser(Lexer lexer)
|
||||
{
|
||||
_lexer = lexer;
|
||||
}
|
||||
|
||||
public Expression NextTopLevelExpression()
|
||||
{
|
||||
Token t = _lexer.NextToken();
|
||||
return t.Accept(new ParserTopLevelVisitor(this));
|
||||
}
|
||||
|
||||
public Expression NextExpressionCC(ITokenVisitor visitor)
|
||||
{
|
||||
Token t = _lexer.NextToken();
|
||||
return t.Accept(visitor);
|
||||
}
|
||||
}
|
||||
}
|
62
parser/ParserExceptions.cs
Normal file
62
parser/ParserExceptions.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
[Serializable]
|
||||
internal class ParserEndOfFileException : Exception
|
||||
{
|
||||
public ParserEndOfFileException()
|
||||
{
|
||||
}
|
||||
|
||||
public ParserEndOfFileException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ParserEndOfFileException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected ParserEndOfFileException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class ParserUnexpectedTokenException : Exception
|
||||
{
|
||||
public ParserUnexpectedTokenException()
|
||||
{
|
||||
}
|
||||
|
||||
public ParserUnexpectedTokenException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ParserUnexpectedTokenException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected ParserUnexpectedTokenException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class ParserUnexpectedEndOfFileException : Exception
|
||||
{
|
||||
public ParserUnexpectedEndOfFileException()
|
||||
{
|
||||
}
|
||||
|
||||
public ParserUnexpectedEndOfFileException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ParserUnexpectedEndOfFileException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected ParserUnexpectedEndOfFileException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
53
parser/ParserListVisitor.cs
Normal file
53
parser/ParserListVisitor.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class ParserListVisitor : ITokenVisitor
|
||||
{
|
||||
Parser _parser;
|
||||
public ParserListVisitor(Parser parser)
|
||||
{
|
||||
_parser = parser;
|
||||
}
|
||||
|
||||
public Expression VisitAtom(AtomToken atom)
|
||||
{
|
||||
return atom.ToExpression();
|
||||
}
|
||||
|
||||
public Expression VisitString(StringToken str)
|
||||
{
|
||||
return str.ToExpression();
|
||||
}
|
||||
|
||||
public Expression VisitEoF(EndOfFileToken eof)
|
||||
{
|
||||
throw new ParserUnexpectedEndOfFileException("Expected ')' before end of file.");
|
||||
}
|
||||
|
||||
public Expression VisitParen(ParenthesisToken paren)
|
||||
{
|
||||
if (!paren._leftParen)
|
||||
return null; //TODO: some other way of throwing it back
|
||||
|
||||
List<Expression> list = new List<Expression>();
|
||||
Expression item = _parser.NextExpressionCC(this);
|
||||
|
||||
while (item is not null)
|
||||
{
|
||||
list.Add(item);
|
||||
item = _parser.NextExpressionCC(this);
|
||||
}
|
||||
|
||||
return ListFactory.MakeList(list);
|
||||
}
|
||||
|
||||
public Expression VisitSpecial(SpecialToken spec)
|
||||
{
|
||||
if (spec._value == '\'')
|
||||
return _parser.NextExpressionCC(new ParserQuoteVisitor(_parser));
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
65
parser/ParserQuoteVisitor.cs
Normal file
65
parser/ParserQuoteVisitor.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class ParserQuoteVisitor : ITokenVisitor
|
||||
{
|
||||
Parser _parser;
|
||||
public ParserQuoteVisitor(Parser parser)
|
||||
{
|
||||
_parser = parser;
|
||||
}
|
||||
|
||||
public Expression VisitAtom(AtomToken atom)
|
||||
{
|
||||
List<Expression> quotedAtom = new List<Expression>
|
||||
{
|
||||
new SymbolExpression(new Symbol("quote")),
|
||||
atom.ToExpression()
|
||||
};
|
||||
return new ProperListExpression(quotedAtom);
|
||||
}
|
||||
|
||||
public Expression VisitEoF(EndOfFileToken eof)
|
||||
{
|
||||
throw new ParserUnexpectedEndOfFileException("Expected <atom>, <list>, got EOF.");
|
||||
}
|
||||
|
||||
public Expression VisitParen(ParenthesisToken paren)
|
||||
{
|
||||
if (!paren._leftParen)
|
||||
throw new ParserUnexpectedTokenException("Unexpected Token ')'! Wanted <atom>, '('.");
|
||||
|
||||
List<Expression> list = new List<Expression>();
|
||||
ParserListVisitor listVisitor = new ParserListVisitor(_parser);
|
||||
Expression item = _parser.NextExpressionCC(listVisitor);
|
||||
while (item is not null)
|
||||
{
|
||||
list.Add(item);
|
||||
item = _parser.NextExpressionCC(listVisitor);
|
||||
}
|
||||
Expression listExpression = ListFactory.MakeList(list);
|
||||
List<Expression> quotedList = new List<Expression>
|
||||
{
|
||||
new SymbolExpression(new Symbol("quote")),
|
||||
listExpression
|
||||
};
|
||||
return new ProperListExpression(quotedList);
|
||||
}
|
||||
|
||||
public Expression VisitSpecial(SpecialToken spec)
|
||||
{
|
||||
throw new ParserUnexpectedTokenException("Expected <atom>, <list>, got SPECIAL.");
|
||||
}
|
||||
|
||||
public Expression VisitString(StringToken str)
|
||||
{
|
||||
List<Expression> quotedString = new List<Expression>
|
||||
{
|
||||
new SymbolExpression(new Symbol("quote")),
|
||||
str.ToExpression()
|
||||
};
|
||||
return new ProperListExpression(quotedString);
|
||||
}
|
||||
}
|
||||
}
|
54
parser/ParserTopLevelVisitor.cs
Normal file
54
parser/ParserTopLevelVisitor.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class ParserTopLevelVisitor : ITokenVisitor
|
||||
{
|
||||
Parser _parser;
|
||||
public ParserTopLevelVisitor(Parser parser)
|
||||
{
|
||||
_parser = parser;
|
||||
}
|
||||
|
||||
public Expression VisitAtom(AtomToken atom)
|
||||
{
|
||||
return atom.ToExpression();
|
||||
}
|
||||
|
||||
public Expression VisitString(StringToken str)
|
||||
{
|
||||
return str.ToExpression();
|
||||
}
|
||||
|
||||
public Expression VisitEoF(EndOfFileToken eof)
|
||||
{
|
||||
throw new ParserEndOfFileException();
|
||||
}
|
||||
|
||||
public Expression VisitParen(ParenthesisToken paren)
|
||||
{
|
||||
if (!paren._leftParen)
|
||||
throw new ParserUnexpectedTokenException("Unexpected Token ')'! Wanted ATOM, '(', or EOF.");
|
||||
|
||||
List<Expression> list = new List<Expression>();
|
||||
ParserListVisitor listVisitor = new ParserListVisitor(_parser);
|
||||
Expression item = _parser.NextExpressionCC(listVisitor);
|
||||
|
||||
while (item is not null)
|
||||
{
|
||||
list.Add(item);
|
||||
item = _parser.NextExpressionCC(listVisitor);
|
||||
}
|
||||
|
||||
return ListFactory.MakeList(list);
|
||||
}
|
||||
|
||||
public Expression VisitSpecial(SpecialToken spec)
|
||||
{
|
||||
if (spec._value == '\'')
|
||||
return _parser.NextExpressionCC(new ParserQuoteVisitor(_parser));
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
23
parser/SpecialToken.cs
Normal file
23
parser/SpecialToken.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class SpecialToken : Token
|
||||
{
|
||||
public readonly char _value;
|
||||
public SpecialToken(char value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public override Expression Accept(ITokenVisitor tokenVisitor)
|
||||
{
|
||||
return tokenVisitor.VisitSpecial(this);
|
||||
}
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
return _value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
39
parser/Stack.cs
Normal file
39
parser/Stack.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
namespace KumiScript.Reader
|
||||
{
|
||||
|
||||
public class Stack<T>
|
||||
{
|
||||
List<T> _values;
|
||||
|
||||
public Stack(int size)
|
||||
{
|
||||
_values = new List<T>(size);
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (!_values.Any())
|
||||
throw new Exception("Stack empty!");
|
||||
|
||||
T last = _values.Last();
|
||||
_values.Remove(last);
|
||||
return last;
|
||||
}
|
||||
|
||||
public bool Push(T item)
|
||||
{
|
||||
_values.Add(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return !_values.Any();
|
||||
}
|
||||
|
||||
public List<T> ToList()
|
||||
{
|
||||
return _values;
|
||||
}
|
||||
}
|
||||
}
|
23
parser/StringToken.cs
Normal file
23
parser/StringToken.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public class StringToken : AtomToken
|
||||
{
|
||||
readonly string _value;
|
||||
public StringToken(string value) : base (value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public override Expression ToExpression()
|
||||
{
|
||||
return new StringExpression(_value);
|
||||
}
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
}
|
10
parser/Token.cs
Normal file
10
parser/Token.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public abstract class Token
|
||||
{
|
||||
public abstract String GetValue();
|
||||
public abstract Expression Accept(ITokenVisitor tokenVisitor);
|
||||
}
|
||||
}
|
13
parser/TokenVisitor.cs
Normal file
13
parser/TokenVisitor.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using KumiScript.Interpreter;
|
||||
|
||||
namespace KumiScript.Reader
|
||||
{
|
||||
public interface ITokenVisitor
|
||||
{
|
||||
Expression VisitEoF(EndOfFileToken eof);
|
||||
Expression VisitAtom(AtomToken atom);
|
||||
Expression VisitString(StringToken str);
|
||||
Expression VisitParen(ParenthesisToken paren);
|
||||
Expression VisitSpecial(SpecialToken spec);
|
||||
}
|
||||
}
|
44
renderer/Background.cs
Normal file
44
renderer/Background.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using SDL2;
|
||||
|
||||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class Background : IDrawable
|
||||
{
|
||||
SDLRenderer _renderer;
|
||||
Image _image;
|
||||
int _height;
|
||||
int _width;
|
||||
|
||||
public Background(string path, SDLRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_image = new Image(path, renderer);
|
||||
}
|
||||
|
||||
public void Draw(int x, int y)
|
||||
{
|
||||
SDL.SDL_RenderCopy(_renderer.id, _image.GetTexture().id, 0, 0);
|
||||
}
|
||||
|
||||
public int GetBitmapHeight()
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
public int GetBitmapWidth()
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
public int GetXOffset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetYOffset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
11
renderer/IDrawable.cs
Normal file
11
renderer/IDrawable.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace KumiScript.Renderer
|
||||
{
|
||||
public interface IDrawable
|
||||
{
|
||||
void Draw(int x, int y);
|
||||
int GetBitmapWidth();
|
||||
int GetBitmapHeight();
|
||||
int GetXOffset();
|
||||
int GetYOffset();
|
||||
}
|
||||
}
|
21
renderer/Image.cs
Normal file
21
renderer/Image.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using SDL2;
|
||||
|
||||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class Image
|
||||
{
|
||||
SDLRenderer _renderer;
|
||||
SDLTexture _texture;
|
||||
|
||||
public Image(string path, SDLRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_texture = new SDLTexture(path, renderer);
|
||||
}
|
||||
|
||||
public SDLTexture GetTexture()
|
||||
{
|
||||
return _texture;
|
||||
}
|
||||
}
|
||||
}
|
32
renderer/Scene.cs
Normal file
32
renderer/Scene.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class Scene
|
||||
{
|
||||
SDLRenderer _renderer;
|
||||
List<SceneElement> _elements;
|
||||
public Scene(SDLRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_elements = new List<SceneElement>(16);
|
||||
}
|
||||
|
||||
public void DrawScene()
|
||||
{
|
||||
foreach (SceneElement e in _elements)
|
||||
{
|
||||
e.Draw(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddElement(SceneElement e)
|
||||
{
|
||||
_elements.Add(e);
|
||||
return;
|
||||
}
|
||||
|
||||
public bool RemoveElement(SceneElement e)
|
||||
{
|
||||
return _elements.Remove(e);
|
||||
}
|
||||
}
|
||||
}
|
21
renderer/SceneElement.cs
Normal file
21
renderer/SceneElement.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class SceneElement
|
||||
{
|
||||
IDrawable _elem;
|
||||
int _x;
|
||||
int _y;
|
||||
public SceneElement(IDrawable elem, int xPos, int yPos)
|
||||
{
|
||||
_elem = elem;
|
||||
_x = xPos;
|
||||
_y = yPos;
|
||||
}
|
||||
|
||||
public void Draw(int sceneX, int sceneY)
|
||||
{
|
||||
_elem.Draw(_x + sceneX, _y + sceneY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
56
renderer/Sprite.cs
Normal file
56
renderer/Sprite.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using KumiScript.Loader;
|
||||
using SDL2;
|
||||
|
||||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class Sprite : IDrawable
|
||||
{
|
||||
readonly SDLRenderer _renderer;
|
||||
readonly Image _image;
|
||||
SDL.SDL_Rect _drawCoords;
|
||||
readonly int _height;
|
||||
readonly int _width;
|
||||
readonly int _xOffset;
|
||||
readonly int _yOffset;
|
||||
public Sprite(string path, SDLRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_image = new Image(path, renderer);
|
||||
KSMetaParser parser = new KSMetaParser(string.Concat(path, ".ksmeta"));
|
||||
_height = parser.GetAttribute("height");
|
||||
_width = parser.GetAttribute("width");
|
||||
_xOffset = parser.GetAttribute("xOffset");
|
||||
_yOffset = parser.GetAttribute("yOffset");
|
||||
_drawCoords.w = _width;
|
||||
_drawCoords.h = _height;
|
||||
}
|
||||
|
||||
public void Draw(int x, int y)
|
||||
{
|
||||
_drawCoords.x = x + _xOffset;
|
||||
_drawCoords.y = y + _yOffset;
|
||||
SDL.SDL_RenderCopy(_renderer.id, _image.GetTexture().id, 0, ref _drawCoords);
|
||||
}
|
||||
|
||||
public int GetBitmapHeight()
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
public int GetBitmapWidth()
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
public int GetXOffset()
|
||||
{
|
||||
return _xOffset;
|
||||
}
|
||||
|
||||
public int GetYOffset()
|
||||
{
|
||||
return _yOffset;
|
||||
}
|
||||
}
|
||||
}
|
25
renderer/sdl/SDLRenderer.cs
Normal file
25
renderer/sdl/SDLRenderer.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using SDL2;
|
||||
|
||||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class SDLRenderer
|
||||
{
|
||||
internal readonly nint id;
|
||||
internal SDLRenderer(SDLWindow window)
|
||||
{
|
||||
id = SDL.SDL_CreateRenderer(window.Id, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED);
|
||||
if (id == 0)
|
||||
throw new Exception("Failed to create renderer!");
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
SDL.SDL_RenderClear(id);
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
{
|
||||
SDL.SDL_RenderPresent(id);
|
||||
}
|
||||
}
|
||||
}
|
26
renderer/sdl/SDLTexture.cs
Normal file
26
renderer/sdl/SDLTexture.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using SDL2;
|
||||
|
||||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class SDLTexture : IDisposable
|
||||
{
|
||||
internal readonly nint id;
|
||||
public SDLTexture(string path, SDLRenderer renderer)
|
||||
{
|
||||
nint surface = SDL_image.IMG_Load(path);
|
||||
if (surface == 0)
|
||||
throw new Exception(SDL_image.IMG_GetError());
|
||||
|
||||
nint texture = SDL.SDL_CreateTextureFromSurface(renderer.id, surface);
|
||||
if (texture == 0)
|
||||
throw new Exception(SDL.SDL_GetError());
|
||||
|
||||
SDL.SDL_FreeSurface(surface);
|
||||
id = texture;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
SDL.SDL_DestroyTexture(id);
|
||||
}
|
||||
}
|
||||
}
|
39
renderer/sdl/SDLWindow.cs
Normal file
39
renderer/sdl/SDLWindow.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using SDL2;
|
||||
|
||||
namespace KumiScript.Renderer
|
||||
{
|
||||
public class SDLWindow
|
||||
{
|
||||
internal readonly nint Id;
|
||||
ushort _width;
|
||||
ushort _height;
|
||||
string _title;
|
||||
SDLRenderer? _renderer;
|
||||
public SDLWindow(ushort horizontalResolution, ushort verticalResolution, string windowTitle)
|
||||
{
|
||||
_width = horizontalResolution;
|
||||
_height = verticalResolution;
|
||||
_title = windowTitle;
|
||||
|
||||
nint window = SDL.SDL_CreateWindow(windowTitle, SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
|
||||
horizontalResolution, verticalResolution, 0);
|
||||
if (window == 0)
|
||||
throw new Exception("Failed to create window!");
|
||||
|
||||
Id = window;
|
||||
}
|
||||
|
||||
public int UpdateSurface()
|
||||
{
|
||||
return SDL.SDL_UpdateWindowSurface(Id);
|
||||
}
|
||||
|
||||
public SDLRenderer GetRenderer()
|
||||
{
|
||||
if (_renderer is null)
|
||||
_renderer = new SDLRenderer(this);
|
||||
|
||||
return _renderer;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue