Skip to content
This repository has been archived by the owner on Oct 12, 2024. It is now read-only.

Commit

Permalink
This is very close to working but the last few bits are making me mad...
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanbeattie committed Jul 14, 2024
1 parent ee8b7f7 commit 1d8671f
Show file tree
Hide file tree
Showing 27 changed files with 503 additions and 163 deletions.
54 changes: 23 additions & 31 deletions Starship/Rockstar.Engine/Expressions/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,51 @@ namespace Rockstar.Engine.Expressions;
public class Binary : Expression {
private readonly Operator op;
private readonly Expression lhs;
private readonly Expression rhs;
private readonly ICollection<Expression> rhs;

public static Binary Reduce(Expression lhs, IList<OpList> lists, Source source) {
var binary = lists.First().Reduce(lhs);
return lists.Skip(1).Aggregate(binary, (current, list) => list.Reduce(current));
}
public static Expression Reduce(Expression lhs, IList<OpList> lists, Source source)
=> lists.Aggregate(lhs, (expr, next) => new Binary(next.Operator, expr, next.List, source));

public Binary(Operator op, Expression lhs, Expression rhs, Source source)
: base(source) {
this.op = op;
this.lhs = lhs;
this.rhs = rhs;
this.rhs = new List<Expression> { rhs };
}

public Binary(Operator op, Expression lhs, ICollection<Expression> rhs, Source source)
: base(source) {
this.op = op;
this.lhs = lhs;
this.rhs = rhs.Count > 1
? new Binary(op, rhs.First(), rhs.Skip(1).ToList(), source)
: rhs.Single();
this.rhs = rhs;
}

// public Operator Op => op;
//public Expression Lhs => lhs;
//public Expression Rhs => rhs;

public Value Resolve(Func<Expression, Value> eval) {
var v = eval(lhs);
return op switch {
Operator.Plus => v.Plus(eval(rhs)),
Operator.Minus => v.Minus(eval(rhs)),
Operator.Times => v.Times(eval(rhs)),
Operator.Divide => v.Divide(eval(rhs)),
Operator.Plus => v.Plus(rhs.Select(eval)),
Operator.Minus => v.Minus(rhs.Select(eval)),
Operator.Times => v.Times(rhs.Select(eval)),
Operator.Divide => v.Divide(rhs.Select(eval)),

Operator.Equals => v.Equäls(eval(rhs)),
Operator.NotEquals => v.NotEquäls(eval(rhs)),
Operator.LessThanEqual => v.LessThanEqual(eval(rhs)),
Operator.MoreThanEqual => v.MoreThanEqual(eval(rhs)),
Operator.LessThan => v.LessThan(eval(rhs)),
Operator.MoreThan => v.MoreThan(eval(rhs)),
Operator.Equals => v.Equäls(eval(rhs.Single())),
Operator.NotEquals => v.NotEquäls(eval(rhs.Single())),
Operator.LessThanEqual => v.LessThanEqual(eval(rhs.Single())),
Operator.MoreThanEqual => v.MoreThanEqual(eval(rhs.Single())),
Operator.LessThan => v.LessThan(eval(rhs.Single())),
Operator.MoreThan => v.MoreThan(eval(rhs.Single())),

Operator.Nor => new Booleän(v.Falsy && eval(rhs).Falsy),
Operator.And => v.Truthy ? eval(rhs) : v,
Operator.Or => v.Truthy ? v : eval(rhs),
Operator.Nor => new Booleän(v.Falsy && eval(rhs.Single()).Falsy),
Operator.And => v.Truthy ? eval(rhs.Single()) : v,
Operator.Or => v.Truthy ? v : eval(rhs.Single()),
_ => throw new ArgumentOutOfRangeException(nameof(op), op, null)
};
}

public override void Print(StringBuilder sb, string prefix) {
sb.Append(prefix).AppendLine($"{op}:".ToLowerInvariant());
lhs.Print(sb, prefix + INDENT);
rhs.Print(sb, prefix + INDENT);
foreach(var expr in rhs) expr.Print(sb, prefix + INDENT);
}

public override string ToString() {
Expand All @@ -75,8 +67,8 @@ public class OpList(Operator op, List<Expression> list) {
public Operator Operator => op;
public List<Expression> List => list;

public Binary Reduce(Expression lhs) {
var binary = new Binary(op, lhs, list.First(), Source.None);
return list.Skip(1).Aggregate(binary, (current, tail) => new(op, current, tail, Source.None));
}
//public Binary Reduce(Expression lhs) {
// var binary = new Binary(op, lhs, list.First(), Source.None);
// return list.Skip(1).Aggregate(binary, (current, tail) => new(op, current, tail, Source.None));
//}
}
37 changes: 37 additions & 0 deletions Starship/Rockstar.Engine/Expressions/Looküp.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Runtime.CompilerServices;
using System.Text;
using Rockstar.Engine.Statements;

namespace Rockstar.Engine.Expressions;

Expand All @@ -9,3 +11,38 @@ public class Looküp(Variable variable, Source source)
public override void Print(StringBuilder sb, string prefix)
=> sb.Append(prefix).AppendLine($"lookup: {variable.Name} ({variable.GetType().Name})");
}

public class Delist(Variable variable, Source source)
: Expression(source) {
public Variable Variable => variable;

public override void Print(StringBuilder sb, string prefix) {
base.Print(sb, prefix);
variable.Print(sb, prefix + INDENT);
}
}

public class Enlist(Variable variable, Source source)
: Statement(source) {

public Variable Variable => variable;
public List<Expression> Expressions = new();

public override void Print(StringBuilder sb, string prefix) {
base.Print(sb, prefix);
variable.Print(sb, prefix + INDENT);
foreach (var expr in Expressions) expr.Print(sb, prefix + INDENT);
}

public Enlist(Variable variable, Expression expr, Source source)
: this(variable, source) {
Expressions.Add(expr);

}

public Enlist(Variable variable, IEnumerable<Expression> list, Source source)
: this(variable, source) {
Expressions.AddRange(list);
}

}
4 changes: 3 additions & 1 deletion Starship/Rockstar.Engine/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public enum WhatToDo {
public class Result(Value value, WhatToDo whatToDo = WhatToDo.Next) {
public Value Value => value;
public WhatToDo WhatToDo => whatToDo;
public static Result Continue => new(new Null(), WhatToDo.Skip);
public static Result Break => new(new Null(), WhatToDo.Break);
public static Result Unknown = new(new Null(), WhatToDo.Unknown);
public static Result Return(Value value) => new Result(value, WhatToDo.Return);
public static Result Return(Value value) => new(value, WhatToDo.Return);
}
80 changes: 52 additions & 28 deletions Starship/Rockstar.Engine/RockstarEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,12 @@ public class RockstarEnvironment(RockstarIO io) {
public RockstarEnvironment(RockstarIO io, RockstarEnvironment parent)
: this(io) {
Parent = parent;
//this.CopyVariablesFrom(parent);
}

public RockstarEnvironment? Parent { get; init; }

public RockstarEnvironment Extend() => new(IO, this);

//private void CopyVariablesFrom(RockstarEnvironment that) {
// foreach (var variable in that.variables) {
// this.variables[variable.Key] = variable.Value;
// }
//}

protected RockstarIO IO = io;

public string? ReadInput() => IO.Read();
Expand All @@ -38,8 +31,10 @@ public RockstarEnvironment(RockstarIO io, RockstarEnvironment parent)
private readonly Dictionary<string, Value> variables = new();
private readonly Dictionary<string, Dictionary<Value, Value>> arrays = new();

private Variable AssertTarget(Pronoun pronoun)
=> pronounTarget ?? throw new($"You must assign a variable before using a pronoun ('{pronoun.Name}')");
private Variable QualifyPronoun(Variable variable) =>
variable is Pronoun pronoun
? pronounTarget ?? throw new($"You must assign a variable before using a pronoun ('{pronoun.Name}')")
: variable;

public RockstarEnvironment? GetScope(Variable variable) {
return variables.ContainsKey(variable.Key) ? this : Parent?.GetScope(variable);
Expand All @@ -59,7 +54,7 @@ private void SetLocal(Variable variable, Value value)
public Result SetVariable(Variable variable, Value value) {
var scope = GetScope(variable) ?? this;
if (variable is Pronoun pronoun) {
scope.SetLocal(AssertTarget(pronoun), value);
scope.SetLocal(QualifyPronoun(pronoun), value);
} else if (variable.Index != default) {
var index = Eval(variable.Index);
scope.SetArray(variable, index, value);
Expand All @@ -70,11 +65,8 @@ public Result SetVariable(Variable variable, Value value) {
return new(value);
}

//private Value Scalar(Dictionary<Value, Value> array)
// => new Number(1 + array.Keys.Where(k => k is Number).Select(k => Math.Ceiling(((Number) k).Value)).Max());

public Value Lookup(Variable variable) {
var key = (variable is Pronoun pronoun ? AssertTarget(pronoun).Key : variable.Key);
var key = (variable is Pronoun pronoun ? QualifyPronoun(pronoun).Key : variable.Key);
var value = LookupValue(key);
if (variable.Index == default) return value ?? throw new($"Unknown variable '{variable.Name}'");
var index = Eval(variable.Index);
Expand All @@ -85,17 +77,18 @@ public Value Lookup(Variable variable) {
};
}

private Dictionary<Value, Value>? LookupArray(string key)
=> arrays.TryGetValue(key, out var array) ? array : Parent?.LookupArray(key);

private Value? LookupValue(string key)
=> variables.TryGetValue(key, out var value) ? value : Parent?.LookupValue(key);

public Result Exec(Block block) {
var result = Result.Unknown;
foreach (var statement in block.Statements) {
result = Exec(statement);
if (result.WhatToDo == WhatToDo.Return) return result;
switch (result.WhatToDo) {
case WhatToDo.Skip: return result;
case WhatToDo.Break: return result;
case WhatToDo.Return: return result;
}
}
return result;
}
Expand All @@ -112,9 +105,31 @@ public Result Exec(Block block) {
Listen l => Listen(l),
Rounding r => Rounding(r),
Mutation m => Mutation(m),
Enlist e => Enlist(e),
Continue => Result.Continue,
Break => Result.Break,
ExpressionStatement e => new(Eval(e.Expression)),
_ => throw new($"I don't know how to execute {statement.GetType().Name} statements")
};

private Result Delist(Delist delist) {
var key = delist.Variable is Pronoun pronoun ? QualifyPronoun(pronoun).Key : delist.Variable.Key;
var value = LookupValue(key);
if (value is Array array) return new(array.Pop());
return new(new Null());
}

private Result Enlist(Enlist e) {
var key = (e.Variable is Pronoun pronoun ? QualifyPronoun(pronoun).Key :e.Variable.Key);
var value = LookupValue(key);
if (value is not Array array) {
array = value == null ? new Array() : new(value);
SetLocal(e.Variable, array);
}
foreach (var expr in e.Expressions) array.Push(Eval(expr));
return new(array);
}

private Result Mutation(Mutation m)
=> m.Operator switch {
Operator.Join => Join(m),
Expand Down Expand Up @@ -188,27 +203,35 @@ private Result Call(FunctionCall call) {

private Result Loop(Loop loop) {
var result = Result.Unknown;
var condition = Eval(loop.Condition);
while (condition.Truthy == loop.CompareTo) {
while (Eval(loop.Condition).Truthy == loop.CompareTo) {
result = Exec(loop.Body);
condition = Eval(loop.Condition);
switch (result.WhatToDo) {
case WhatToDo.Skip: continue;
case WhatToDo.Break: break;
case WhatToDo.Return:
return result;
}
}
return result;
}

private Result Increment(Increment inc) {
return Eval(inc.Variable) switch {
Number n => Assign(inc.Variable, new Number(n.Value + inc.Multiple)),
Booleän b => inc.Multiple % 2 == 0 ? new(b) : Assign(inc.Variable, b.Negate),
{ } v => throw new($"Cannot increment '{inc.Variable.Name}' because it has type {v.GetType().Name}")
var variable = QualifyPronoun(inc.Variable);
return Eval(variable) switch {
Null n => Assign(variable, new Number(inc.Multiple)),
Number n => Assign(variable, new Number(n.Value + inc.Multiple)),
Booleän b => inc.Multiple % 2 == 0 ? new(b) : Assign(variable, b.Negate),
{ } v => throw new($"Cannot increment '{variable.Name}' because it has type {v.GetType().Name}")
};
}

private Result Decrement(Decrement dec) {
var variable = QualifyPronoun(dec.Variable);
return Eval(dec.Variable) switch {
Number n => Assign(dec.Variable, new Number(n.Value - dec.Multiple)),
Booleän b => dec.Multiple % 2 == 0 ? new(b) : Assign(dec.Variable, b.Negate),
{ } v => throw new($"Cannot increment '{dec.Variable.Name}' because it has type {v.GetType().Name}")
Null n => Assign(variable, new Number(-dec.Multiple)),
Number n => Assign(variable, new Number(n.Value - dec.Multiple)),
Booleän b => dec.Multiple % 2 == 0 ? new(b) : Assign(variable, b.Negate),
{ } v => throw new($"Cannot increment '{variable.Name}' because it has type {v.GetType().Name}")
};
}

Expand Down Expand Up @@ -239,6 +262,7 @@ private Result Output(Output output) {
{ Op: Operator.Not } => Booleän.Not(Eval(u.Expr)),
_ => throw new NotImplementedException($"Cannot apply {u.Op} to {u.Expr}")
},
Delist delist => Delist(delist).Value,
FunctionCall call => Call(call).Value,
_ => throw new NotImplementedException($"Eval not implemented for {expr.GetType()}")
};
Expand Down
5 changes: 5 additions & 0 deletions Starship/Rockstar.Engine/Statements/Break.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Rockstar.Engine.Statements;

public class Break(Source source) : Statement(source) {

}
5 changes: 5 additions & 0 deletions Starship/Rockstar.Engine/Statements/Continue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Rockstar.Engine.Statements;

public class Continue(Source source) : Statement(source) {

}
11 changes: 11 additions & 0 deletions Starship/Rockstar.Engine/Statements/Mutation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Rockstar.Engine.Expressions;

namespace Rockstar.Engine.Statements;

public class Mutation(Operator op, Expression expr, Source source, Variable? target = default, Expression? modifier = default)
: Statement(source) {
public Operator Operator => op;
public Expression Expression => expr;
public Variable? Target => target;
public Expression? Modifier => modifier;
}
7 changes: 7 additions & 0 deletions Starship/Rockstar.Engine/Statements/Round.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Rockstar.Engine.Statements;

public enum Round {
Up,
Down,
Nearest
}
8 changes: 8 additions & 0 deletions Starship/Rockstar.Engine/Statements/Rounding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Rockstar.Engine.Expressions;

namespace Rockstar.Engine.Statements;

public class Rounding(Variable variable, Round round, Source source) : Statement(source) {
public Variable Variable => variable;
public Round Round => round;
}
30 changes: 2 additions & 28 deletions Starship/Rockstar.Engine/Statements/Statement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,9 @@ public Block Concat(IList<Statement> list)

public Block Concat(Statement tail)
=> new Block(new List<Statement> { this }.Concat([ tail ]));

};

public enum Round {
Up,
Down,
Nearest
}

public class Rounding(Variable variable, Round round, Source source) : Statement(source) {
public Variable Variable => variable;
public Round Round => round;
}
public class Mutation(Operator op, Expression expr, Source source, Variable? target = default, Expression? modifier = default)
: Statement(source) {
public Operator Operator => op;
public class ExpressionStatement(Expression expr, Source source) : Statement(source) {
public Expression Expression => expr;
public Variable? Target => target;
public Expression? Modifier => modifier;
}

public class Noop() : Statement(Source.None) {
public static Noop Instance => new Noop();
public override void Print(StringBuilder sb, string prefix) => expr.Print(sb, prefix);
}

public class Break(Source source) : Statement(source) {

}

public class Continue(Source source) : Statement(source) {

}
Loading

0 comments on commit 1d8671f

Please sign in to comment.