From 3c1e4a4523a983346897f69b9f5aefc79af402c8 Mon Sep 17 00:00:00 2001 From: Anmol Sahoo Date: Sun, 10 Aug 2025 14:18:39 -0400 Subject: [PATCH 1/2] Add sequence literals This commit adds sequence literals with the syntax `{| elems+ |}`, which enables assigning sequence literals to seq[T] variables. --- .../Backend/CSharp/CSharpCodeGenerator.cs | 13 ++++++++++ .../Backend/Debugging/IrToPseudoP.cs | 4 +++ .../CompilerCore/Backend/IRTransformer.cs | 7 +++++ Src/PCompiler/CompilerCore/Parser/PLexer.g4 | 2 ++ Src/PCompiler/CompilerCore/Parser/PParser.g4 | 5 ++++ .../AST/Expressions/SequenceLiteralExpr.cs | 23 ++++++++++++++++ .../TypeChecker/DeclarationStubVisitor.cs | 5 ++++ .../CompilerCore/TypeChecker/ExprVisitor.cs | 5 ++++ .../SequenceLiteralExpr/SequenceLiteralExpr.p | 26 +++++++++++++++++++ 9 files changed, 90 insertions(+) create mode 100644 Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs create mode 100644 Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs index 93f14d53f7..cbd16a82e6 100644 --- a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs +++ b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs @@ -1486,6 +1486,19 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p context.Write(output, ")"); break; + case SequenceLiteralExpr sequenceLiteralExpr: + context.Write(output, $"new {GetCSharpType(sequenceLiteralExpr.Type)}(new List"); + context.Write(output, "{"); + var sep2 = ""; + foreach (var elem in sequenceLiteralExpr.SequenceElements) + { + context.Write(output, sep2); + WriteExpr(context, output, elem); + sep2 = ", "; + } + context.Write(output, "})"); + break; + case ValuesExpr valuesExpr: context.Write(output, "("); WriteExpr(context, output, valuesExpr.Expr); diff --git a/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs b/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs index 23c7968fb9..391e9be7ff 100644 --- a/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs +++ b/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs @@ -543,6 +543,10 @@ protected override void WriteExpr(IPExpr expr) WriteParts("null"); break; + case SequenceLiteralExpr sequenceLiteralExpr: + WriteParts("{|", sequenceLiteralExpr.SequenceElements, "|}"); + break; + case SeqAccessExpr seqAccessExpr: WriteParts("(", seqAccessExpr.SeqExpr, ")[", seqAccessExpr.IndexExpr, "]"); break; diff --git a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs index 1aa12b676e..1995413b95 100644 --- a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs +++ b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs @@ -268,6 +268,13 @@ public static void SimplifyMethod(Function function) deps.Add(ndStore); return (ndTemp, deps); + case SequenceLiteralExpr sequenceLiteralExpr: + (var sequenceElements, var sequenceElementDeps) = SimplifyArgPack(sequenceLiteralExpr.SequenceElements); + deps.AddRange(sequenceElementDeps); + (var seqElementsVal, var seqElementsStore) = SaveInTemporary(new SequenceLiteralExpr(location, sequenceElements)); + deps.Add(seqElementsStore); + return (seqElementsVal, deps); + case SeqAccessExpr seqAccessExpr: (var seqExpr, var seqDeps) = SimplifyExpression(seqAccessExpr.SeqExpr); (var seqIdx, var seqIdxDeps) = SimplifyExpression(seqAccessExpr.IndexExpr); diff --git a/Src/PCompiler/CompilerCore/Parser/PLexer.g4 b/Src/PCompiler/CompilerCore/Parser/PLexer.g4 index 8f7511ac8d..43f0cfe705 100644 --- a/Src/PCompiler/CompilerCore/Parser/PLexer.g4 +++ b/Src/PCompiler/CompilerCore/Parser/PLexer.g4 @@ -134,6 +134,8 @@ LBRACK : '[' ; RBRACK : ']' ; LPAREN : '(' ; RPAREN : ')' ; +LSEQ : '{|'; +RSEQ : '|}'; SEMI : ';' ; COMMA : ',' ; DOT : '.' ; diff --git a/Src/PCompiler/CompilerCore/Parser/PParser.g4 b/Src/PCompiler/CompilerCore/Parser/PParser.g4 index dc00fca475..f6a148d02b 100644 --- a/Src/PCompiler/CompilerCore/Parser/PParser.g4 +++ b/Src/PCompiler/CompilerCore/Parser/PParser.g4 @@ -170,6 +170,7 @@ noParamAnonEventHandler : functionBody; expr : primitive # PrimitiveExpr | LPAREN unnamedTupleBody RPAREN # UnnamedTupleExpr | LPAREN namedTupleBody RPAREN # NamedTupleExpr + | LSEQ seqElems RSEQ # SequenceLiteralExpr | LPAREN expr RPAREN # ParenExpr | expr DOT field=iden # NamedTupleAccessExpr | expr DOT field=int # TupleAccessExpr @@ -212,6 +213,10 @@ floatLiteral : pre=IntLiteral? DOT post=IntLiteral # DecimalFloat | FLOAT LPAREN base=IntLiteral COMMA exp=IntLiteral RPAREN # ExpFloat ; +seqElems : elems+=primitive + | elems+=primitive (COMMA elems+=primitive)* + ; + unnamedTupleBody : fields+=rvalue COMMA | fields+=rvalue (COMMA fields+=rvalue)+ ; diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs new file mode 100644 index 0000000000..8deedca7dd --- /dev/null +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using Antlr4.Runtime; +using Plang.Compiler.TypeChecker.Types; + +namespace Plang.Compiler.TypeChecker.AST.Expressions +{ + public class SequenceLiteralExpr: IPExpr + { + public SequenceLiteralExpr(ParserRuleContext sourceLocation, IReadOnlyList sequenceElements) + { + SourceLocation = sourceLocation; + SequenceElements = sequenceElements; + Type = new SequenceType(sequenceElements[0].Type); + } + + public IReadOnlyList SequenceElements { get; } + + public ParserRuleContext SourceLocation { get; } + + public PLanguageType Type { get; } + } +} diff --git a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs index 77782e7308..68723e389e 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs @@ -246,6 +246,11 @@ public override object VisitKeywordExpr(PParser.KeywordExprContext context) return null; } + public override object VisitSequenceLiteralExpr(PParser.SequenceLiteralExprContext context) + { + return null; + } + public override object VisitSeqAccessExpr(PParser.SeqAccessExprContext context) { return null; diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs index ff6d1e2d0d..d222af771b 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs @@ -76,6 +76,11 @@ public override IPExpr VisitTupleAccessExpr(PParser.TupleAccessExprContext conte return new TupleAccessExpr(context, subExpr, fieldNo, tuple.Types[fieldNo]); } + public override IPExpr VisitSequenceLiteralExpr(PParser.SequenceLiteralExprContext context) { + var elems = context.seqElems()._elems.Select(Visit).ToArray(); + return new SequenceLiteralExpr(context, elems); + } + public override IPExpr VisitSeqAccessExpr(PParser.SeqAccessExprContext context) { var seqOrMap = Visit(context.seq); diff --git a/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p b/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p new file mode 100644 index 0000000000..eaf98ccd6a --- /dev/null +++ b/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p @@ -0,0 +1,26 @@ +machine Main { + var s1: seq[int]; + var s2: seq[any]; + var a: int; + + start state S + { + entry + { + s1 = {| 1 , 2 , 3 |}; + assert (s1[0] == 1); + assert (s1[1] == 2); + assert (s1[2] == 3); + + s2 = {| true, false, true |}; + assert (s2[0] as bool); + assert (!(s2[1] as bool)); + assert (s2[2] as bool); + + s1 = {| a, a, a |}; + assert (s1[0] == 0); + assert (s1[1] == 0); + assert (s1[2] == 0); + } + } +} From 798581b7a9927c61afcd8c885ba9c3e14519f422 Mon Sep 17 00:00:00 2001 From: Anmol Sahoo Date: Mon, 11 Aug 2025 19:06:34 -0400 Subject: [PATCH 2/2] Added checks for all elements to be of same type and assign seq[any] type to empty literal --- Src/PCompiler/CompilerCore/Parser/PParser.g4 | 2 +- .../AST/Expressions/SequenceLiteralExpr.cs | 8 +++++++- .../CompilerCore/TypeChecker/ExprVisitor.cs | 12 ++++++++++++ .../SequenceLiteralExpr/SequenceLiteralExpr.p | 3 +++ .../StaticError/SequenceLiterals/ExprOperators.p | 12 ++++++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 Tst/RegressionTests/Feature3Exprs/StaticError/SequenceLiterals/ExprOperators.p diff --git a/Src/PCompiler/CompilerCore/Parser/PParser.g4 b/Src/PCompiler/CompilerCore/Parser/PParser.g4 index f6a148d02b..65e12f32af 100644 --- a/Src/PCompiler/CompilerCore/Parser/PParser.g4 +++ b/Src/PCompiler/CompilerCore/Parser/PParser.g4 @@ -213,7 +213,7 @@ floatLiteral : pre=IntLiteral? DOT post=IntLiteral # DecimalFloat | FLOAT LPAREN base=IntLiteral COMMA exp=IntLiteral RPAREN # ExpFloat ; -seqElems : elems+=primitive +seqElems : | elems+=primitive (COMMA elems+=primitive)* ; diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs index 8deedca7dd..a45e6e5e27 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs @@ -11,7 +11,13 @@ public SequenceLiteralExpr(ParserRuleContext sourceLocation, IReadOnlyList 0) { + Type = new SequenceType(sequenceElements[0].Type); + } + else { + Type = new SequenceType(PrimitiveType.Any); + } } public IReadOnlyList SequenceElements { get; } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs index d222af771b..518b6c850c 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs @@ -78,6 +78,18 @@ public override IPExpr VisitTupleAccessExpr(PParser.TupleAccessExprContext conte public override IPExpr VisitSequenceLiteralExpr(PParser.SequenceLiteralExprContext context) { var elems = context.seqElems()._elems.Select(Visit).ToArray(); + + // check whether all elements have the same type + if (elems.Count() > 0) { + var firstElementType = elems[0].Type; + for (int i = 1; i < elems.Count(); i++) { + var currElementType = elems[i].Type; + if (!currElementType.Equals(firstElementType)) { + throw handler.TypeMismatch(context.seqElems()._elems[i], currElementType, firstElementType); + } + } + } + return new SequenceLiteralExpr(context, elems); } diff --git a/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p b/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p index eaf98ccd6a..a151f71d2e 100644 --- a/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p +++ b/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p @@ -1,6 +1,7 @@ machine Main { var s1: seq[int]; var s2: seq[any]; + var s3: seq[bool]; var a: int; start state S @@ -21,6 +22,8 @@ machine Main { assert (s1[0] == 0); assert (s1[1] == 0); assert (s1[2] == 0); + + s3 = {||} as seq[bool]; } } } diff --git a/Tst/RegressionTests/Feature3Exprs/StaticError/SequenceLiterals/ExprOperators.p b/Tst/RegressionTests/Feature3Exprs/StaticError/SequenceLiterals/ExprOperators.p new file mode 100644 index 0000000000..e3963dbe2f --- /dev/null +++ b/Tst/RegressionTests/Feature3Exprs/StaticError/SequenceLiterals/ExprOperators.p @@ -0,0 +1,12 @@ +machine Main { + var s1 : seq[bool]; + + start state S + { + entry + { + s1 = {| true, 1, 2 |}; //error: "got type int, expected bool" + raise halt; + } + } +}