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..65e12f32af 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 (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..a45e6e5e27 --- /dev/null +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/SequenceLiteralExpr.cs @@ -0,0 +1,29 @@ +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; + + if (sequenceElements.Count > 0) { + Type = new SequenceType(sequenceElements[0].Type); + } + else { + Type = new SequenceType(PrimitiveType.Any); + } + } + + 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..518b6c850c 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs @@ -76,6 +76,23 @@ 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(); + + // 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); + } + 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..a151f71d2e --- /dev/null +++ b/Tst/RegressionTests/Feature3Exprs/Correct/SequenceLiteralExpr/SequenceLiteralExpr.p @@ -0,0 +1,29 @@ +machine Main { + var s1: seq[int]; + var s2: seq[any]; + var s3: seq[bool]; + 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); + + 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; + } + } +}