diff --git a/Starship/Rockstar.Engine/Expressions/Expression.cs b/Starship/Rockstar.Engine/Expressions/Expression.cs index e2fb427..90d4053 100644 --- a/Starship/Rockstar.Engine/Expressions/Expression.cs +++ b/Starship/Rockstar.Engine/Expressions/Expression.cs @@ -8,4 +8,8 @@ public virtual void Print(StringBuilder sb, string prefix) => sb.Append(prefix).AppendLine(this.GetType().Name.ToLowerInvariant()); protected string Location => source.Location; + + public List Concat(List list) + => new List { this }.Concat(list).ToList(); + } \ No newline at end of file diff --git a/Starship/Rockstar.Engine/Expressions/Variable.cs b/Starship/Rockstar.Engine/Expressions/Variable.cs index f44e1be..47468e5 100644 --- a/Starship/Rockstar.Engine/Expressions/Variable.cs +++ b/Starship/Rockstar.Engine/Expressions/Variable.cs @@ -16,4 +16,7 @@ protected string NormalizedName => String.Join("_", whitespace.Split(Name)); public abstract string Key { get; } + + public List Concat(List list) + => new List { this }.Concat(list).ToList(); } \ No newline at end of file diff --git a/Starship/Rockstar.Engine/Statements/Statement.cs b/Starship/Rockstar.Engine/Statements/Statement.cs index e2677c3..b9eddcf 100644 --- a/Starship/Rockstar.Engine/Statements/Statement.cs +++ b/Starship/Rockstar.Engine/Statements/Statement.cs @@ -1,4 +1,5 @@ using System.Text; +using Rockstar.Engine.Expressions; namespace Rockstar.Engine.Statements; @@ -8,3 +9,23 @@ public abstract class Statement(Source source) { protected string Location => source.Location; } +public class Function(Variable name, IEnumerable args, Block body, Source source) + : Statement(source) { + public override void Print(StringBuilder sb, string prefix = "") { + sb.Append(prefix).Append($"function: {name.Name}("); + sb.Append(String.Join(", ", args.Select(a => a.Name))); + sb.AppendLine(")"); + body.Print(sb, prefix + "|" + INDENT); + } +} + +public class FunctionCall(Variable name, List args, Source source) + : Statement(source) { + public override void Print(StringBuilder sb, string prefix = "") { + sb.Append(prefix).AppendLine($"function call: {name.Name}"); + foreach (var arg in args) { + arg.Print(sb, prefix + INDENT); + } + } +} + diff --git a/Starship/Rockstar.Engine/rockstar.peg b/Starship/Rockstar.Engine/rockstar.peg index 81595f9..4143bcb 100644 --- a/Starship/Rockstar.Engine/rockstar.peg +++ b/Starship/Rockstar.Engine/rockstar.peg @@ -35,9 +35,37 @@ statement = loop / alternate / output_stmt + / function_call + / function / assign_stmt / increment / decrement + + +takes = ('takes' / 'wants') + +function + = name:variable _ takes _ args:variable_list EOS body:statements + { new Function(name, args, body, state.Source()) } + +function_call + = name:variable _ 'taking' _ args:expression_list + { new FunctionCall(name, args, state.Source()) } + +expression_list > + = head:expression _XLS_ tail:expression_list + { head.Concat(tail) } + / expr:expression { new List { expr } } + +_XLS_ + = (_? ', and' _ / _? ('&' / ',' / "'n'") _?) + +_VLS_ = _XLS_ / _ 'and' _ + +variable_list > + = head:variable _VLS_ tail:variable_list + { head.Concat(tail) } + / arg:variable { new List { arg } } noise = (_ / [;,]) diff --git a/Starship/Rockstar.Test/ConditionalTests.cs b/Starship/Rockstar.Test/ConditionalTests.cs index b084d3e..fb9950a 100644 --- a/Starship/Rockstar.Test/ConditionalTests.cs +++ b/Starship/Rockstar.Test/ConditionalTests.cs @@ -2,71 +2,6 @@ namespace Rockstar.Test; -public class LoopTests(ITestOutputHelper output) : ParserTestBase(output) { - [Theory] - [InlineData("while true say loop")] - [InlineData(""" - while true - say loop1 - say loop2 - say loop3 - - say done - """)] - public void ParserParsesLoop(string source) => Parse(source); - - [Theory] - [InlineData(""" - X is 10 - While X is greater than nothing - While Y is less than 3 - Build Y up - Say Y - - Knock X down - - """)] - public void ParserParsesNestedLoop(string source) { - var parsed = Parse(source); - parsed.Statements.Count.ShouldBe(2); - } - - [Fact] - public void WhileLoopWorks() { - var source = """ - let i be 0 - while i is less than 5 - say i - build i up - - say "finished" - """; - var parsed = Parse(source); - var e = new TestEnvironment(); - var i = new Interpreter(e); - var result = i.Exec(parsed); - e.Output.ReplaceLineEndings().ShouldBe("0\n1\n2\n3\n4\nfinished\n".ReplaceLineEndings()); - } - - [Fact] - public void UntilLoopWorks() { - var source = """ - let i be 0 - until i is as great as 5 - say i - build i up - - say "finished" - """; - var parsed = Parse(source); - var e = new TestEnvironment(); - var i = new Interpreter(e); - var result = i.Exec(parsed); - e.Output.ReplaceLineEndings().ShouldBe("0\n1\n2\n3\n4\nfinished\n".ReplaceLineEndings()); - } - -} - public class ConditionalTests(ITestOutputHelper output) { [Theory] [InlineData("if true say 1")] diff --git a/Starship/Rockstar.Test/FunLyricTests.cs b/Starship/Rockstar.Test/FunLyricTests.cs new file mode 100644 index 0000000..0edbe73 --- /dev/null +++ b/Starship/Rockstar.Test/FunLyricTests.cs @@ -0,0 +1,10 @@ +namespace Rockstar.Test; + +public class FunLyricTests(ITestOutputHelper output) : ParserTestBase(output) { + + [Theory] + [InlineData("It's more than a feeling (More than a feeling)")] + [InlineData("If it's more than a feeling (More than a feeling) say yeah")] + public void ParserParsesLyric(string source) + => Parse(source); +} \ No newline at end of file diff --git a/Starship/Rockstar.Test/FunctionTests.cs b/Starship/Rockstar.Test/FunctionTests.cs new file mode 100644 index 0000000..b8d8438 --- /dev/null +++ b/Starship/Rockstar.Test/FunctionTests.cs @@ -0,0 +1,23 @@ +namespace Rockstar.Test; + +public class FunctionTests(ITestOutputHelper output) : ParserTestBase(output) { + [Theory] + [InlineData(""" + Echo takes X + say X + (end function) + """)] + [InlineData("sum taking 2, 3")] + [InlineData(""" + Echo takes X + say X + (end function) + Echo taking true + Echo taking "hello world" + put 5 into Temp + Echo taking Temp + """)] + public void ParserParsesFunctions(string source) { + var result = Parse(source); + } +} \ No newline at end of file diff --git a/Starship/Rockstar.Test/LoopTests.cs b/Starship/Rockstar.Test/LoopTests.cs new file mode 100644 index 0000000..796b35d --- /dev/null +++ b/Starship/Rockstar.Test/LoopTests.cs @@ -0,0 +1,66 @@ +namespace Rockstar.Test; + +public class LoopTests(ITestOutputHelper output) : ParserTestBase(output) { + [Theory] + [InlineData("while true say loop")] + [InlineData(""" + while true + say loop1 + say loop2 + say loop3 + + say done + """)] + public void ParserParsesLoop(string source) => Parse(source); + + [Theory] + [InlineData(""" + X is 10 + While X is greater than nothing + While Y is less than 3 + Build Y up + Say Y + + Knock X down + + """)] + public void ParserParsesNestedLoop(string source) { + var parsed = Parse(source); + parsed.Statements.Count.ShouldBe(2); + } + + [Fact] + public void WhileLoopWorks() { + var source = """ + let i be 0 + while i is less than 5 + say i + build i up + + say "finished" + """; + var parsed = Parse(source); + var e = new TestEnvironment(); + var i = new Interpreter(e); + var result = i.Exec(parsed); + e.Output.ReplaceLineEndings().ShouldBe("0\n1\n2\n3\n4\nfinished\n".ReplaceLineEndings()); + } + + [Fact] + public void UntilLoopWorks() { + var source = """ + let i be 0 + until i is as great as 5 + say i + build i up + + say "finished" + """; + var parsed = Parse(source); + var e = new TestEnvironment(); + var i = new Interpreter(e); + var result = i.Exec(parsed); + e.Output.ReplaceLineEndings().ShouldBe("0\n1\n2\n3\n4\nfinished\n".ReplaceLineEndings()); + } + +} \ No newline at end of file diff --git a/Starship/Rockstar.Test/ParserTestBase.cs b/Starship/Rockstar.Test/ParserTestBase.cs index ea791eb..b77f4cb 100644 --- a/Starship/Rockstar.Test/ParserTestBase.cs +++ b/Starship/Rockstar.Test/ParserTestBase.cs @@ -9,13 +9,4 @@ protected Block Parse(string source) { output.WriteLine(result.ToString()); return result; } -} - -public class FunLyricTests(ITestOutputHelper output) : ParserTestBase(output) { - - [Theory] - [InlineData("It's more than a feeling (More than a feeling)")] - [InlineData("If it's more than a feeling (More than a feeling) say yeah")] - public void ParserParsesLyric(string source) - => Parse(source); } \ No newline at end of file diff --git a/Starship/Rockstar.Test/Rockstar.Test.v3.ncrunchproject b/Starship/Rockstar.Test/Rockstar.Test.v3.ncrunchproject index a3525f7..25b1bf2 100644 --- a/Starship/Rockstar.Test/Rockstar.Test.v3.ncrunchproject +++ b/Starship/Rockstar.Test/Rockstar.Test.v3.ncrunchproject @@ -5,9 +5,6 @@ Rockstar.Test.FixturePreTests - - Rockstar.Test.FixtureTests - \ No newline at end of file