Substantial progress on renderer among other things

This commit is contained in:
Michael Kiselev 2024-07-11 19:17:00 -05:00
parent 5c14525067
commit 45dc6f63ea
Signed by: Sangui
GPG key ID: DAB055E38B47526A
61 changed files with 1370 additions and 606 deletions

35
Game.cs
View file

@ -1,11 +1,14 @@
using KumiScript.Renderer;
using SDL2; using SDL2;
using KumiScript.Renderer;
using KumiScript.Gearbox;
public class EngineWindow public class EngineWindow
{ {
internal ushort width {get; private set;} internal ushort width {get; private set;}
internal ushort height {get; private set;} internal ushort height {get; private set;}
internal string title {get; private set;} internal string title {get; private set;}
public EngineWindow(ushort horizontalResolution, ushort verticalResolution, string windowTitle) public EngineWindow(ushort horizontalResolution, ushort verticalResolution, string windowTitle)
{ {
width = horizontalResolution; width = horizontalResolution;
@ -17,35 +20,21 @@ public class EngineWindow
if (SDL_image.IMG_Init(SDL_image.IMG_InitFlags.IMG_INIT_PNG) < 0) if (SDL_image.IMG_Init(SDL_image.IMG_InitFlags.IMG_INIT_PNG) < 0)
throw new Exception("SDL2 Image init failed!"); throw new Exception("SDL2 Image init failed!");
if (SDL_ttf.TTF_Init() < 0)
throw new Exception("SDL2 ttf init failed!");
} }
public void show() public void show()
{ {
SDLWindow window = new SDLWindow(width, height, title); SDLWindow window = new SDLWindow(width, height, title);
SDLRenderer renderer = new SDLRenderer(window); SDLRenderer renderer = new SDLRenderer(window);
bool mainLoop = true; GameState state = new GameStateMain(renderer);
SDL.SDL_Event e; while (!state.IsQuitting())
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) state = state.UpdateState();
{
switch (e.type)
{
case SDL.SDL_EventType.SDL_QUIT:
mainLoop = false;
break;
}
renderer.Clear();
s.DrawScene();
renderer.SwapBuffers();
}
} }
renderer.Dispose();
window.Dispose();
} }
} }

View file

@ -4,11 +4,11 @@ namespace KumiScript {
class KumiScript { class KumiScript {
static void Main (string[] args) { static void Main (string[] args) {
Console.WriteLine(System.IO.Directory.GetCurrentDirectory()); /*Console.WriteLine(System.IO.Directory.GetCurrentDirectory());
EngineWindow engineWindow = new EngineWindow(800, 600, "KumiScript Unicode"); EngineWindow engineWindow = new EngineWindow(800, 600, "KumiScript Unicode");
engineWindow.show(); engineWindow.show();*/
/*ReadEvalPrintLoop repl = new ReadEvalPrintLoop(Console.OpenStandardInput(), Console.OpenStandardOutput()); ReadEvalPrintLoop repl = new ReadEvalPrintLoop(Console.OpenStandardInput(), Console.OpenStandardOutput());
repl.Loop();*/ repl.Loop();
} }
} }
} }

166
common/FastLinkedList.cs Normal file
View file

@ -0,0 +1,166 @@
namespace KumiScript.Common
{
public class FastLinkedList<T>
{
ListNode<T>? _first;
ListNode<T>? _last;
uint _length;
public FastLinkedList()
{
_length = 0;
}
public void InsertLast(T addend)
{
ListNode<T> n = new ListNode<T>(addend);
if (_length == 0)
{
_first = n;
_last = n;
_length = 1;
return;
}
_last!.SetNext(n);
n.SetPrev(_last);
_last = n;
_length++;
return;
}
public void InsertFirst(T addend)
{
ListNode<T> n = new ListNode<T>(addend);
if (_length == 0)
{
_first = n;
_last = n;
_length = 1;
return;
}
_first!.SetPrev(n);
n.SetNext(_first);
_first = n;
_length++;
return;
}
private ListNode<T>? FindNth(uint index)
{
if (index > _length - 1)
return null;
if (index - 1 == _length)
return _last;
ListNode<T>? ni = _first;
if (ni is null)
return null;
for (uint i = 0; i < index; i++)
{
ni = ni!.GetNext();
}
return ni;
}
public void InsertAfter(uint index, T value)
{
ListNode<T> nn = new ListNode<T>(value);
ListNode<T>? ni = FindNth(index);
}
public T? Find(IEqualityComparer<T> eq, T other)
{
ListNode<T>? n = _first;
if (n is null)
return default;
do
{
T nv = n.GetValue();
if (eq.Equals(nv, other))
{
return nv;
}
n = n.GetNext();
} while (n is not null);
return default;
}
public T? GetFirst()
{
if (_first is null)
return default;
return _first.GetValue();
}
public T? GetLast()
{
if (_last is null)
return default;
return _last.GetValue();
}
public uint GetLength()
{
return _length;
}
}
internal class ListNode<T>
{
ListNode<T>? _next;
ListNode<T>? _prev;
T _value;
internal ListNode(T value)
{
_value = value;
}
internal T GetValue()
{
return _value;
}
internal void SetValue(T value)
{
_value = value;
return;
}
internal void SetNext(ListNode<T> next)
{
_next = next;
}
internal void SetPrev(ListNode<T> prev)
{
_prev = prev;
}
internal bool HasNext()
{
return _next is not null;
}
internal bool HasPrev()
{
return _prev is not null;
}
internal ListNode<T>? GetNext()
{
return _next;
}
internal ListNode<T>? GetPrev()
{
return _prev;
}
}
}

9
gearbox/GameState.cs Normal file
View file

@ -0,0 +1,9 @@
namespace KumiScript.Gearbox
{
public abstract class GameState
{
public abstract GameState UpdateState();
public abstract void AcceptMessage(StateMessage message);
public abstract bool IsQuitting();
}
}

118
gearbox/GameStateMain.cs Normal file
View file

@ -0,0 +1,118 @@
using SDL2;
using KumiScript.Renderer;
using TextBox = KumiScript.Renderer.TextBox;
namespace KumiScript.Gearbox
{
public class GameStateMain : GameState
{
List<Scene> _scenes;
Scene _curScene;
List<Sprite> _sprites;
List<Background> _backgrounds;
List<ManagedFont> _fonts;
GraphicalUserInterface _graphicalUI;
TextBox _bigBox;
SDLRenderer _renderer;
SDL.SDL_Event e;
ulong _tA;
ulong _tB;
float _delta;
public GameStateMain(SDLRenderer renderer)
{
_renderer = renderer;
_curScene = new Scene();
_scenes = new List<Scene>
{
_curScene
};
Sprite seiba = new Sprite("Resources/Sprites/test.png", renderer);
_sprites = new List<Sprite> {
seiba
};
Background background = new Background("Resources/Backgrounds/test.png", renderer);
_backgrounds = new List<Background>
{
background
};
_curScene.AddElement(background);
_curScene.AddElement(seiba);
_graphicalUI = new GraphicalUserInterface();
SDL.SDL_Color color;
color.r = 255;
color.g = 255;
color.b = 255;
color.a = 0;
ManagedFont font = new ManagedFont("Resources/Fonts/DejaVuSerif.ttf", 36, color, renderer, 256); //ascii
_fonts = new List<ManagedFont> {
font
};
Text hello = new Text("Hello, world!", font);
Text lorem = new Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", font);
_bigBox = new TextBox("Resources/Interface/bigbox.png", renderer, 36, true);
_bigBox.AddText(hello);
_bigBox.BreakLine();
_bigBox.AddText(lorem);
_graphicalUI.AddElement(_bigBox);
_tA = SDL.SDL_GetPerformanceCounter();
_tB = SDL.SDL_GetPerformanceCounter();
_delta = 0;
}
public override void AcceptMessage(StateMessage message)
{
throw new NotImplementedException();
}
public override bool IsQuitting()
{
return false;
}
public override GameState UpdateState()
{
_tA = SDL.SDL_GetPerformanceCounter();
while (SDL.SDL_PollEvent(out e) > 0)
{
switch (e.type)
{
case SDL.SDL_EventType.SDL_QUIT:
CleanUp();
return new GameStateQuitting();
case SDL.SDL_EventType.SDL_KEYUP:
switch (e.key.keysym.sym)
{
case SDL.SDL_Keycode.SDLK_RETURN:
_bigBox.UpdateState();
break;
}
break;
}
}
_tB = _tA;
_renderer.Clear();
_curScene.DrawScene();
_graphicalUI.DrawInterface();
_renderer.SwapBuffers();
_tB = SDL.SDL_GetPerformanceCounter();
_delta = (_tB - _tA) / SDL.SDL_GetPerformanceFrequency() * 1000.0f;
SDL.SDL_Delay((uint) (1000/60 - _delta));
return this;
}
private void CleanUp()
{
foreach (Sprite s in _sprites)
s.Dispose();
foreach(Background b in _backgrounds)
b.Dispose();
foreach(ManagedFont f in _fonts)
f.Dispose();
_graphicalUI.Dispose();
}
}
}

View file

@ -0,0 +1,23 @@
namespace KumiScript.Gearbox
{
public class GameStateQuitting : GameState
{
public GameStateQuitting()
{
}
public override void AcceptMessage(StateMessage message)
{
return;
}
public override bool IsQuitting()
{
return true;
}
public override GameState UpdateState()
{
return this;
}
}
}

7
gearbox/StateMessage.cs Normal file
View file

@ -0,0 +1,7 @@
namespace KumiScript.Gearbox
{
public abstract class StateMessage
{
}
}

View file

@ -1,5 +1,3 @@
using System.Diagnostics.CodeAnalysis;
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public class Environment public class Environment
@ -8,11 +6,11 @@ namespace KumiScript.Interpreter
readonly Dictionary<Symbol, Expression> _bindings; readonly Dictionary<Symbol, Expression> _bindings;
public Environment() public Environment()
{ {
_bindings = new Dictionary<Symbol, Expression>(SymbolComparer.GetInstance()); _bindings = new Dictionary<Symbol, Expression>(ReferenceEqualityComparer.Instance);
} }
public Environment(Environment outer) public Environment(Environment outer)
{ {
_bindings = new Dictionary<Symbol, Expression>(SymbolComparer.GetInstance()); _bindings = new Dictionary<Symbol, Expression>(ReferenceEqualityComparer.Instance);
_outer = outer; _outer = outer;
} }
@ -40,8 +38,7 @@ namespace KumiScript.Interpreter
{ {
if (_bindings.ContainsKey(symbol)) if (_bindings.ContainsKey(symbol))
{ {
_bindings.Remove(symbol); _bindings[symbol] = value;
_bindings.Add(symbol, value);
return; return;
} }
@ -51,33 +48,4 @@ namespace KumiScript.Interpreter
_outer.RedefineSymbol(symbol, value); _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();
}
}
}

View file

@ -1,32 +1,26 @@
using KumiScript.Reader;
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public class LispPrimitives public class LispPrimitives
{ {
public static Expression Lambda(ListExpression args, Environment env) public static Expression Lambda(Expression args, Environment env)
{ {
Expression car = args.Car(); Expression car = args.Car();
ListExpression rest = args.Cdr(); Expression rest = args.Cdr();
ListExpression? head = car as ListExpression; List<Expression> headl = car.GetMembers();
if (head is null)
throw new InterpreterInvalidDefinitionException();
List<Expression> headl = head.GetMembers();
List<Symbol> arg_names = new List<Symbol>(); List<Symbol> arg_names = new List<Symbol>();
for (int i = 0; i < headl.Count; i++) for (int i = 0; i < headl.Count; i++)
{ {
SymbolExpression? argi = headl[i] as SymbolExpression; arg_names.Add(headl[i].GetSymbol());
if (argi is null)
throw new InterpreterInvalidDefinitionException();
arg_names.Add(argi.GetSymbol());
} }
Expression body = rest.Car(); Expression body = rest.Car();
return new ProcedureExpression(new LispProcedure(arg_names, body, env)); return new ProcedureExpression(new LispProcedure(arg_names, body, env));
} }
public static Expression Quote(ListExpression args, Environment env) public static Expression Quote(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 1) if (argl.Count != 1)
@ -35,78 +29,60 @@ namespace KumiScript.Interpreter
return argl[0]; return argl[0];
} }
public static Expression Define(ListExpression args, Environment env) public static Expression Define(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
SymbolExpression? binding = argl[0] as SymbolExpression; Expression? binding = argl[0];
if (binding is null)
throw new InterpreterTypingException();
Symbol name = binding.GetSymbol(); Symbol name = binding.GetSymbol();
Expression definition = argl[1].Eval(env); Expression definition = argl[1].Eval(env);
env.AddSymbol(name, definition); env.AddSymbol(name, definition);
return definition; return definition;
} }
public static Expression Car(ListExpression args, Environment env) public static Expression Car(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 1) if (argl.Count != 1)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
ListExpression? list = argl[0] as ListExpression; return argl[0].Car();
if (list is null)
throw new InterpreterTypingException();
return list.Car();
} }
public static ListExpression Cdr(ListExpression args, Environment env) public static Expression Cdr(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 1) if (argl.Count != 1)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
ListExpression? list = argl[0] as ListExpression; return argl[0].Cdr();
if (list is null)
throw new InterpreterTypingException();
return list.Cdr();
} }
public static ProperListExpression Cons(ListExpression args, Environment env) public static ProperListExpression Cons(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
Expression car = argl[0]; Expression car = argl[0];
ListExpression? cdr = argl[1] as ListExpression; Expression cdr = argl[1];
if (cdr is null)
throw new InterpreterTypingException();
return cdr.Cons(car); return cdr.Cons(car);
} }
public static Expression Quit(ListExpression args, Environment env) public static Expression Quit(Expression args, Environment env)
{ {
System.Environment.Exit(0); System.Environment.Exit(0);
return new SymbolExpression(new Symbol("bye")); return new SymbolExpression(new Symbol("bye"));
} }
public static Expression Cond(ListExpression args, Environment env) public static Expression Cond(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
for (int i = 0; i < argl.Count; i ++) for (int i = 0; i < argl.Count; i ++)
{ {
ProperListExpression? conditional = argl[i] as ProperListExpression; Expression conditional = argl[i];
if (conditional is null)
throw new InterpreterTypingException();
Expression antecedent = conditional.Car(); Expression antecedent = conditional.Car();
Expression consequent = conditional.Cdr().Car(); Expression consequent = conditional.Cdr().Car();
if (antecedent.Eval(env) != NilExpression.GetInstance()) if (antecedent.Eval(env) != NilExpression.GetInstance())
@ -115,7 +91,7 @@ namespace KumiScript.Interpreter
return NilExpression.GetInstance(); return NilExpression.GetInstance();
} }
public static Expression Eq(ListExpression args, Environment env) public static Expression Eq(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
@ -127,24 +103,19 @@ namespace KumiScript.Interpreter
return NilExpression.GetInstance(); return NilExpression.GetInstance();
} }
public static Expression Set(ListExpression args, Environment env) public static Expression Set(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
SymbolExpression? binding = argl[0] as SymbolExpression; Symbol name = argl[0].GetSymbol();
if (binding is null)
throw new InterpreterTypingException();
Symbol name = binding.GetSymbol();
Expression definition = argl[1].Eval(env); Expression definition = argl[1].Eval(env);
env.RedefineSymbol(name, definition); env.RedefineSymbol(name, definition);
return definition; return definition;
} }
public static Expression For(ListExpression args, Environment env) public static Expression For(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 4) if (argl.Count != 4)
@ -163,19 +134,18 @@ namespace KumiScript.Interpreter
return result; return result;
} }
public static Expression Progn(ListExpression args, Environment env) public static Expression Progn(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
Expression result = NilExpression.GetInstance(); Expression result = NilExpression.GetInstance();
foreach (Expression expr in argl) foreach (Expression expr in argl)
{
result = expr.Eval(env); result = expr.Eval(env);
}
return result; return result;
} }
public static Expression Prog1(ListExpression args, Environment env) public static Expression Prog1(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
Expression result = argl.Count > 0 ? argl[0] : NilExpression.GetInstance(); Expression result = argl.Count > 0 ? argl[0] : NilExpression.GetInstance();
@ -186,7 +156,7 @@ namespace KumiScript.Interpreter
return result; return result;
} }
public static Expression Not(ListExpression args, Environment env) public static Expression Not(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 1) if (argl.Count != 1)
@ -195,26 +165,18 @@ namespace KumiScript.Interpreter
return argl[0] != NilExpression.GetInstance() ? NilExpression.GetInstance() : TrueExpression.GetInstance(); return argl[0] != NilExpression.GetInstance() ? NilExpression.GetInstance() : TrueExpression.GetInstance();
} }
public static Expression Nth(ListExpression args, Environment env) public static Expression Nth(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
IntegerExpression? arg0 = argl[0] as IntegerExpression;
if (arg0 is null)
throw new InterpreterTypingException();
ListExpression? arg1 = argl[1] as ListExpression; int n = (int) argl[0].GetValueAsFloat();
if (arg1 is null) List<Expression> arg1l = argl[1].GetMembers();
throw new InterpreterTypingException();
int n = arg0.GetValueAsInt();
List<Expression> arg1l = arg1.GetMembers();
return n >= 0 && n < arg1l.Count ? arg1l[n] : NilExpression.GetInstance(); return n >= 0 && n < arg1l.Count ? arg1l[n] : NilExpression.GetInstance();
} }
public static Expression While(ListExpression args, Environment env) public static Expression While(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 2) if (argl.Count != 2)
@ -234,22 +196,22 @@ namespace KumiScript.Interpreter
public static Environment RegisterPrimitives() public static Environment RegisterPrimitives()
{ {
Environment result = new Environment(); Environment result = new Environment();
result.AddSymbol(new Symbol("lambda"), new ProcedureExpression(new PrimitiveProcedure(Lambda))); result.AddSymbol(SymbolTable.GetInstance().FromString("lambda"), new ProcedureExpression(new PrimitiveProcedure(Lambda)));
result.AddSymbol(new Symbol("quote"), new ProcedureExpression(new PrimitiveProcedure(Quote))); result.AddSymbol(SymbolTable.GetInstance().FromString("quote"), new ProcedureExpression(new PrimitiveProcedure(Quote)));
result.AddSymbol(new Symbol("define"), new ProcedureExpression(new PrimitiveProcedure(Define))); result.AddSymbol(SymbolTable.GetInstance().FromString("define"), new ProcedureExpression(new PrimitiveProcedure(Define)));
result.AddSymbol(new Symbol("car"), new ProcedureExpression(new PrimitiveProcedure(Car))); result.AddSymbol(SymbolTable.GetInstance().FromString("car"), new ProcedureExpression(new PrimitiveProcedure(Car)));
result.AddSymbol(new Symbol("cdr"), new ProcedureExpression(new PrimitiveProcedure(Cdr))); result.AddSymbol(SymbolTable.GetInstance().FromString("cdr"), new ProcedureExpression(new PrimitiveProcedure(Cdr)));
result.AddSymbol(new Symbol("cons"), new ProcedureExpression(new PrimitiveProcedure(Cons))); result.AddSymbol(SymbolTable.GetInstance().FromString("cons"), new ProcedureExpression(new PrimitiveProcedure(Cons)));
result.AddSymbol(new Symbol("quit"), new ProcedureExpression(new PrimitiveProcedure(Quit))); result.AddSymbol(SymbolTable.GetInstance().FromString("quit"), new ProcedureExpression(new PrimitiveProcedure(Quit)));
result.AddSymbol(new Symbol("cond"), new ProcedureExpression(new PrimitiveProcedure(Cond))); result.AddSymbol(SymbolTable.GetInstance().FromString("cond"), new ProcedureExpression(new PrimitiveProcedure(Cond)));
result.AddSymbol(new Symbol("eq"), new ProcedureExpression(new PrimitiveProcedure(Eq))); result.AddSymbol(SymbolTable.GetInstance().FromString("eq"), new ProcedureExpression(new PrimitiveProcedure(Eq)));
result.AddSymbol(new Symbol("set!"), new ProcedureExpression(new PrimitiveProcedure(Set))); result.AddSymbol(SymbolTable.GetInstance().FromString("set!"), new ProcedureExpression(new PrimitiveProcedure(Set)));
result.AddSymbol(new Symbol("for"), new ProcedureExpression(new PrimitiveProcedure(For))); result.AddSymbol(SymbolTable.GetInstance().FromString("for"), new ProcedureExpression(new PrimitiveProcedure(For)));
result.AddSymbol(new Symbol("progn"), new ProcedureExpression(new PrimitiveProcedure(Progn))); result.AddSymbol(SymbolTable.GetInstance().FromString("progn"), new ProcedureExpression(new PrimitiveProcedure(Progn)));
result.AddSymbol(new Symbol("not"), new ProcedureExpression(new PrimitiveProcedure(Not))); result.AddSymbol(SymbolTable.GetInstance().FromString("not"), new ProcedureExpression(new PrimitiveProcedure(Not)));
result.AddSymbol(new Symbol("prog1"), new ProcedureExpression(new PrimitiveProcedure(Prog1))); result.AddSymbol(SymbolTable.GetInstance().FromString("prog1"), new ProcedureExpression(new PrimitiveProcedure(Prog1)));
result.AddSymbol(new Symbol("nth"), new ProcedureExpression(new PrimitiveProcedure(Nth))); result.AddSymbol(SymbolTable.GetInstance().FromString("nth"), new ProcedureExpression(new PrimitiveProcedure(Nth)));
result.AddSymbol(new Symbol("while"), new ProcedureExpression(new PrimitiveProcedure(While))); result.AddSymbol(SymbolTable.GetInstance().FromString("while"), new ProcedureExpression(new PrimitiveProcedure(While)));
return result; return result;
} }
} }

View file

@ -12,7 +12,7 @@ namespace KumiScript.Interpreter
_closureEnv = closureEnv; _closureEnv = closureEnv;
} }
public override Expression ApplyWithArgs(ListExpression args, Environment env) public override Expression ApplyWithArgs(Expression args, Environment env)
{ {
List<Expression> evaluatedArgs = args.EvalMembers(env); List<Expression> evaluatedArgs = args.EvalMembers(env);
if (_parameters.Count != evaluatedArgs.Count) if (_parameters.Count != evaluatedArgs.Count)
@ -40,5 +40,10 @@ namespace KumiScript.Interpreter
{ {
return string.Concat("λ(", string.Join(' ', _parameters), ")"); return string.Concat("λ(", string.Join(' ', _parameters), ")");
} }
public List<Symbol> GetParameters()
{
return _parameters;
}
} }
} }

View file

@ -1,211 +1,127 @@
using System.Reflection.Metadata.Ecma335; using KumiScript.Reader;
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public class MathPrimitives public class MathPrimitives
{ {
public static NumberExpression Plus(ListExpression args, Environment env) public static NumberExpression Plus(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
decimal acc = 0; decimal acc = 0;
for (int i = 0; i < argl.Count; i++) for (int i = 0; i < argl.Count; i++)
{ {
NumberExpression? argin = argl[i] as NumberExpression; acc += argl[i].GetValueAsFloat();
if (argin is null)
throw new InterpreterTypingException();
acc += argin.GetValueAsFloat();
} }
return NumberFactory.NormalizeFloat(acc); return new NumberExpression(acc);
} }
public static NumberExpression Minus(ListExpression args, Environment env) public static NumberExpression Minus(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count == 0) if (argl.Count == 0)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
NumberExpression? argn0 = argl[0] as NumberExpression; decimal acc = argl[0].GetValueAsFloat();
if (argn0 is null)
throw new InterpreterTypingException();
decimal acc = argn0.GetValueAsFloat();
if (argl.Count == 1) if (argl.Count == 1)
return NumberFactory.NormalizeFloat(1 - acc); return new NumberExpression(1 - acc);
for (int i = 1; i < argl.Count; i++) for (int i = 1; i < argl.Count; i++)
{ {
NumberExpression? argin = argl[i] as NumberExpression; acc -= argl[i].GetValueAsFloat();
if (argin is null)
throw new InterpreterTypingException();
acc -= argin.GetValueAsFloat();
} }
return NumberFactory.NormalizeFloat(acc); return new NumberExpression(acc);
} }
public static NumberExpression Times(ListExpression args, Environment env) public static NumberExpression Times(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count < 2) if (argl.Count < 2)
throw new InterpreterInvalidInvocationException(); throw new InterpreterInvalidInvocationException();
NumberExpression? arg0 = argl[0] as NumberExpression; decimal f = argl[0].GetValueAsFloat();
if (arg0 is null)
throw new InterpreterTypingException();
decimal f = arg0.GetValueAsFloat();
for (int i = 1; i < argl.Count; i++) for (int i = 1; i < argl.Count; i++)
{ {
NumberExpression? argn = argl[i] as NumberExpression; f *= argl[i].GetValueAsFloat();
if (argn is null)
throw new InterpreterTypingException();
f *= argn.GetValueAsFloat();
} }
return NumberFactory.NormalizeFloat(f); return new NumberExpression(f);
} }
public static NumberExpression DividedBy(ListExpression args, Environment env) public static NumberExpression DividedBy(Expression 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 GreaterThan(ListExpression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
NumberExpression? arg0 = argl[0] as NumberExpression; return new NumberExpression(argl[0].GetValueAsFloat() / argl[1].GetValueAsFloat());
if (arg0 is null)
throw new InterpreterTypingException();
NumberExpression? arg1 = argl[1] as NumberExpression;
if (arg1 is null)
throw new InterpreterTypingException();
return arg0.GetValueAsFloat() > arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
} }
public static Expression LessThan(ListExpression args, Environment env)
public static NumberExpression Modulus(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
NumberExpression? arg0 = argl[0] as NumberExpression; return new NumberExpression(argl[0].GetValueAsFloat() % argl[1].GetValueAsFloat());
if (arg0 is null)
throw new InterpreterTypingException();
NumberExpression? arg1 = argl[1] as NumberExpression;
if (arg1 is null)
throw new InterpreterTypingException();
return arg0.GetValueAsFloat() < arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
} }
public static Expression LessThanEquals(ListExpression args, Environment env) public static Expression GreaterThan(Expression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
NumberExpression? arg0 = argl[0] as NumberExpression; return argl[0].GetValueAsFloat() > argl[1].GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
if (arg0 is null)
throw new InterpreterTypingException();
NumberExpression? arg1 = argl[1] as NumberExpression;
if (arg1 is null)
throw new InterpreterTypingException();
return arg0.GetValueAsFloat() <= arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
} }
public static Expression LessThan(Expression args, Environment env)
public static Expression GreaterThanEquals(ListExpression args, Environment env)
{ {
List<Expression> argl = args.EvalMembers(env); List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2) if (argl.Count != 2)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
NumberExpression? arg0 = argl[0] as NumberExpression; return argl[0].GetValueAsFloat() < argl[1].GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
if (arg0 is null)
throw new InterpreterTypingException();
NumberExpression? arg1 = argl[1] as NumberExpression;
if (arg1 is null)
throw new InterpreterTypingException();
return arg0.GetValueAsFloat() >= arg1.GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
} }
public static Expression PlusPlus(ListExpression args, Environment env) public static Expression LessThanEquals(Expression args, Environment env)
{
List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2)
throw new InterpreterInvalidApplicationException();
return argl[0].GetValueAsFloat() <= argl[1].GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
}
public static Expression GreaterThanEquals(Expression args, Environment env)
{
List<Expression> argl = args.EvalMembers(env);
if (argl.Count != 2)
throw new InterpreterInvalidApplicationException();
return argl[0].GetValueAsFloat() >= argl[1].GetValueAsFloat() ? TrueExpression.GetInstance() : NilExpression.GetInstance();
}
public static Expression PlusPlus(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 1) if (argl.Count != 1)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
SymbolExpression? binding = argl[0] as SymbolExpression; Symbol name = argl[0].GetSymbol();
if (binding is null)
throw new InterpreterTypingException();
Symbol name = binding.GetSymbol();
Expression val = env.Lookup(name); Expression val = env.Lookup(name);
NumberExpression? num = val as NumberExpression; NumberExpression nump = new NumberExpression(val.GetValueAsFloat() + 1);
if (num is null)
throw new InterpreterTypingException();
NumberExpression nump = NumberFactory.NormalizeFloat(num.GetValueAsFloat() + 1);
env.RedefineSymbol(name, nump); env.RedefineSymbol(name, nump);
return nump; return nump;
} }
public static Expression MinusMinus(ListExpression args, Environment env) public static Expression MinusMinus(Expression args, Environment env)
{ {
List<Expression> argl = args.GetMembers(); List<Expression> argl = args.GetMembers();
if (argl.Count != 1) if (argl.Count != 1)
throw new InterpreterInvalidApplicationException(); throw new InterpreterInvalidApplicationException();
SymbolExpression? binding = argl[0] as SymbolExpression; Symbol name = argl[0].GetSymbol();
if (binding is null)
throw new InterpreterTypingException();
Symbol name = binding.GetSymbol();
Expression val = env.Lookup(name); Expression val = env.Lookup(name);
NumberExpression? num = val as NumberExpression; NumberExpression nump = new NumberExpression(val.GetValueAsFloat() - 1);
if (num is null)
throw new InterpreterTypingException();
NumberExpression nump = NumberFactory.NormalizeFloat(num.GetValueAsFloat() - 1);
env.RedefineSymbol(name, nump); env.RedefineSymbol(name, nump);
return nump; return nump;
} }
@ -213,17 +129,17 @@ namespace KumiScript.Interpreter
public static Environment RegisterPrimitives(Environment outer) public static Environment RegisterPrimitives(Environment outer)
{ {
Environment result = new Environment(outer); Environment result = new Environment(outer);
result.AddSymbol(new Symbol("+"), new ProcedureExpression(new PrimitiveProcedure(Plus))); result.AddSymbol(SymbolTable.GetInstance().FromString("+"), new ProcedureExpression(new PrimitiveProcedure(Plus)));
result.AddSymbol(new Symbol("-"), new ProcedureExpression(new PrimitiveProcedure(Minus))); result.AddSymbol(SymbolTable.GetInstance().FromString("-"), new ProcedureExpression(new PrimitiveProcedure(Minus)));
result.AddSymbol(new Symbol("*"), new ProcedureExpression(new PrimitiveProcedure(Times))); result.AddSymbol(SymbolTable.GetInstance().FromString("*"), new ProcedureExpression(new PrimitiveProcedure(Times)));
result.AddSymbol(new Symbol("/"), new ProcedureExpression(new PrimitiveProcedure(DividedBy))); result.AddSymbol(SymbolTable.GetInstance().FromString("/"), new ProcedureExpression(new PrimitiveProcedure(DividedBy)));
result.AddSymbol(new Symbol("%"), new ProcedureExpression(new PrimitiveProcedure(Modulus))); result.AddSymbol(SymbolTable.GetInstance().FromString("%"), new ProcedureExpression(new PrimitiveProcedure(Modulus)));
result.AddSymbol(new Symbol(">"), new ProcedureExpression(new PrimitiveProcedure(GreaterThan))); result.AddSymbol(SymbolTable.GetInstance().FromString(">"), new ProcedureExpression(new PrimitiveProcedure(GreaterThan)));
result.AddSymbol(new Symbol("<"), new ProcedureExpression(new PrimitiveProcedure(LessThan))); result.AddSymbol(SymbolTable.GetInstance().FromString("<"), new ProcedureExpression(new PrimitiveProcedure(LessThan)));
result.AddSymbol(new Symbol("<="), new ProcedureExpression(new PrimitiveProcedure(LessThanEquals))); result.AddSymbol(SymbolTable.GetInstance().FromString("<="), new ProcedureExpression(new PrimitiveProcedure(LessThanEquals)));
result.AddSymbol(new Symbol(">="), new ProcedureExpression(new PrimitiveProcedure(GreaterThanEquals))); result.AddSymbol(SymbolTable.GetInstance().FromString(">="), new ProcedureExpression(new PrimitiveProcedure(GreaterThanEquals)));
result.AddSymbol(new Symbol("++!"), new ProcedureExpression(new PrimitiveProcedure(PlusPlus))); result.AddSymbol(SymbolTable.GetInstance().FromString("++!"), new ProcedureExpression(new PrimitiveProcedure(PlusPlus)));
result.AddSymbol(new Symbol("--!"), new ProcedureExpression(new PrimitiveProcedure(MinusMinus))); result.AddSymbol(SymbolTable.GetInstance().FromString("--!"), new ProcedureExpression(new PrimitiveProcedure(MinusMinus)));
return result; return result;
} }
} }

View file

@ -2,14 +2,14 @@ namespace KumiScript.Interpreter
{ {
public class PrimitiveProcedure : Procedure public class PrimitiveProcedure : Procedure
{ {
public delegate Expression PrimitiveDelegate(ListExpression args, Environment env); public delegate Expression PrimitiveDelegate(Expression args, Environment env);
readonly PrimitiveDelegate _function; readonly PrimitiveDelegate _function;
public PrimitiveProcedure(PrimitiveDelegate function) public PrimitiveProcedure(PrimitiveDelegate function)
{ {
_function = function; _function = function;
} }
public override Expression ApplyWithArgs(ListExpression args, Environment env) public override Expression ApplyWithArgs(Expression args, Environment env)
{ {
return _function(args, env); return _function(args, env);
} }

View file

@ -6,7 +6,7 @@ namespace KumiScript.Interpreter
{ {
} }
public abstract Expression ApplyWithArgs(ListExpression args, Environment env); public abstract Expression ApplyWithArgs(Expression args, Environment env);
public abstract bool IsPrimitive(); public abstract bool IsPrimitive();
} }
} }

View file

@ -24,9 +24,9 @@ namespace KumiScript.Interpreter
Expression expr = parser.NextTopLevelExpression(); Expression expr = parser.NextTopLevelExpression();
try try
{ {
Expression result = expr.Eval(top); Expression result = expr.Eval(top);
streamWriter.Write(string.Format("{0}\n", result.ToString())); streamWriter.Write(string.Format("{0}\n", result.ToString()));
streamWriter.Flush(); streamWriter.Flush();
} catch (Exception ex) { } catch (Exception ex) {
if (ex is InterpreterInvalidApplicationException if (ex is InterpreterInvalidApplicationException
or InterpreterInvalidDefinitionException or InterpreterInvalidDefinitionException

View file

@ -10,7 +10,7 @@ namespace KumiScript.Interpreter
public bool Equals(Symbol s) public bool Equals(Symbol s)
{ {
return s.ToString() == _name; return ReferenceEquals(this, s);
} }
public override string ToString() public override string ToString()

View file

@ -1,12 +1,70 @@
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public abstract class Expression public class Expression
{ {
public Expression() public virtual Expression Eval(Environment env)
{ {
return this;
} }
public abstract Expression Eval(Environment env); public virtual decimal GetValueAsFloat()
public abstract bool Equals(Expression expr); {
throw new InterpreterTypingException();
}
public virtual Expression Car()
{
throw new InterpreterTypingException();
}
public virtual Expression Cdr()
{
throw new InterpreterTypingException();
}
public virtual ProperListExpression Cons(Expression expr)
{
throw new InterpreterTypingException();
}
public virtual ProperListExpression AppendToList(Expression expr)
{
List<Expression> el = new List<Expression>(2)
{
this,
expr
};
return new ProperListExpression(el);
}
public virtual List<Expression> EvalMembers(Environment env)
{
throw new InterpreterTypingException();
}
public virtual List<Expression> GetMembers()
{
throw new InterpreterTypingException();
}
public virtual Symbol GetSymbol()
{
throw new InterpreterTypingException();
}
public virtual Expression Apply(Expression operand, Environment env)
{
throw new InterpreterTypingException();
}
public virtual bool IsPrimitive()
{
throw new InterpreterTypingException();
}
public virtual bool Equals (Expression expr)
{
return ReferenceEquals(this, expr);
}
} }
} }

View file

@ -1,41 +0,0 @@
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();
}
}
}

View file

@ -1,42 +0,0 @@
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();
}
}
}

View file

@ -1,15 +0,0 @@
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();
}
}

View file

@ -2,7 +2,7 @@ namespace KumiScript.Interpreter
{ {
public class ListFactory public class ListFactory
{ {
public static ListExpression MakeList(List<Expression> expressions) public static Expression MakeList(List<Expression> expressions)
{ {
if (expressions.Any()) if (expressions.Any())
return new ProperListExpression(expressions); return new ProperListExpression(expressions);

View file

@ -1,6 +1,6 @@
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public class NilExpression : ListExpression public class NilExpression : Expression
{ {
private static NilExpression? _instance; private static NilExpression? _instance;
private NilExpression() private NilExpression()
@ -20,7 +20,7 @@ namespace KumiScript.Interpreter
return this; return this;
} }
public override ListExpression Cdr() public override Expression Cdr()
{ {
return this; return this;
} }
@ -30,16 +30,6 @@ namespace KumiScript.Interpreter
return new ProperListExpression(new List<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) public override List<Expression> EvalMembers(Environment env)
{ {
return new List<Expression>(); return new List<Expression>();

View file

@ -1,12 +1,35 @@
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public abstract class NumberExpression : Expression public class NumberExpression : Expression
{ {
public NumberExpression() decimal _value;
public NumberExpression(decimal value)
{ {
_value = value;
} }
public abstract decimal GetValueAsFloat(); public override decimal GetValueAsFloat()
public abstract int GetValueAsInt(); {
return _value;
}
public override string ToString()
{
return _value.ToString();
}
public override bool Equals(Expression expr)
{
try
{
decimal d = expr.GetValueAsFloat();
return d == _value;
}
catch (InterpreterTypingException)
{
return false;
}
}
} }
} }

View file

@ -1,15 +0,0 @@
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);
}
}
}

View file

@ -21,7 +21,7 @@ namespace KumiScript.Interpreter
return this; return this;
} }
public Expression Apply(ListExpression args, Environment env) public override Expression Apply(Expression args, Environment env)
{ {
return _proc.ApplyWithArgs(args, env); return _proc.ApplyWithArgs(args, env);
} }
@ -34,18 +34,9 @@ namespace KumiScript.Interpreter
return string.Format("#Procedure<{0}>", _proc.ToString()); return string.Format("#Procedure<{0}>", _proc.ToString());
} }
public override bool Equals(Expression expr) public override bool IsPrimitive()
{ {
ProcedureExpression? pe = expr as ProcedureExpression; return _proc.IsPrimitive();
if (pe is null)
return false;
return _proc.Equals(pe._proc);
}
public Procedure GetProcedure()
{
return _proc;
} }
} }
} }

View file

@ -1,6 +1,6 @@
namespace KumiScript.Interpreter namespace KumiScript.Interpreter
{ {
public class ProperListExpression : ListExpression public class ProperListExpression : Expression
{ {
readonly List<Expression> _values; readonly List<Expression> _values;
public ProperListExpression(List<Expression> expressions) public ProperListExpression(List<Expression> expressions)
@ -10,11 +10,8 @@ namespace KumiScript.Interpreter
public override Expression Eval(Environment env) public override Expression Eval(Environment env)
{ {
ProcedureExpression? rator = Car().Eval(env) as ProcedureExpression; Expression rator = Car().Eval(env);
if (rator is null) Expression rand = Cdr();
throw new InterpreterInvalidInvocationException();
ListExpression rand = Cdr();
return rator.Apply(rand, env); return rator.Apply(rand, env);
} }
@ -34,24 +31,18 @@ namespace KumiScript.Interpreter
public override string ToString() public override string ToString()
{ {
return String.Concat("(", return string.Concat("(",
String.Join(' ', (object[]) _values.ToArray()), string.Join(' ', (object[]) _values.ToArray()),
")"); ")");
} }
public override Expression Car() public override Expression Car()
{ {
if (_values.Count == 0)
return this;
return _values.First(); return _values.First();
} }
public override ListExpression Cdr() public override Expression Cdr()
{ {
if (_values.Count == 0)
return this;
List<Expression> rest = new List<Expression>(_values); List<Expression> rest = new List<Expression>(_values);
rest.RemoveAt(0); rest.RemoveAt(0);
return ListFactory.MakeList(rest); return ListFactory.MakeList(rest);
@ -64,13 +55,11 @@ namespace KumiScript.Interpreter
return new ProperListExpression(consd); return new ProperListExpression(consd);
} }
public override bool Equals(Expression expr) public override ProperListExpression AppendToList(Expression expr)
{ {
ProperListExpression? lexpr = expr as ProperListExpression; List<Expression> appended = new List<Expression>(_values);
if (lexpr is null) appended.Append(expr);
return false; return new ProperListExpression(appended);
return lexpr.GetMembers().SequenceEqual(_values);
} }
} }
} }

View file

@ -8,23 +8,9 @@ namespace KumiScript.Interpreter
_value = 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() public override string ToString()
{ {
return _value; return "\"" + _value + "\"";
} }
} }
} }

View file

@ -8,21 +8,12 @@ namespace KumiScript.Interpreter
_value = 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) public override Expression Eval(Environment env)
{ {
return env.Lookup(_value); return env.Lookup(_value);
} }
public Symbol GetSymbol() public override Symbol GetSymbol()
{ {
return _value; return _value;
} }
@ -31,5 +22,18 @@ namespace KumiScript.Interpreter
{ {
return _value.ToString(); return _value.ToString();
} }
public override bool Equals(Expression expr)
{
try
{
Symbol s = expr.GetSymbol();
return s != _value;
}
catch (InterpreterTypingException)
{
return false;
}
}
} }
} }

View file

@ -15,16 +15,6 @@ namespace KumiScript.Interpreter
return _instance; return _instance;
} }
public override bool Equals(Expression expr)
{
return expr is TrueExpression;
}
public override Expression Eval(Environment env)
{
return this;
}
public override string ToString() public override string ToString()
{ {
return "t"; return "t";

View file

@ -19,7 +19,7 @@ namespace KumiScript.Reader
{ {
decimal f; decimal f;
if (decimal.TryParse(_value, out f)) if (decimal.TryParse(_value, out f))
return NumberFactory.NormalizeFloat(f); return new NumberExpression(f);
if (_value == "null") if (_value == "null")
return NilExpression.GetInstance(); return NilExpression.GetInstance();
@ -27,7 +27,7 @@ namespace KumiScript.Reader
if (_value == "t") if (_value == "t")
return TrueExpression.GetInstance(); return TrueExpression.GetInstance();
return new SymbolExpression(new Symbol(_value)); return new SymbolExpression(SymbolTable.GetInstance().FromString(_value));
} }
public override string GetValue() public override string GetValue()

22
reader/FakeExpression.cs Normal file
View file

@ -0,0 +1,22 @@
using KumiScript.Interpreter;
namespace KumiScript.Reader
{
public class FakeExpression : Expression
{
static FakeExpression? _instance;
private FakeExpression()
{
_instance = this;
}
public static FakeExpression GetInstance()
{
if (_instance is null)
return new FakeExpression();
return _instance;
}
}
}

View file

@ -28,17 +28,15 @@ namespace KumiScript.Reader
public Expression VisitParen(ParenthesisToken paren) public Expression VisitParen(ParenthesisToken paren)
{ {
if (!paren._leftParen) if (!paren._leftParen)
return null; //TODO: some other way of throwing it back return FakeExpression.GetInstance(); //TODO: some other way of throwing it back
List<Expression> list = new List<Expression>(); List<Expression> list = new List<Expression>();
Expression item = _parser.NextExpressionCC(this); Expression item = _parser.NextExpressionCC(this);
while (!ReferenceEquals(item, FakeExpression.GetInstance()))
while (item is not null)
{ {
list.Add(item); list.Add(item);
item = _parser.NextExpressionCC(this); item = _parser.NextExpressionCC(this);
} }
return ListFactory.MakeList(list); return ListFactory.MakeList(list);
} }

View file

@ -14,7 +14,7 @@ namespace KumiScript.Reader
{ {
List<Expression> quotedAtom = new List<Expression> List<Expression> quotedAtom = new List<Expression>
{ {
new SymbolExpression(new Symbol("quote")), new SymbolExpression(SymbolTable.GetInstance().FromString("quote")),
atom.ToExpression() atom.ToExpression()
}; };
return new ProperListExpression(quotedAtom); return new ProperListExpression(quotedAtom);
@ -33,7 +33,7 @@ namespace KumiScript.Reader
List<Expression> list = new List<Expression>(); List<Expression> list = new List<Expression>();
ParserListVisitor listVisitor = new ParserListVisitor(_parser); ParserListVisitor listVisitor = new ParserListVisitor(_parser);
Expression item = _parser.NextExpressionCC(listVisitor); Expression item = _parser.NextExpressionCC(listVisitor);
while (item is not null) while (!ReferenceEquals(item, FakeExpression.GetInstance()))
{ {
list.Add(item); list.Add(item);
item = _parser.NextExpressionCC(listVisitor); item = _parser.NextExpressionCC(listVisitor);
@ -41,7 +41,7 @@ namespace KumiScript.Reader
Expression listExpression = ListFactory.MakeList(list); Expression listExpression = ListFactory.MakeList(list);
List<Expression> quotedList = new List<Expression> List<Expression> quotedList = new List<Expression>
{ {
new SymbolExpression(new Symbol("quote")), new SymbolExpression(SymbolTable.GetInstance().FromString("quote")),
listExpression listExpression
}; };
return new ProperListExpression(quotedList); return new ProperListExpression(quotedList);
@ -56,7 +56,7 @@ namespace KumiScript.Reader
{ {
List<Expression> quotedString = new List<Expression> List<Expression> quotedString = new List<Expression>
{ {
new SymbolExpression(new Symbol("quote")), new SymbolExpression(SymbolTable.GetInstance().FromString("quote")),
str.ToExpression() str.ToExpression()
}; };
return new ProperListExpression(quotedString); return new ProperListExpression(quotedString);

View file

@ -34,7 +34,7 @@ namespace KumiScript.Reader
ParserListVisitor listVisitor = new ParserListVisitor(_parser); ParserListVisitor listVisitor = new ParserListVisitor(_parser);
Expression item = _parser.NextExpressionCC(listVisitor); Expression item = _parser.NextExpressionCC(listVisitor);
while (item is not null) while (!ReferenceEquals(item, FakeExpression.GetInstance()))
{ {
list.Add(item); list.Add(item);
item = _parser.NextExpressionCC(listVisitor); item = _parser.NextExpressionCC(listVisitor);

36
reader/SymbolTable.cs Normal file
View file

@ -0,0 +1,36 @@
using KumiScript.Interpreter;
namespace KumiScript.Reader
{
public class SymbolTable
{
static SymbolTable? _instance;
readonly Dictionary<string, Symbol> _table;
private SymbolTable()
{
_instance = this;
_table = new Dictionary<string, Symbol>();
}
public static SymbolTable GetInstance()
{
if (_instance is null)
return new SymbolTable();
return _instance;
}
public Symbol FromString(string s)
{
Symbol? sym;
_table.TryGetValue(s, out sym);
if (sym is null)
{
sym = new Symbol(s);
_table.Add(s, sym);
}
return sym;
}
}
}

View file

@ -1,44 +1,59 @@
using KumiScript.Loader;
using SDL2; using SDL2;
namespace KumiScript.Renderer namespace KumiScript.Renderer
{ {
public class Background : IDrawable public class Background : SceneElement, IDisposable
{ {
SDLTexture _texture;
SDLRenderer _renderer; SDLRenderer _renderer;
Image _image;
int _height; int _height;
int _width; int _width;
int _anim;
int _frame;
public Background(string path, SDLRenderer renderer) public Background(string path, SDLRenderer renderer)
{ {
_texture = new SDLTexture(path, renderer);
_renderer = renderer; _renderer = renderer;
_image = new Image(path, renderer); KSMetaParser parser = new KSMetaParser(string.Concat(path, ".ksmeta"));
_width = parser.GetAttribute("width");
_height = parser.GetAttribute("height");
_anim = 0;
_frame = 0;
} }
public void Draw(int x, int y) public void Dispose()
{ {
SDL.SDL_RenderCopy(_renderer.id, _image.GetTexture().id, 0, 0); _texture.Dispose();
return;
} }
public int GetBitmapHeight() public override void Draw(int x, int y)
{ {
return _height; SDL.SDL_Rect destRect = new SDL.SDL_Rect();
destRect.x = x;
destRect.y = y;
destRect.w = 800;
destRect.h = 600;
SDL.SDL_Rect sourceRect = new SDL.SDL_Rect();
sourceRect.x = _anim * _width;
sourceRect.y = _frame * _height;
sourceRect.w = _width;
sourceRect.h = _height;
_texture.Draw(_renderer, sourceRect, destRect);
} }
public int GetBitmapWidth() public override int GetBitmapHeight()
{ {
return _width; return 600;
} }
public int GetXOffset() public override int GetBitmapWidth()
{ {
return 0; return 800;
} }
public int GetYOffset()
{
return 0;
}
} }
} }

29
renderer/DummyText.cs Normal file
View file

@ -0,0 +1,29 @@
namespace KumiScript.Renderer
{
public class DummyText : Text
{
public DummyText(string text, ManagedFont font) : base(text, font)
{
}
public override void Draw(int x, int y)
{
return;
}
public override void DrawWrapping(int x, int y, int maxw, int spacing, int retw, char delim, out int penx, out int peny)
{
penx = retw;
peny = y + spacing;
return;
}
public override bool DrawWrappingAnimate(int x, int y, int maxw, int spacing, int retw, char delim, out int penx, out int peny)
{
penx = retw;
peny = y + spacing;
return true;
}
}
}

101
renderer/Glyph.cs Normal file
View file

@ -0,0 +1,101 @@
using SDL2;
namespace KumiScript.Renderer
{
public class Glyph : IDisposable
{
readonly char _char;
readonly int _width;
readonly int _height;
SDLTexture _tex;
SDLRenderer _renderer;
public Glyph(char c, SDLFont font, SDL.SDL_Color clr, SDLRenderer renderer)
{
_char = c;
nint surface = SDL_ttf.TTF_RenderGlyph32_Blended(font.GetHandle(), c, clr);
_tex = new SDLTexture(surface, renderer);
SDL.SDL_FreeSurface(surface);
_tex.QueryTexture(out _, out _, out _width, out _height);
_renderer = renderer;
}
public void Dispose()
{
_tex.Dispose();
return;
}
public char GetCharacter()
{
return _char;
}
public SDLTexture GetTexture()
{
return _tex;
}
public int GetWidth()
{
return _width;
}
public void DrawAt(int x, int y)
{
SDL.SDL_Rect destRect;
destRect.x = x;
destRect.y = y;
destRect.w = _width;
destRect.h = _height;
SDL.SDL_Rect sourceRect;
sourceRect.x = 0;
sourceRect.y = 0;
sourceRect.w = _width;
sourceRect.h = _height;
_tex.Draw(_renderer, sourceRect, destRect);
}
public void DrawAdvancePen(int x, int y, out int pen)
{
SDL.SDL_Rect destRect;
destRect.x = x;
destRect.y = y;
destRect.w = _width;
destRect.h = _height;
SDL.SDL_Rect sourceRect;
sourceRect.x = 0;
sourceRect.y = 0;
sourceRect.w = _width;
sourceRect.h = _height;
_tex.Draw(_renderer, sourceRect, destRect);
pen = x + _width;
}
internal void DrawAdvancePenModAlpha(int x, int y, out int pen, byte v)
{
_tex.SetAlpha(v);
SDL.SDL_Rect destRect;
destRect.x = x;
destRect.y = y;
destRect.w = _width;
destRect.h = _height;
SDL.SDL_Rect sourceRect;
sourceRect.x = 0;
sourceRect.y = 0;
sourceRect.w = _width;
sourceRect.h = _height;
_tex.Draw(_renderer, sourceRect, destRect);
_tex.SetAlpha(255);
pen = x + _width;
return;
}
}
}

View file

@ -0,0 +1,36 @@
namespace KumiScript.Renderer
{
public class GraphicalUserInterface : IDisposable
{
List<InterfaceElement> _elements;
public GraphicalUserInterface()
{
_elements = new List<InterfaceElement>(16);
}
public void DrawInterface()
{
foreach (InterfaceElement e in _elements)
{
e.Draw(0, 0);
}
}
public void AddElement(InterfaceElement e)
{
_elements.Add(e);
return;
}
public bool RemoveElement(InterfaceElement e)
{
return _elements.Remove(e);
}
public void Dispose()
{
foreach (InterfaceElement e in _elements)
e.Dispose();
}
}
}

View file

@ -5,7 +5,5 @@ namespace KumiScript.Renderer
void Draw(int x, int y); void Draw(int x, int y);
int GetBitmapWidth(); int GetBitmapWidth();
int GetBitmapHeight(); int GetBitmapHeight();
int GetXOffset();
int GetYOffset();
} }
} }

View file

@ -1,21 +0,0 @@
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;
}
}
}

View file

@ -0,0 +1,13 @@
namespace KumiScript.Renderer
{
public abstract class InterfaceElement : IDrawable, IDisposable
{
public abstract void Click();
public abstract void OnMouseover();
public abstract void OnMouseout();
public abstract void Draw(int x, int y);
public abstract int GetBitmapHeight();
public abstract int GetBitmapWidth();
public abstract void Dispose();
}
}

73
renderer/ManagedFont.cs Normal file
View file

@ -0,0 +1,73 @@
using SDL2;
namespace KumiScript.Renderer
{
public class ManagedFont : IDisposable
{
SDLFont _font;
int _cachesize;
SDL.SDL_Color _color;
SDLRenderer _renderer;
Dictionary<char, Glyph> _glyphs;
LinkedList<char> _incidence;
public ManagedFont(string path, int points, SDL.SDL_Color color, SDLRenderer renderer, int num_cache)
{
_font = new SDLFont(path, points);
_renderer = renderer;
_color = color;
_glyphs = new Dictionary<char, Glyph>();
_incidence = new LinkedList<char>();
_cachesize = num_cache;
}
public Glyph GetGlyph(char c)
{
UpdateFreq(c);
Glyph? g;
if (!_glyphs.TryGetValue(c, out g))
return CacheGlyph(c);
return g;
}
private Glyph CacheGlyph(char c)
{
if (_glyphs.Count >= _cachesize)
PurgeCache();
Glyph g = new Glyph(c, _font, _color, _renderer);
_glyphs.Add(c, g);
return g;
}
private void UpdateFreq(char c)
{
_incidence.Remove(c);
_incidence.AddFirst(c);
return;
}
private void PurgeCache()
{
for (int i = _cachesize - 1; i > _cachesize * .75; i--)
{
char c = _incidence.Last();
Glyph g = _glyphs[c];
_glyphs.Remove(c);
g.Dispose();
_incidence.RemoveLast();
}
return;
}
public void Dispose()
{
List<Glyph> glyphs = _glyphs.Values.ToList();
foreach (Glyph g in glyphs)
g.Dispose();
_font.Dispose();
}
}
}

View file

@ -2,11 +2,9 @@ namespace KumiScript.Renderer
{ {
public class Scene public class Scene
{ {
SDLRenderer _renderer;
List<SceneElement> _elements; List<SceneElement> _elements;
public Scene(SDLRenderer renderer) public Scene()
{ {
_renderer = renderer;
_elements = new List<SceneElement>(16); _elements = new List<SceneElement>(16);
} }

View file

@ -1,21 +1,9 @@
namespace KumiScript.Renderer namespace KumiScript.Renderer
{ {
public class SceneElement public abstract class SceneElement : IDrawable
{ {
IDrawable _elem; public abstract void Draw(int x, int y);
int _x; public abstract int GetBitmapHeight();
int _y; public abstract int GetBitmapWidth();
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;
}
} }
} }

View file

@ -1,56 +1,59 @@
using System.Text.Json.Serialization;
using KumiScript.Loader; using KumiScript.Loader;
using SDL2; using SDL2;
namespace KumiScript.Renderer namespace KumiScript.Renderer
{ {
public class Sprite : IDrawable public class Sprite : SceneElement, IDisposable
{ {
readonly SDLRenderer _renderer; SDLTexture _texture;
readonly Image _image; SDLRenderer _renderer;
SDL.SDL_Rect _drawCoords;
readonly int _height; readonly int _height;
readonly int _width; readonly int _width;
readonly int _xOffset; int _anim;
readonly int _yOffset; int _frame;
public Sprite(string path, SDLRenderer renderer) public Sprite(string path, SDLRenderer renderer)
{ {
_texture = new SDLTexture(path, renderer);
_renderer = renderer; _renderer = renderer;
_image = new Image(path, renderer);
KSMetaParser parser = new KSMetaParser(string.Concat(path, ".ksmeta")); KSMetaParser parser = new KSMetaParser(string.Concat(path, ".ksmeta"));
_height = parser.GetAttribute("height");
_width = parser.GetAttribute("width"); _width = parser.GetAttribute("width");
_xOffset = parser.GetAttribute("xOffset"); _height = parser.GetAttribute("height");
_yOffset = parser.GetAttribute("yOffset"); _anim = 0;
_drawCoords.w = _width; _frame = 0;
_drawCoords.h = _height;
} }
public void Draw(int x, int y) public void Dispose()
{ {
_drawCoords.x = x + _xOffset; _texture.Dispose();
_drawCoords.y = y + _yOffset; return;
SDL.SDL_RenderCopy(_renderer.id, _image.GetTexture().id, 0, ref _drawCoords);
} }
public int GetBitmapHeight() public override void Draw(int x, int y)
{
SDL.SDL_Rect destRect = new SDL.SDL_Rect();
destRect.x = x;
destRect.y = y;
destRect.w = _width;
destRect.h = _height;
SDL.SDL_Rect sourceRect = new SDL.SDL_Rect();
sourceRect.x = _anim * _width;
sourceRect.y = _frame * _height;
sourceRect.w = _width;
sourceRect.h = _height;
_texture.Draw(_renderer, sourceRect, destRect);
}
public override int GetBitmapHeight()
{ {
return _height; return _height;
} }
public int GetBitmapWidth() public override int GetBitmapWidth()
{ {
return _width; return _width;
} }
public int GetXOffset()
{
return _xOffset;
}
public int GetYOffset()
{
return _yOffset;
}
} }
} }

149
renderer/Text.cs Normal file
View file

@ -0,0 +1,149 @@
namespace KumiScript.Renderer
{
public class Text : InterfaceElement
{
readonly string _text;
readonly ManagedFont _font;
string[]? _words;
int _progress;
int _animProg;
readonly int _charcount;
public Text(string text, ManagedFont font)
{
_text = text;
_font = font;
_progress = 0;
_animProg = -24;
_charcount = text.Length;
}
public override void Click()
{
return;
}
public override void Draw(int x, int y)
{
foreach (char c in _text)
{
Glyph g = _font.GetGlyph(c);
g.DrawAdvancePen(x, y, out x);
}
}
public virtual void DrawWrapping(int x, int y, int maxw, int spacing, int retw, char delim, out int penx, out int peny)
{
if (_words is null)
_words = _text.Split(delim);
int spacew = _font.GetGlyph(delim).GetWidth();
penx = x;
peny = y;
foreach (string word in _words)
{
int w = 0;
Glyph[] gs = new Glyph[word.Length];
for (int i = 0; i < word.Length; i++)
{
gs[i] = _font.GetGlyph(word[i]);
w += gs[i].GetWidth();
}
if (penx + w >= maxw)
{
penx = retw;
peny += spacing;
}
foreach (Glyph g in gs)
g.DrawAdvancePen(penx, peny, out penx);
penx += spacew;
}
return;
}
public virtual bool DrawWrappingAnimate(int x, int y, int maxw, int spacing, int retw, char delim, out int penx, out int peny)
{
int c = 2;
int dist;
_animProg += 24;
if (_words is null)
_words = _text.Split(delim);
int spacew = _font.GetGlyph(delim).GetWidth();
penx = x;
peny = y;
foreach (string word in _words)
{
int w = 0;
Glyph[] gs = new Glyph[word.Length];
for (int i = 0; i < word.Length; i++)
{
gs[i] = _font.GetGlyph(word[i]);
w += gs[i].GetWidth();
}
if (penx + w >= maxw)
{
penx = retw;
peny += spacing;
}
foreach (Glyph g in gs)
{
if (_animProg >= 60)
{
_animProg = 0;
_progress++;
}
dist = _progress - c;
if (dist > 0)
{
g.DrawAdvancePen(penx, peny, out penx);
c++;
}
else if (dist < -4)
{
return false;
}
else
{
g.DrawAdvancePenModAlpha(penx, peny, out penx, (byte) (255 + dist * 42));
c++;
}
}
penx += spacew;
}
return true;
}
public override int GetBitmapHeight()
{
throw new NotImplementedException();
}
public override int GetBitmapWidth()
{
throw new NotImplementedException();
}
public override void OnMouseout()
{
return;
}
public override void OnMouseover()
{
return;
}
public void ForceProgress()
{
_progress = _charcount;
return;
}
public override void Dispose()
{
return;
}
}
}

176
renderer/TextBox.cs Normal file
View file

@ -0,0 +1,176 @@
using KumiScript.Loader;
using SDL2;
namespace KumiScript.Renderer
{
public class TextBox : InterfaceElement
{
SDLTexture _texture;
readonly SDLRenderer _renderer;
int _width;
int _height;
int _hpadding;
int _vpadding;
int _linespacing;
readonly bool _consecutive;
List<Text> _texts;
List<Text> _textsQueue;
TextBoxState _state;
private enum TextBoxState
{
StateRenderLine,
StateWaitEnter,
StateDone
}
public TextBox(string path, SDLRenderer renderer, bool consecutive)
{
_texture = new SDLTexture(path, renderer);
_renderer = renderer;
KSMetaParser parser = new KSMetaParser(string.Concat(path, ".ksmeta"));
_width = parser.GetAttribute("width");
_height = parser.GetAttribute("height");
_hpadding = parser.GetAttribute("hpadding");
_vpadding = parser.GetAttribute("vpadding");
_linespacing = parser.GetAttribute("linespacing");
_texts = new List<Text>(8);
_textsQueue = new List<Text>(8);
_consecutive = consecutive;
if (consecutive)
_state = TextBoxState.StateRenderLine;
else
_state = TextBoxState.StateDone;
}
public TextBox(string path, SDLRenderer renderer, int linespacing, bool consecutive)
{
_texture = new SDLTexture(path, renderer);
_renderer = renderer;
KSMetaParser parser = new KSMetaParser(string.Concat(path, ".ksmeta"));
_width = parser.GetAttribute("width");
_height = parser.GetAttribute("height");
_hpadding = parser.GetAttribute("hpadding");
_vpadding = parser.GetAttribute("vpadding");
_linespacing = linespacing;
_texts = new List<Text>(8);
_textsQueue = new List<Text>(8);
_consecutive = consecutive;
if (consecutive)
_state = TextBoxState.StateRenderLine;
else
_state = TextBoxState.StateDone;
}
public override void Click()
{
return;
}
public override void Dispose()
{
_texture.Dispose();
}
public override void Draw(int x, int y)
{
SDL.SDL_Rect destRect = new SDL.SDL_Rect();
destRect.x = x;
destRect.y = y;
destRect.w = _width;
destRect.h = _height;
SDL.SDL_Rect sourceRect = new SDL.SDL_Rect();
sourceRect.x = 0;
sourceRect.y = 0;
sourceRect.w = _width;
sourceRect.h = _height;
_texture.Draw(_renderer, sourceRect, destRect);
int retw = x + _hpadding;
int penx = retw;
int peny = y + _vpadding;
foreach (Text t in _texts)
{
t.DrawWrapping(penx, peny, _width - _hpadding, _linespacing, retw, ' ', out penx, out peny);
}
if (_state == TextBoxState.StateRenderLine)
{
Text t2 = _textsQueue.First();
bool done = t2.DrawWrappingAnimate(penx, peny, _width - _hpadding, _linespacing, retw, ' ', out penx, out peny);
if (done)
{
_texts.Add(t2);
_textsQueue.RemoveAt(0);
_state = _textsQueue.Any() ? TextBoxState.StateWaitEnter : TextBoxState.StateDone;
}
}
}
public void BreakLine()
{
AddText(new DummyText("", null));
}
public void AddText(Text t)
{
if (_consecutive)
_textsQueue.Add(t);
else
_texts.Add(t);
return;
}
public void UpdateState()
{
switch(_state)
{
case TextBoxState.StateRenderLine:
SkipLine();
return;
case TextBoxState.StateWaitEnter:
_state = TextBoxState.StateRenderLine;
return;
}
return;
}
private void SkipLine()
{
Text t = _textsQueue.First();
t.ForceProgress();
return;
}
public void ClearText()
{
_texts.Clear();
}
public bool IsDone()
{
return _state == TextBoxState.StateDone;
}
public override int GetBitmapHeight()
{
return _height;
}
public override int GetBitmapWidth()
{
return _width;
}
public override void OnMouseout()
{
return;
}
public override void OnMouseover()
{
return;
}
}
}

26
renderer/sdl/SDLFont.cs Normal file
View file

@ -0,0 +1,26 @@
using SDL2;
namespace KumiScript.Renderer
{
public class SDLFont : IDisposable
{
nint _handle;
public SDLFont(string path, int points)
{
_handle = SDL_ttf.TTF_OpenFont(path, points);
if (_handle == 0)
throw new Exception(SDL_ttf.TTF_GetError());
}
public void Dispose()
{
SDL_ttf.TTF_CloseFont(_handle);
return;
}
public nint GetHandle()
{
return _handle;
}
}
}

View file

@ -2,12 +2,12 @@ using SDL2;
namespace KumiScript.Renderer namespace KumiScript.Renderer
{ {
public class SDLRenderer public class SDLRenderer : IDisposable
{ {
internal readonly nint id; internal readonly nint id;
internal SDLRenderer(SDLWindow window) internal SDLRenderer(SDLWindow window)
{ {
id = SDL.SDL_CreateRenderer(window.Id, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED); id = SDL.SDL_CreateRenderer(window.Id, -1, SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED | SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC);
if (id == 0) if (id == 0)
throw new Exception("Failed to create renderer!"); throw new Exception("Failed to create renderer!");
} }
@ -17,6 +17,11 @@ namespace KumiScript.Renderer
SDL.SDL_RenderClear(id); SDL.SDL_RenderClear(id);
} }
public void Dispose()
{
SDL.SDL_DestroyRenderer(id);
}
public void SwapBuffers() public void SwapBuffers()
{ {
SDL.SDL_RenderPresent(id); SDL.SDL_RenderPresent(id);

View file

@ -4,7 +4,7 @@ namespace KumiScript.Renderer
{ {
public class SDLTexture : IDisposable public class SDLTexture : IDisposable
{ {
internal readonly nint id; readonly nint _id;
public SDLTexture(string path, SDLRenderer renderer) public SDLTexture(string path, SDLRenderer renderer)
{ {
nint surface = SDL_image.IMG_Load(path); nint surface = SDL_image.IMG_Load(path);
@ -16,11 +16,39 @@ namespace KumiScript.Renderer
throw new Exception(SDL.SDL_GetError()); throw new Exception(SDL.SDL_GetError());
SDL.SDL_FreeSurface(surface); SDL.SDL_FreeSurface(surface);
id = texture; _id = texture;
} }
public SDLTexture(nint surface, SDLRenderer renderer)
{
nint texture = SDL.SDL_CreateTextureFromSurface(renderer.id, surface);
if (texture == 0)
throw new Exception(SDL.SDL_GetError());
_id = texture;
}
public void Draw(SDLRenderer renderer, SDL.SDL_Rect sourceRect, SDL.SDL_Rect destRect)
{
SDL.SDL_RenderCopy(renderer.id, _id, ref sourceRect, ref destRect);
return;
}
public void Dispose() public void Dispose()
{ {
SDL.SDL_DestroyTexture(id); SDL.SDL_DestroyTexture(_id);
return;
}
public void QueryTexture(out uint format, out int access, out int width, out int height)
{
SDL.SDL_QueryTexture(_id, out format, out access, out width, out height);
return;
}
public void SetAlpha(byte alpha)
{
SDL.SDL_SetTextureAlphaMod(_id, alpha);
} }
} }
} }

View file

@ -2,7 +2,7 @@ using SDL2;
namespace KumiScript.Renderer namespace KumiScript.Renderer
{ {
public class SDLWindow public class SDLWindow : IDisposable
{ {
internal readonly nint Id; internal readonly nint Id;
ushort _width; ushort _width;
@ -35,5 +35,15 @@ namespace KumiScript.Renderer
return _renderer; return _renderer;
} }
public void SetResizable(bool r)
{
SDL.SDL_SetWindowResizable(Id, r ? SDL.SDL_bool.SDL_TRUE : SDL.SDL_bool.SDL_FALSE);
}
public void Dispose()
{
SDL.SDL_DestroyWindow(Id);
}
} }
} }