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

Commit

Permalink
Compound assignments (let x be with 5) are working.
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanbeattie committed Jul 9, 2024
1 parent a10f784 commit d330694
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 87 deletions.
3 changes: 2 additions & 1 deletion Starship/Rockstar.Engine/Expressions/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ public Value Resolve(Func<Expression, Value> eval) {
Operator.Minus => v.Minus(eval(rhs)),
Operator.Times => v.Times(eval(rhs)),
Operator.Divide => v.Divide(eval(rhs)),

Operator.Equals => v.Equäls(eval(rhs)),
Operator.NotEquals => v.NotEquäls(eval(rhs)),
Operator.Nor => v.Divide(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.And => v.Truthy ? eval(rhs) : v,
Operator.Or => v.Truthy ? v : eval(rhs),
_ => throw new ArgumentOutOfRangeException(nameof(op), op, null)
Expand Down
11 changes: 7 additions & 4 deletions Starship/Rockstar.Engine/Values/Value.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public override void Print(StringBuilder sb, int depth)
_ => that switch {
Booleän booleän => this.Truthy == booleän.Truthy,
Strïng s => s.Value.Equals(this.ToStrïng().Value),
_ => throw new NotImplementedException($"Equality not implemented for {this.GetType()} {that.GetType()}")
_ => throw Boom(nameof(Equäls), this, that)
},
});

Expand All @@ -85,16 +85,19 @@ public Value NotEquäls(Value that)

public Value LessThanEqual(Value that) => (Booleän) ((this, that) switch {
(Number a, Number b) => a.Value <= b.Value,
_ => throw new NotImplementedException()
_ => throw Boom(nameof(LessThanEqual), this, that)
});

public Value MoreThanEqual(Value that) => (Booleän) ((this, that) switch {
(Number a, Number b) => a.Value >= b.Value,
_ => throw new NotImplementedException()
_ => throw Boom(nameof(MoreThanEqual), this, that)
});

public Value LessThan(Value that) => (Booleän) ((this, that) switch {
(Number a, Number b) => a.Value < b.Value,
_ => throw new NotImplementedException()
_ => throw Boom(nameof(LessThan), this, that)
});

private Exception Boom(string op, Value lhs, Value rhs)
=> new NotImplementedException($"{op} not implemented for {lhs.GetType()} {rhs.GetType()}");
}
32 changes: 19 additions & 13 deletions Starship/Rockstar.Engine/rockstar.peg
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ bonglit <Block>
assign_stmt <Statement>
= 'put' _ e:expression _ 'into' _ v:variable
{ new Assign(v, e, state.Source()) }
/ 'let' _ v:variable _ 'be' o:_op_ e:expression
{ new Assign(v, new Binary(o, new Looküp(v, state.Source()), e, state.Source()), state.Source()) }
/ 'let' _ v:variable _ 'be' _ e:expression
{ new Assign(v, e, state.Source()) }
/ v:variable _ says _ s:("" [^\r\n]*)
Expand Down Expand Up @@ -126,7 +128,7 @@ proper_variable // e.g. Big Bad Benny
proper_noun
= !keyword uppercase_letter letter*

keyword = (is / common_prefix / pronoun / 'let') !letter
keyword = (is / common_prefix / pronoun / 'let' / 'with') !letter

common_variable
= common_prefix _ simple_variable
Expand All @@ -135,7 +137,7 @@ common_prefix
= ('an' / 'a' / 'the' / 'my' / 'your' / 'our') !letter

simple_variable
= ("" letter+)
= !keyword ("" letter+)

letter
= uppercase_letter / lowercase_letter
Expand Down Expand Up @@ -213,17 +215,20 @@ math <Expression>
= sum

sum <Expression> -memoize
= lhs:sum op:(plus/minus) rhs:product { new Binary(op, lhs, rhs, state.Source()) }
= lhs:sum op:(_plus_/_minus_) rhs:product { new Binary(op, lhs, rhs, state.Source()) }
/ product

product <Expression> -memoize
= lhs:product op:(times/divide) rhs:primary { new Binary(op, lhs, rhs, state.Source()) }
= lhs:product op:(_times_/_divide_) rhs:primary { new Binary(op, lhs, rhs, state.Source()) }
/ primary

plus <Operator> = (_? '+' _? / _ 'plus' _ / _ 'with' _ ) { Operator.Plus }
minus <Operator> = (_? '-' _? / _ 'minus' _ / _ 'without' _ ) { Operator.Minus }
times <Operator> = (_? '*' _? / _ 'times' _ / _ 'of' _ ) { Operator.Times }
divide <Operator> = (_? '/' _? / _ 'over' _ / _ 'between' _ ) { Operator.Divide }
_plus_ <Operator> = (_? '+' _? / _ 'plus' _ / _ 'with' _ ) { Operator.Plus }
_minus_ <Operator> = (_? '-' _? / _ 'minus' _ / _ 'without' _ ) { Operator.Minus }
_times_ <Operator> = (_? '*' _? / _ 'times' _ / _ 'of' _ ) { Operator.Times }
_divide_ <Operator> = (_? '/' _? / _ 'over' _ / _ 'between' _ ) { Operator.Divide }

_op_ <Operator>
= _plus_ / _minus_ / _times_ / _divide_

primary <Expression>
= literal
Expand Down Expand Up @@ -255,15 +260,16 @@ string <Strïng>
= '"' contents:("" [^"]*) '"' { new Strïng(contents, state.Source(contents)) }

number <Number>
= digits:([0-9]+ ("." [0-9]+)?) { new Number(Decimal.Parse(digits), state.Source(digits) ) }
/ digits:("." [0-9]+) { new Number(Decimal.Parse(digits), state.Source(digits) ) }
= digits:('-'? [0-9]+ ("." [0-9]+)?) { new Number(Decimal.Parse(digits), state.Source(digits) ) }
/ digits:('-'? "." [0-9]+) { new Number(Decimal.Parse(digits), state.Source(digits) ) }

unary_op <Operator>
= not { Operator.Not }
/ minus { Operator.Minus }
/ _minus_ { Operator.Minus }

output = "shout" / "say" / "scream" / "whisper"
output
= "shout" / "say" / "scream" / "whisper"

_ = "" (whitespace / comment)+
whitespace = [ \t]
comment = '(' [^)]* ')' / '{' [^\}]* '}' / '[' [^\]]* ']'
comment = '(' [^)]* ')' / '{' [^\}]* '}' / '[' [^\]]* ']'
11 changes: 11 additions & 0 deletions Starship/Rockstar.Test/CompoundAssignmentTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Rockstar.Test;

public class CompoundAssignmentTests(ITestOutputHelper output) : ParserTestBase(output) {
[Theory]
[InlineData("let x be with 5")]
[InlineData("let x be without 5")]
[InlineData("let x be over 2")]
[InlineData("let the night be without regret")]
public void ParserParsesSimpleConditionals(string source)
=> Parse(source);
}
15 changes: 0 additions & 15 deletions Starship/Rockstar.Test/ConditionalTests.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
namespace Rockstar.Test;

public class IncrementDecrementTests(ITestOutputHelper output) {
[Theory]
[InlineData("build X up")]
[InlineData("build X up up")]
[InlineData("build X up, up")]
[InlineData("knock X down")]
[InlineData("knock X down, down, down")]
[InlineData("knock X down down down")]
public void ParserParsesIncrementsAndDecrements(string source) {
var parser = new Parser(); // { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
output.WriteLine(result.ToString());
}
}

public class ConditionalTests(ITestOutputHelper output) {
[Theory]
[InlineData("if true say 1")]
Expand Down
13 changes: 0 additions & 13 deletions Starship/Rockstar.Test/FixtureBase.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
namespace Rockstar.Test;

public class TestEnvironment : RockstarEnvironment {

private readonly StringBuilder outputStringBuilder = new();
public string Output => outputStringBuilder.ToString();
public override string? ReadInput() => null;

public override void WriteLine(string output)
=> this.outputStringBuilder.Append(output + Environment.NewLine);

public override void Write(string s)
=> this.outputStringBuilder.Append(s);
}

public abstract class FixtureBase(ITestOutputHelper testOutput) {

private static string[] excludes = []; // ["arrays", "conditionals", "control-flow", "examples"];
Expand Down
16 changes: 16 additions & 0 deletions Starship/Rockstar.Test/IncrementDecrementTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Rockstar.Test;

public class IncrementDecrementTests(ITestOutputHelper output) {
[Theory]
[InlineData("build X up")]
[InlineData("build X up up")]
[InlineData("build X up, up")]
[InlineData("knock X down")]
[InlineData("knock X down, down, down")]
[InlineData("knock X down down down")]
public void ParserParsesIncrementsAndDecrements(string source) {
var parser = new Parser(); // { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
output.WriteLine(result.ToString());
}
}
30 changes: 30 additions & 0 deletions Starship/Rockstar.Test/LiteralTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Pegasus.Common.Tracing;

namespace Rockstar.Test;

public class LiteralTests {
[Theory]
[InlineData("say 1")]
[InlineData("say 1.1")]
[InlineData("say .1")]
public void ParserParsesNumberLiterals(string source) {
var parser = new Parser() { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
result.Statements.Count.ShouldBe(1);
}

[Theory]
[InlineData("the sky is crying", 6)]
[InlineData("Tommy was a lovestruck ladykiller", 100)]
[InlineData("Tommy was a", 1)]
[InlineData("Tommy was a aa", 12)]
[InlineData("Tommy was a aa aaa", 123)]
[InlineData("Tommy was a aa aaa aaaa aaaaa", 12345)]
[InlineData("Tommy was a. aa aaa aaaa", 1.234)]
[InlineData("Tommy was a aa. aaa aaaa", 12.34)]
public void PoeticLiteralAssignsCorrectValue(string source, decimal value) {
var parser = new Parser() { Tracer = DiagnosticsTracer.Instance };
var assign = parser.Parse(source).Statements[0] as Assign;
((Number) assign.Expr).Value.ShouldBe(value);
}
}
14 changes: 14 additions & 0 deletions Starship/Rockstar.Test/OperatorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Pegasus.Common.Tracing;

namespace Rockstar.Test;

public class OperatorTests {
[Theory]
[InlineData("say 1 + 2 + 3")]
[InlineData("say 1 plus 2 plus 3")]
[InlineData("say \"hello\" plus \" \" plus .11")]
public void AdditionOperatorWorks(string source) {
var parser = new Parser() { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
}
}
10 changes: 10 additions & 0 deletions Starship/Rockstar.Test/ParserTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Rockstar.Test;

public class ParserTestBase(ITestOutputHelper output) {
protected void Parse(string source) {
var parser = new Parser(); // { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
output.WriteLine(result.ToString());
}

}
2 changes: 0 additions & 2 deletions Starship/Rockstar.Test/ParserTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.ComponentModel.Design;
using System.Diagnostics;
using Pegasus.Common.Tracing;

namespace Rockstar.Test;
Expand Down
1 change: 0 additions & 1 deletion Starship/Rockstar.Test/PronounTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Diagnostics;
using Pegasus.Common.Tracing;
using Rockstar.Engine.Expressions;

Expand Down
14 changes: 14 additions & 0 deletions Starship/Rockstar.Test/TestEnvironment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Rockstar.Test;

public class TestEnvironment : RockstarEnvironment {

private readonly StringBuilder outputStringBuilder = new();
public string Output => outputStringBuilder.ToString();
public override string? ReadInput() => null;

public override void WriteLine(string output)
=> this.outputStringBuilder.Append(output + Environment.NewLine);

public override void Write(string s)
=> this.outputStringBuilder.Append(s);
}
38 changes: 0 additions & 38 deletions Starship/Rockstar.Test/VariableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,6 @@

namespace Rockstar.Test;

public class OperatorTests {
[Theory]
[InlineData("say 1 + 2 + 3")]
[InlineData("say 1 plus 2 plus 3")]
[InlineData("say \"hello\" plus \" \" plus .11")]
public void AdditionOperatorWorks(string source) {
var parser = new Parser() { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
}
}

public class LiteralTests {
[Theory]
[InlineData("say 1")]
[InlineData("say 1.1")]
[InlineData("say .1")]
public void ParserParsesNumberLiterals(string source) {
var parser = new Parser() { Tracer = DiagnosticsTracer.Instance };
var result = parser.Parse(source);
result.Statements.Count.ShouldBe(1);
}

[Theory]
[InlineData("the sky is crying", 6)]
[InlineData("Tommy was a lovestruck ladykiller", 100)]
[InlineData("Tommy was a", 1)]
[InlineData("Tommy was a aa", 12)]
[InlineData("Tommy was a aa aaa", 123)]
[InlineData("Tommy was a aa aaa aaaa aaaaa", 12345)]
[InlineData("Tommy was a. aa aaa aaaa", 1.234)]
[InlineData("Tommy was a aa. aaa aaaa", 12.34)]
public void PoeticLiteralAssignsCorrectValue(string source, decimal value) {
var parser = new Parser() { Tracer = DiagnosticsTracer.Instance };
var assign = parser.Parse(source).Statements[0] as Assign;
((Number) assign.Expr).Value.ShouldBe(value);
}
}

public class VariableTests {
[Theory]
[InlineData("a variable", "a variable")]
Expand Down

0 comments on commit d330694

Please sign in to comment.