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

Commit

Permalink
Poetic literals (integers) are working.
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanbeattie committed Jul 6, 2024
1 parent 780c833 commit af16141
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 36 deletions.
22 changes: 11 additions & 11 deletions .obsidian/workspace.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,17 @@
},
"active": "af9edaf1541aa592",
"lastOpenFiles": [
"Starship/Rockstar.Test/obj/Debug/net8.0/nCrunchTemp_511cc3bb-5125-4e86-9e1b-af622834b219.csproj.AssemblyReference.cache",
"Starship/Rockstar.Test/obj/Debug/net8.0/nCrunchTemp_511cc3bb-5125-4e86-9e1b-af622834b219.GlobalUsings.g.cs",
"Starship/Rockstar.Test/obj/Debug/net8.0/nCrunchTemp_511cc3bb-5125-4e86-9e1b-af622834b219.assets.cache",
"Starship/Rockstar.Test/nCrunchTemp_511cc3bb-5125-4e86-9e1b-af622834b219.csproj",
"Starship/Rockstar.Test/obj/nCrunchTemp_511cc3bb-5125-4e86-9e1b-af622834b219.csproj.nuget.g.targets",
"Starship/Rockstar.Test/obj/nCrunchTemp_511cc3bb-5125-4e86-9e1b-af622834b219.csproj.nuget.g.props",
"Starship/Rockstar.Engine/rockstar.peg~RF19ed0814.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF19eacad6.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF19e8e3c6.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF19e7b067.TMP",
"Starship/Rockstar.Test/ParserTests.cs~RF19e07a84.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF1ac18bc3.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF1ac1496b.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF1ac093a8.TMP",
"Starship/Rockstar.Wasm/bin/Debug/net8.0/wwwroot/_framework/Rockstar.Engine.wasm.gz",
"Starship/Rockstar.Wasm/bin/Debug/net8.0/wwwroot/_framework/Rockstar.Engine.pdb.gz",
"Starship/Rockstar.Wasm/obj/Debug/net8.0/webcil/System.Configuration.wasm",
"Starship/Rockstar.Wasm/obj/Debug/net8.0/webcil/System.ComponentModel.wasm",
"Starship/Rockstar.Wasm/obj/Debug/net8.0/webcil/System.Data.DataSetExtensions.wasm",
"Starship/Rockstar.Engine/rockstar.peg~RF1abbe124.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF1abbd29d.TMP",
"Starship/Rockstar.Engine/rockstar.peg~RF1abab3df.TMP",
"codewithrockstar.com/getting-started.md",
"codewithrockstar.com/index copy.md"
]
Expand Down
6 changes: 6 additions & 0 deletions Starship/Rockstar.Engine/Expressions/Variable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ protected string NormalizedName
public abstract string Key { get; }
}

public class Pronoun(string name, Source source) : Variable(name, source) {
public Pronoun() : this(String.Empty) { }
public Pronoun(string name) : this(name, Source.None) { }
public override string Key => Name.ToLowerInvariant();
}

public class SimpleVariable(string name, Source source) : Variable(name, source) {
public SimpleVariable(string name) : this(name, Source.None) { }
public override string Key => Name.ToLowerInvariant();
Expand Down
2 changes: 1 addition & 1 deletion Starship/Rockstar.Engine/Interpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public int Run(Progräm program) {
};

private Result Assign(Assign assign) {
env.SetVariable(assign.Name, Eval(assign.Expr));
env.SetVariable(assign.Variable, Eval(assign.Expr));
return Result.Ok;
}

Expand Down
18 changes: 16 additions & 2 deletions Starship/Rockstar.Engine/RockstarEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,25 @@ public abstract class RockstarEnvironment {
public abstract string? ReadInput();
public abstract void WriteLine(string? output);
public abstract void Write(string s);
private Variable? pronounTarget;

private readonly Dictionary<string, Value> variables = new();
public void SetVariable(Variable variable, Value value) => variables[variable.Key] = value;

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

public void SetVariable(Variable variable, Value value) {
pronounTarget = variable;
variables[variable.Key] = value;
}

public void SetVariable(Pronoun pronoun, Value value)
=> SetVariable(AssertTarget(pronoun), value);

public Value GetVariable(Pronoun pronoun)
=> GetVariable(AssertTarget(pronoun));

public Value GetVariable(Variable variable) =>
variables.TryGetValue(variable.Key, out var value) ? value : throw new Exception($"Unknown variable '{variable.Name}'");
variables.TryGetValue(variable.Key, out var value) ? value : throw new($"Unknown variable '{variable.Name}'");

}
6 changes: 3 additions & 3 deletions Starship/Rockstar.Engine/Statements/Assign.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

namespace Rockstar.Engine.Statements;

public class Assign(Variable name, Expression expr, Source source)
public class Assign(Variable variable, Expression expr, Source source)
: Statement(source) {
public Variable Name => name;
public Variable Variable => variable;
public Expression Expr => expr;
public override void Print(StringBuilder sb, int depth) {
sb.Indent(depth).AppendLine($"assign:");
name.Print(sb, depth + 1);
variable.Print(sb, depth + 1);
expr.Print(sb, depth + 1);
}
}
1 change: 1 addition & 0 deletions Starship/Rockstar.Engine/Values/Null.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ namespace Rockstar.Engine.Values;

public class Null(Source source)
: Value(source) {
public Null() : this(Source.None) { }
public override bool Truthy => false;
}
6 changes: 6 additions & 0 deletions Starship/Rockstar.Engine/Values/Number.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ namespace Rockstar.Engine.Values;

public class Number(decimal value, Source source)
: Value(source) {

public Number(string s) : this(Decimal.Parse(s)) { }

public Number(string s, Source source) : this(Decimal.Parse(s), source) { }

public Number(decimal value) : this(value, Source.None) { }

public decimal Value => value;
public override string ToString()
=> value.ToString(CultureInfo.InvariantCulture);
Expand Down
52 changes: 34 additions & 18 deletions Starship/Rockstar.Engine/rockstar.peg
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@

@ignorecase true

// Ok, so a program is:
// Whitespace followed by EOF. Empty program.
// A single statement followed by an empty program

program <Progräm>
= ("" _ / EOL)+ p:program
{ p }
Expand All @@ -37,41 +33,58 @@ comment
/ '{' [^\}]* '}'
/ '[' [^\]]* ']'


statement <Statement>
= output_stmt
/ assign_stmt

assign_stmt <Statement>
= 'let' _ v:variable _ 'be' _ e:expression
{ new Assign(v, e, state.Source()) }
/ v:variable _ 'says' _ s:("" [^\r\n]*)
/ 'put' _ e:expression _ 'into' _ v:variable
{ new Assign(v, e, state.Source()) }
/ v:variable _ says _ s:("" [^\r\n]*)
{ new Assign(v, new Strïng(s, state.Source(s)), state.Source()) }
// / v:variable _ "was a lovestruck ladykiller"
// { new Assign(v, new Number(100), state.Source()) }
/ v:variable _is _ l:literal
/ v:variable _is _ l:(literal / poetic_literal)
{ new Assign(v, l, state.Source()) }

//TODO: reinstate for 2.0
// v:variable _is _ e:expression { new Assign(v, e, state.Source()) }

says = ('says' / 'say' / 'said')

poetic_literal <Number>
= head:poetic_digit _ tail:poetic_digits
{ new Number(head + tail) }
/ d:poetic_digit { new Number(d) }

poetic_digits <string>
= head:poetic_digit _ tail:poetic_digits
{ head + tail }
/ d:poetic_digit { d }

poetic_digit <string>
= word:("" [A-Za-z\-']+)
{ (word.Length % 10).ToString() }

output_stmt <Statement>
= output _ e:expression { new Output(e, state.Source()) }

variable <Variable>
= name:variable_name
= p:pronoun { new Pronoun(p, state.Source(p)) }
/ n:common_variable { new CommonVariable(n, state.Source(n)) }
/ n:proper_variable { new ProperVariable(n, state.Source(n)) }
/ n:simple_variable { new SimpleVariable(n, state.Source(n)) }

variable_name <Variable>
= name:common_variable { new CommonVariable(name, state.Source(name)) }
/ name:proper_variable { new ProperVariable(name, state.Source(name)) }
/ name:simple_variable { new SimpleVariable(name, state.Source(name)) }
pronoun
= p:( 'they' / 'them' )

proper_variable // e.g. Big Bad Benny
= proper_noun (_ proper_noun)*

proper_noun
= uppercase_letter letter*
= !keyword uppercase_letter letter*

keyword = 'is'

common_variable
= common_prefix _ simple_variable
Expand Down Expand Up @@ -145,11 +158,13 @@ _eq
/ _is

_is <Operator>
= ("'s" / "'re" / _ ('=' / 'is' / 'was' / 'are' / 'were')) !letter
= ("'s" / "'re" / _ ('=' / is)) !letter
{ Operator.Equals }

is = 'is' / 'was' / 'are' / 'were'

_is_not <Operator>
= _ ('!=' / "'s" _ "not" / 'is' _ 'not' / "isnt" / "isn't" / 'aint' / "ain't" / "wasn't" / "wasnt" / "aren't" / "arent" / "weren't" / "werent") !letter
= _ ('!=' / _is _ "not" / "isnt" / "isn't" / 'aint' / "ain't" / "wasn't" / "wasnt" / "aren't" / "arent" / "weren't" / "werent") !letter
{ Operator.NotEquals }

math <Expression>
Expand All @@ -173,7 +188,8 @@ primary <Expression>
/ lookup

lookup <Expression>
= v:variable { new Looküp(v, state.Source()) }
= v:variable
{ new Looküp(v, state.Source()) }

literal <Expression>
= constant
Expand Down
59 changes: 59 additions & 0 deletions Starship/Rockstar.Test/PronounTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Rockstar.Engine.Expressions;

namespace Rockstar.Test;

public class PronounTests {

private void TestPronoun(Variable variable, Value value) {
var e = new TestEnvironment();
var pronoun = new Pronoun();
e.SetVariable(variable, value);
var result = e.GetVariable(pronoun) as Number;
result.ShouldBe(value);
}


[Fact]
public void AssigningProperVariableSetsPronoun()
=> TestPronoun(new ProperVariable("Doctor Feelgood"), new Number(123));

[Fact]
public void AssigningSimpleVariableSetsPronoun()
=> TestPronoun(new SimpleVariable("Doctor Feelgood"), new Number(123));

[Fact]
public void AssigningCommonVariableSetsPronoun()
=> TestPronoun(new CommonVariable("Doctor Feelgood"), new Number(123));

[Fact]
public void LookupPronounWithoutAssigningVariableThrowsException() {
var e = new TestEnvironment();
Should.Throw<Exception>(() => e.GetVariable(new("him")));
}

[Fact]
public void AssignPronounWithoutAssigningVariableThrowsException() {
var e = new TestEnvironment();
Should.Throw<Exception>(() => e.SetVariable(new("him"), new Number(123)));
}

private void AssignPronounAfterAssigningVariableUpdatesVariable(Variable variable, Value value) {
var e = new TestEnvironment();
e.SetVariable(variable, new Null());
e.SetVariable(new(), value);
e.GetVariable(variable).ShouldBe(value);
}

[Fact]
public void AssignPronounAfterAssigningProperVariableUpdatesVariable()
=> AssignPronounAfterAssigningVariableUpdatesVariable(new ProperVariable("Mr Crowley"), new Strïng("hey"));

[Fact]
public void AssignPronounAfterAssigningSimpleVariableUpdatesVariable()
=> AssignPronounAfterAssigningVariableUpdatesVariable(new SimpleVariable("crowley"), new Strïng("hey"));

[Fact]
public void AssignPronounAfterAssigningCommonVariableUpdatesVariable()
=> AssignPronounAfterAssigningVariableUpdatesVariable(new CommonVariable("my humps"), new Strïng("my lady humps"));

}
44 changes: 43 additions & 1 deletion Starship/Rockstar.Test/VariableTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Runtime.InteropServices;
using Pegasus.Common.Tracing;
using Rockstar.Engine.Expressions;

Expand All @@ -9,6 +8,10 @@ public class LiteralTests {
[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)]
public void PoeticLiteralAssignsCorrectValue(string source, decimal value) {
var parser = new Parser() {
Tracer = DiagnosticsTracer.Instance
Expand Down Expand Up @@ -52,4 +55,43 @@ public void ProperVariablesAreCaseInsensitiveAndIgnoreWhitespace(string name1, s
var b = new ProperVariable(name2);
a.Key.ShouldBe(b.Key);
}

[Theory]
[InlineData("Variable Is 5")]
[InlineData("""
variable is 1
say variable
""")]
[InlineData("""
variable is 1
say variable
variable iS 3
say variable
VARIABLE is 4
say variable
""")]
[InlineData("""
variable is 1
say variable
variable iS 3
say variable
VARIABLE IS 4
say variable
""")]
[InlineData("""
variable is 1
say variable
Variable Is 2
say variable
variable iS 3
say variable
VARIABLE IS 4
say variable
""")]
public void LiteralAssignmentsAreCaseInsensitive(string source) {
var parser = new Parser() {
Tracer = DiagnosticsTracer.Instance
};
var result = parser.Parse(source);
}
}

0 comments on commit af16141

Please sign in to comment.