diff --git a/src/samples/IndentedWhile/parser/IndentedWhileParserGeneric.cs b/src/samples/IndentedWhile/parser/IndentedWhileParserGeneric.cs index f88b3534..1b564112 100644 --- a/src/samples/IndentedWhile/parser/IndentedWhileParserGeneric.cs +++ b/src/samples/IndentedWhile/parser/IndentedWhileParserGeneric.cs @@ -143,6 +143,27 @@ public WhileAST skipStmt(WhileAST expression) #region OPERANDS + // fstrings + [Production("primary : OPEN_FSTRING[d] fstring_element* CLOSE_FSTRING[d]")] + public WhileAST fstring(List elements) + { + var fstring = new FString(elements.Cast().ToList(), elements.First().Position); + return fstring; + } + + [Production("fstring_element : FSTRING_CONTENT")] + public WhileAST FStringContent(Token element) + { + return new FStringElement(new StringConstant(element.Value),element.Position); + } + + [Production("fstring_element : OPEN_FSTRING_EXPPRESSION[d] IDENTIFIER CLOSE_FSTRING_EXPPRESSION[d]")] + public WhileAST FStringExpression(Token element) + { + return new FStringElement(new Variable(element.Value),element.Position); + } + + [Production("primary: INT")] public WhileAST PrimaryInt(Token intToken) { @@ -156,11 +177,11 @@ public WhileAST PrimaryBool(Token boolToken) return new BoolConstant(bool.Parse(boolToken.StringWithoutQuotes)); } - [Production("primary: STRING")] - public WhileAST PrimaryString(Token stringToken) - { - return new StringConstant(stringToken.StringWithoutQuotes); - } + // [Production("primary: STRING")] + // public WhileAST PrimaryString(Token stringToken) + // { + // return new StringConstant(stringToken.StringWithoutQuotes); + // } [Production("primary: IDENTIFIER")] public WhileAST PrimaryId(Token varToken) diff --git a/src/samples/IndentedWhile/parser/IndentedWhileTokenGeneric.cs b/src/samples/IndentedWhile/parser/IndentedWhileTokenGeneric.cs index 39fa65cc..18ca272c 100644 --- a/src/samples/IndentedWhile/parser/IndentedWhileTokenGeneric.cs +++ b/src/samples/IndentedWhile/parser/IndentedWhileTokenGeneric.cs @@ -42,7 +42,7 @@ public enum IndentedWhileTokenGeneric [Lexeme(GenericToken.KeyWord, "PRINT")] [Lexeme(GenericToken.KeyWord, "print")] PRINT = 12, - + [Lexeme(GenericToken.KeyWord, "RETURN")] [Lexeme(GenericToken.KeyWord, "return")] RETURN = 13, @@ -50,9 +50,9 @@ public enum IndentedWhileTokenGeneric #region literals 20 -> 29 - [Lexeme(GenericToken.Identifier,IdentifierType.AlphaNumericDash)] IDENTIFIER = 20, - - [Lexeme(GenericToken.String)] STRING = 21, + [Mode(ModeAttribute.DefaultLexerMode, "fstringExpression")] + [Lexeme(GenericToken.Identifier, IdentifierType.AlphaNumericDash)] + IDENTIFIER = 20, [Lexeme(GenericToken.Int)] INT = 22, @@ -88,16 +88,40 @@ public enum IndentedWhileTokenGeneric #region sugar 50 -> - // [Lexeme(GenericToken.SugarToken, "(")] LPAREN = 50, - // - // [Lexeme(GenericToken.SugarToken, ")")] RPAREN = 51, [Lexeme(GenericToken.SugarToken, ";")] SEMICOLON = 52, - [SingleLineComment("#")] - COMMENT=1236 + [SingleLineComment("#")] COMMENT = 1236, + + #endregion + + #region fstring 100 -> + + [Push("fstringExpression")] [Mode("fstring")] [Sugar("{")] + OPEN_FSTRING_EXPPRESSION = 100, + + [Pop] [Mode("fstringExpression")] [Sugar("}")] + CLOSE_FSTRING_EXPPRESSION = 101, + [Sugar("$\"")] + [Push("fstring")] + OPEN_FSTRING, + + [Sugar("\"")] + [Mode("fstring")] + [Pop] + CLOSE_FSTRING, + + + [Mode("fstring")] + [UpTo("{","\"")] + FSTRING_CONTENT + + #endregion + + + } } \ No newline at end of file diff --git a/src/samples/while/model/FString.cs b/src/samples/while/model/FString.cs new file mode 100644 index 00000000..5fd6c586 --- /dev/null +++ b/src/samples/while/model/FString.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using csly.whileLang.compiler; +using Sigil; +using sly.lexer; + +namespace csly.whileLang.model; + +public class FString : Expression +{ + public LexerPosition Position { get; set; } + public Scope CompilerScope { get; set; } + + public List Elements { get; set; } + + public FString(List elements, LexerPosition position) + { + this.Elements = elements; + Position = position; + } + + public string Dump(string tab) + { + StringBuilder builder = new StringBuilder(); + builder.Append($"{{tab}}\""); + foreach (var element in Elements) + { + builder.Append(element.Dump("")); + } + + builder.Append("\""); + return builder.ToString(); + } + + public string Transpile(CompilerContext context) + { + throw new NotImplementedException(); + } + + public Emit> EmitByteCode(CompilerContext context, Emit> emiter) + { + throw new NotImplementedException(); + } + + public WhileType Whiletype { get; set; } = WhileType.STRING; +} \ No newline at end of file diff --git a/src/samples/while/model/FStringElement.cs b/src/samples/while/model/FStringElement.cs new file mode 100644 index 00000000..686a138c --- /dev/null +++ b/src/samples/while/model/FStringElement.cs @@ -0,0 +1,56 @@ +using System; +using csly.whileLang.compiler; +using Sigil; +using sly.lexer; + +namespace csly.whileLang.model; + +public class FStringElement : WhileAST +{ + + public LexerPosition Position { get; set; } + + public Scope CompilerScope { get; set; } + public Variable VariableElement { get; set; } + + public StringConstant StringElement { get; set; } + + public bool IsStringElement => StringElement != null; + + public bool IsVariable => VariableElement != null; + + public FStringElement(Variable variableElement, LexerPosition position) + { + VariableElement = variableElement; + Position = position; + } + + public FStringElement(StringConstant stringElement, LexerPosition position) + { + StringElement = stringElement; + Position = position; + } + + + public string Dump(string tab) + { + if (IsStringElement) + { + return tab + StringElement.Value; + } + else + { + return $"{{tab}}{{{{{VariableElement.Dump("")}}}"; + } + } + + public string Transpile(CompilerContext context) + { + throw new NotImplementedException(); + } + + public Emit> EmitByteCode(CompilerContext context, Emit> emiter) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/tests/ParserTests/samples/IndentedWhileTests.cs b/tests/ParserTests/samples/IndentedWhileTests.cs index 795261ec..98479ee0 100644 --- a/tests/ParserTests/samples/IndentedWhileTests.cs +++ b/tests/ParserTests/samples/IndentedWhileTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using csly.indentedWhileLang.compiler; using csly.indentedWhileLang.parser; using csly.whileLang.interpreter; @@ -147,9 +148,9 @@ public void TestIfThenElse() var program = @" # TestIfThenElse if true then - a := ""hello"" + a := $""hello"" else - b := ""world"" + b := $""world"" "; var result = parser.Parse(program); Check.That(result).IsOkParsing(); @@ -206,6 +207,44 @@ public void TestNestedIfThenElse() } + [Fact] + public void TestFString() + { + var buildResult = buildParser(); + var parser = buildResult.Result; + var program = @" +# fstring +v1 := 1 +v2 := 2 +fstring := $""{v1} - content - {v2} - end"" +"; + Console.WriteLine("=================================="); + Console.WriteLine("=== parse fstring"); + Console.WriteLine("=================================="); + Console.WriteLine(); + var result = parser.Parse(program); + Check.That(result).IsOkParsing(); + Check.That(result.Result).IsNotNull(); + Check.That(result.Result).IsInstanceOf(); + SequenceStatement seq = result.Result as SequenceStatement; + Check.That(seq.Count).IsEqualTo(3); + var fstringAssign = seq.Get(2) as AssignStatement; + Check.That(fstringAssign).IsNotNull(); + Check.That(fstringAssign.VariableName).IsEqualTo("fstring"); + Check.That(fstringAssign.Value).IsInstanceOf(); + var fString = fstringAssign.Value as FString; + Check.That(fString).IsNotNull(); + Check.That(fString.Elements).CountIs(4); + Check.That(fString.Elements[0]).IsInstanceOf(); + Check.That((fString.Elements[0] as FStringElement).IsVariable); + Check.That(fString.Elements[1]).IsInstanceOf(); + Check.That((fString.Elements[1] as FStringElement).IsStringElement); + Check.That(fString.Elements[2]).IsInstanceOf(); + Check.That((fString.Elements[2] as FStringElement).IsVariable); + Check.That(fString.Elements[3]).IsInstanceOf(); + Check.That((fString.Elements[3] as FStringElement).IsStringElement); + } + [Fact] public void TestInfiniteWhile() {