From f8b7fe59ba76181e4ef6ce945d06960460943e95 Mon Sep 17 00:00:00 2001 From: Martin Evans Date: Sat, 7 Nov 2020 22:01:14 +0000 Subject: [PATCH] - Added support for `eval(expr)` to evaluate constant expressions to a value - renamed `lol` files to `yasm` - Added some extra utilities to `lib.yasm` --- YololAssembler/Grammar/AST/BaseDefine.cs | 26 ++++++++++++- YololAssembler/Grammar/AST/EvalReplacement.cs | 38 +++++++++++++++++++ YololAssembler/Grammar/AST/FindAndReplace.cs | 11 +++--- YololAssembler/Grammar/AST/FunctionDefine.cs | 18 +++------ YololAssembler/Grammar/AST/Program.cs | 5 ++- .../Grammar/Errors/CannotParseEval.cs | 16 ++++++++ YololAssembler/Grammar/Errors/EvalNotConst.cs | 14 +++++++ .../PublishProfiles/FolderProfile.pubxml | 14 +++++++ .../Scripts/{hanoi.lol => hanoi.yasm} | 2 +- YololAssembler/Scripts/lib.lol | 6 --- YololAssembler/Scripts/lib.yasm | 13 +++++++ .../{test.yasm => run_length_encoding.yasm} | 4 +- YololAssembler/Scripts/test.yolol | 7 ---- YololAssembler/YololAssembler.csproj | 4 +- 14 files changed, 140 insertions(+), 38 deletions(-) create mode 100644 YololAssembler/Grammar/AST/EvalReplacement.cs create mode 100644 YololAssembler/Grammar/Errors/CannotParseEval.cs create mode 100644 YololAssembler/Grammar/Errors/EvalNotConst.cs create mode 100644 YololAssembler/Properties/PublishProfiles/FolderProfile.pubxml rename YololAssembler/Scripts/{hanoi.lol => hanoi.yasm} (99%) delete mode 100644 YololAssembler/Scripts/lib.lol create mode 100644 YololAssembler/Scripts/lib.yasm rename YololAssembler/Scripts/{test.yasm => run_length_encoding.yasm} (90%) delete mode 100644 YololAssembler/Scripts/test.yolol diff --git a/YololAssembler/Grammar/AST/BaseDefine.cs b/YololAssembler/Grammar/AST/BaseDefine.cs index ebacdd3..32165da 100644 --- a/YololAssembler/Grammar/AST/BaseDefine.cs +++ b/YololAssembler/Grammar/AST/BaseDefine.cs @@ -1,12 +1,36 @@ using System.Collections.Generic; +using System.Text.RegularExpressions; namespace YololAssembler.Grammar.AST { internal abstract class BaseDefine : BaseStatement { - public abstract string Apply(string input); + public string Apply(string input) + { + var match = Regex.Match(input, FindRegex); + if (!match.Success) + return input; + + var r = Replace(match.Groups["body"].Value); + r = Other.Trim(r); + + var v = input.Substring(0, match.Index) + + r + + input.Substring(0 + match.Index + match.Length); + return v; + } + + protected abstract string FindRegex { get; } + + protected abstract string Replace(string part); + /// + /// Apply a set of defines repeatedly until fixpoint + /// + /// + /// + /// internal static string Apply(string block, IEnumerable defines) { var changed = true; diff --git a/YololAssembler/Grammar/AST/EvalReplacement.cs b/YololAssembler/Grammar/AST/EvalReplacement.cs new file mode 100644 index 0000000..65b534e --- /dev/null +++ b/YololAssembler/Grammar/AST/EvalReplacement.cs @@ -0,0 +1,38 @@ +using System; +using Yolol.Execution.Extensions; +using YololAssembler.Grammar.Errors; + +namespace YololAssembler.Grammar.AST +{ + internal class EvalReplacement + : BaseDefine + { + protected override string FindRegex => $"eval\\((?.*?)\\)"; + + protected override string Replace(string part) + { + // Convert the floating expression into a statement assigning a variable; + const string name = "_95efe616"; + var stmtCode = $"{name}={part}"; + + // Try to parse this tiny little program + var parsed = Yolol.Grammar.Parser.ParseProgram(stmtCode); + if (!parsed.IsOk) + throw new CannotParseEval(part, parsed.Err); + + // Get the parsed expression back out + var stmt = (Yolol.Grammar.AST.Statements.Assignment)parsed.Ok.Lines[0].Statements.Statements[0]; + var expr = stmt.Right; + + if (!expr.IsConstant) + throw new EvalNotConst(expr); + + var v = expr.StaticEvaluate(); + + if (v.Type == Yolol.Execution.Type.Number) + return v.ToString(); + else + return $"\"{v}\""; + } + } +} diff --git a/YololAssembler/Grammar/AST/FindAndReplace.cs b/YololAssembler/Grammar/AST/FindAndReplace.cs index 0e7df16..5c02126 100644 --- a/YololAssembler/Grammar/AST/FindAndReplace.cs +++ b/YololAssembler/Grammar/AST/FindAndReplace.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace YololAssembler.Grammar.AST +namespace YololAssembler.Grammar.AST { internal class FindAndReplace : BaseDefine @@ -14,10 +12,11 @@ public FindAndReplace(string identifier, string replacement) Replacement = replacement; } - public override string Apply(string input) + protected override string FindRegex => $"(?{Identifier})"; + + protected override string Replace(string part) { - var replacement = Other.Trim(Replacement); - return input.Replace($"{Identifier}", replacement); + return Replacement; } } } diff --git a/YololAssembler/Grammar/AST/FunctionDefine.cs b/YololAssembler/Grammar/AST/FunctionDefine.cs index bfb0242..7a6525a 100644 --- a/YololAssembler/Grammar/AST/FunctionDefine.cs +++ b/YololAssembler/Grammar/AST/FunctionDefine.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; namespace YololAssembler.Grammar.AST { @@ -19,13 +18,11 @@ public FunctionDefine(string identifier, IReadOnlyList arguments, string Arguments = arguments; } - public override string Apply(string input) - { - var match = Regex.Match(input, $"{Identifier}\\((.*?)\\)"); - if (!match.Success) - return input; + protected override string FindRegex => $"{Identifier}\\((?.*?)\\)"; - var parameters = match.Groups[1].Value.Split(",").Where(a => !string.IsNullOrEmpty(a)).ToArray(); + protected override string Replace(string part) + { + var parameters = part.Split(",").Where(a => !string.IsNullOrEmpty(a)).ToArray(); if (parameters.Length != Arguments.Count) throw new InvalidOperationException($"Incorrect number of arguments passed to function `{Identifier}` (expected {Arguments.Count}, got {parameters.Length})"); @@ -41,12 +38,9 @@ public override string Apply(string input) } var replacement = Other.Trim(Replacement); - var replaced = BaseDefine.Apply(replacement, defines); + var replaced = Apply(replacement, defines); - var v = input.Substring(0, match.Index) - + replaced - + input.Substring(0 + match.Index + match.Length); - return v; + return replaced; } } } diff --git a/YololAssembler/Grammar/AST/Program.cs b/YololAssembler/Grammar/AST/Program.cs index ac1cb8b..000f6c3 100644 --- a/YololAssembler/Grammar/AST/Program.cs +++ b/YololAssembler/Grammar/AST/Program.cs @@ -28,6 +28,9 @@ public Result Compile(bool compress = true) // Replace implicit line labels lines = ApplyImplicitLabels(lines).ToArray(); + // Run all `eval` replacements + lines = Apply(new[] { new EvalReplacement() }, lines).ToArray(); + // Early out if compression should not be applied var yolol = string.Join("\n", lines); if (!compress) @@ -42,7 +45,7 @@ public Result Compile(bool compress = true) return new Result(Compress(parsedYolol.Ok)); } - private IEnumerable ApplyImplicitLabels(IEnumerable lines) + private static IEnumerable ApplyImplicitLabels(IEnumerable lines) { var lineNum = 1; foreach (var line in lines) diff --git a/YololAssembler/Grammar/Errors/CannotParseEval.cs b/YololAssembler/Grammar/Errors/CannotParseEval.cs new file mode 100644 index 0000000..f341bd6 --- /dev/null +++ b/YololAssembler/Grammar/Errors/CannotParseEval.cs @@ -0,0 +1,16 @@ +namespace YololAssembler.Grammar.Errors +{ + public class CannotParseEval + : BaseCompileException + { + public string Expression { get; } + public Yolol.Grammar.Parser.ParseError ParseError { get; } + + public CannotParseEval(string expression, Yolol.Grammar.Parser.ParseError parseError) + : base($"Cannot parse expression pass to eval `{expression}`.") + { + Expression = expression; + ParseError = parseError; + } + } +} diff --git a/YololAssembler/Grammar/Errors/EvalNotConst.cs b/YololAssembler/Grammar/Errors/EvalNotConst.cs new file mode 100644 index 0000000..9322f41 --- /dev/null +++ b/YololAssembler/Grammar/Errors/EvalNotConst.cs @@ -0,0 +1,14 @@ +namespace YololAssembler.Grammar.Errors +{ + public class EvalNotConst + : BaseCompileException + { + public Yolol.Grammar.AST.Expressions.BaseExpression Expression { get; } + + public EvalNotConst(Yolol.Grammar.AST.Expressions.BaseExpression expression) + : base($"Expression pass to eval is not constant `{expression}`.") + { + Expression = expression; + } + } +} diff --git a/YololAssembler/Properties/PublishProfiles/FolderProfile.pubxml b/YololAssembler/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..a2fdb7c --- /dev/null +++ b/YololAssembler/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,14 @@ + + + + + Release + Any CPU + C:\Users\Martin\Desktop\yasm + FileSystem + netcoreapp3.1 + false + + \ No newline at end of file diff --git a/YololAssembler/Scripts/hanoi.lol b/YololAssembler/Scripts/hanoi.yasm similarity index 99% rename from YololAssembler/Scripts/hanoi.lol rename to YololAssembler/Scripts/hanoi.yasm index df90189..8842c92 100644 --- a/YololAssembler/Scripts/hanoi.lol +++ b/YololAssembler/Scripts/hanoi.yasm @@ -18,7 +18,7 @@ #define l_pin_char d #define r_pin_char e -#import lib.lol +#import lib.yasm @line1: b="" diff --git a/YololAssembler/Scripts/lib.lol b/YololAssembler/Scripts/lib.lol deleted file mode 100644 index 3908aae..0000000 --- a/YololAssembler/Scripts/lib.lol +++ /dev/null @@ -1,6 +0,0 @@ -#define undefined _ - -#define err_if_not(expr) undefined/=expr -#define continue_if(expr) undefined/=expr - -#define pop_char(str) str---str \ No newline at end of file diff --git a/YololAssembler/Scripts/lib.yasm b/YololAssembler/Scripts/lib.yasm new file mode 100644 index 0000000..ac85863 --- /dev/null +++ b/YololAssembler/Scripts/lib.yasm @@ -0,0 +1,13 @@ +#define undefined _ + +#define err_if_not(expr) undefined/=expr +#define continue_if(expr) undefined/=expr + +#define pop_char(stack) stack---stack +#define push_char(stack, c) stack+=c + +#define dequeue_char(q) q---q +#define enqueue_char(q, c) q=c+q + +#define set_add_char(set, c) set+=c +#define set_find_char(set, c) set-c!=set \ No newline at end of file diff --git a/YololAssembler/Scripts/test.yasm b/YololAssembler/Scripts/run_length_encoding.yasm similarity index 90% rename from YololAssembler/Scripts/test.yasm rename to YololAssembler/Scripts/run_length_encoding.yasm index ce03c6b..51ab1b1 100644 --- a/YololAssembler/Scripts/test.yasm +++ b/YololAssembler/Scripts/run_length_encoding.yasm @@ -7,7 +7,7 @@ #define tmp h #define output :o -#import lib.lol +#import lib.yasm #define try_next_run_char() { char2=pop_char(input); @@ -31,7 +31,7 @@ ifinput>0then try_next_run_char() end - gotofind_run_end+(input<0)*(run_ended_no_chars-find_run_end) + gotofind_run_end+(input<0)*eval(run_ended_no_chars-find_run_end) @run_ended_dif_char: output=((delimiter+run_acc+delimiter)-".1.") diff --git a/YololAssembler/Scripts/test.yolol b/YololAssembler/Scripts/test.yolol deleted file mode 100644 index cd1d460..0000000 --- a/YololAssembler/Scripts/test.yolol +++ /dev/null @@ -1,7 +0,0 @@ -a=:a:o=""f="."d=a---a g=1ifa<0then:o=d+:o goto:done++end -e=a---a _/=d==e g++ifa>0thene=a---a _/=d==e g++endgoto2+(a<0)*(5-2) -:o=((f+g+f)-".1.")+d+:o-f-f d=e g=1_/=a>0goto2 -:o=e+:o goto:done++ -:o=g+d+:o goto:done++ - -// <-------------- this line is 70 characters long ------------------> \ No newline at end of file diff --git a/YololAssembler/YololAssembler.csproj b/YololAssembler/YololAssembler.csproj index 39745ea..9d2c84a 100644 --- a/YololAssembler/YololAssembler.csproj +++ b/YololAssembler/YololAssembler.csproj @@ -19,10 +19,10 @@ - + PreserveNewest - + PreserveNewest