Skip to content
569 changes: 417 additions & 152 deletions Src/PCompiler/CompilerCore/Backend/Uclid5/Uclid5CodeGenerator.cs

Large diffs are not rendered by default.

42 changes: 41 additions & 1 deletion Src/PCompiler/CompilerCore/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ public int Compile(ICompilerConfiguration job)
var compiledFiles = job.Backend.GenerateCode(job, scope);
foreach (var file in compiledFiles)
{
job.Output.WriteInfo($"Generated {file.FileName}.");
if (entry != CompilerOutput.Uclid5)
{
job.Output.WriteInfo($"Generated {file.FileName}.");
}
job.Output.WriteFile(file);
}

Expand Down Expand Up @@ -167,6 +170,43 @@ public void SyntaxError(IRecognizer recognizer, IToken offendingSymbol, int line
}
}

public static Process NonBlockingRun(string activeDirectory, string exeName, params string[] argumentList)
{
var psi = new ProcessStartInfo(exeName)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WorkingDirectory = activeDirectory,
Arguments = string.Join(" ", argumentList)
};

var proc = new Process { StartInfo = psi };
proc.Start();
return proc;
}

public static int WaitForResult(Process proc, out string stdout, out string stderr)
{
string mStderr = "", mStdout = "";
proc.OutputDataReceived += (s, e) => { mStdout += $"{e.Data}\n"; };
proc.ErrorDataReceived += (s, e) =>
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
mStderr += $"{e.Data}\n";
}
};
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
stdout = mStdout;
stderr = mStderr;
return proc.ExitCode;
}

public static int RunWithOutput(string activeDirectory,
out string stdout,
out string stderr, string exeName,
Expand Down
2 changes: 2 additions & 0 deletions Src/PCompiler/CompilerCore/CompilerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public CompilerConfiguration()
Timeout = 60;
HandlesAll = true;
CheckOnly = null;
Parallelism = Math.Max(Environment.ProcessorCount / 2, 1);
}
public CompilerConfiguration(ICompilerOutput output, DirectoryInfo outputDir, IList<CompilerOutput> outputLanguages, IList<string> inputFiles,
string projectName, DirectoryInfo projectRoot = null, IList<string> projectDependencies = null, string pObservePackageName = null, bool debug = false)
Expand Down Expand Up @@ -79,6 +80,7 @@ public CompilerConfiguration(ICompilerOutput output, DirectoryInfo outputDir, IL
public int Timeout { get; set; }
public bool HandlesAll { get; set; }
public string CheckOnly { get; set; }
public int Parallelism { get; set; }

public void Copy(CompilerConfiguration parsedConfig)
{
Expand Down
1 change: 1 addition & 0 deletions Src/PCompiler/CompilerCore/ICompilerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ public interface ICompilerConfiguration
int Timeout { get; }
bool HandlesAll { get; }
string CheckOnly { get; }
int Parallelism { get; }
}
}
6 changes: 6 additions & 0 deletions Src/PCompiler/CompilerCore/Parser/PLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ IS : 'is';
FLYING : 'inflight';
TARGETS : 'targets';
SENT : 'sent';
PROOF : 'Proof';
PROVE : 'prove';
USING : 'using';
LEMMA : 'Lemma';
THEOREM : 'Theorem';
EXCEPT : 'except';
Copy link
Collaborator

@FedericoAureliano FedericoAureliano Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example that uses the "except" keyword? I'm not totally sure I understand what it does. Is it just like commenting an invariant out?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, essentially it is excluding invariants from goals and premises.
For example, if you write prove X using * and you do not want to put Y in the *, then you can write prove X using * except Y.
Also, if you write prove * and do not want to include Y in *, you can write prove * except Y.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool, looks good to me!


// module-system-specific keywords

Expand Down
9 changes: 9 additions & 0 deletions Src/PCompiler/CompilerCore/Parser/PParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,19 @@ topDecl : typeDefDecl
| testDecl
| implementationDecl
| invariantDecl
| invariantGroupDecl
| axiomDecl
| assumeOnStartDecl
| proofBlockDecl
;

invariantGroupDecl : LEMMA name=iden LBRACE invariantDecl* RBRACE
| THEOREM name=iden LBRACE invariantDecl* RBRACE
;

proofBlockDecl : PROOF LBRACE proofBody RBRACE ;
proofBody : proofItem* ;
proofItem : PROVE (targets+=expr (COMMA targets+=expr)* | goalsAll=MUL) (USING ((premises+=expr (COMMA premises+=expr)*) | premisesAll=MUL))? (EXCEPT excludes+=expr (COMMA excludes+=expr)*)? SEMI # ProveUsingCmd ;

typeDefDecl : TYPE name=iden SEMI # ForeignTypeDef
| TYPE name=iden ASSIGN type SEMI # PTypeDef
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using Antlr4.Runtime;

namespace Plang.Compiler.TypeChecker.AST.Declarations
{
public class InvariantGroup : IPDecl
{
public InvariantGroup(string name, ParserRuleContext sourceNode)
{
Name = name;
SourceLocation = sourceNode;
}
public List<Invariant> Invariants { get; set; }
public ParserRuleContext SourceLocation { get; }
public string Name { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Diagnostics;
using Antlr4.Runtime;

namespace Plang.Compiler.TypeChecker.AST.Declarations
{
public class ProofCommand : IPDecl
{
public ProofCommand(string name, ParserRuleContext sourceNode)
{
Debug.Assert(sourceNode is PParser.ProofItemContext);
SourceLocation = sourceNode;
Name = name;
}

public List<Invariant> Goals { get; set; }
public List<Invariant> Premises { get; set; }
public List<Invariant> Excepts { get; set; }
public ParserRuleContext SourceLocation { get; }
public string Name { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using Antlr4.Runtime;
using Plang.Compiler.TypeChecker.AST.Declarations;
using Plang.Compiler.TypeChecker.Types;

namespace Plang.Compiler.TypeChecker.AST.Expressions
{
public class InvariantRefExpr : IPExpr
{
public InvariantRefExpr(Invariant inv, ParserRuleContext sourceLocation)
{
Invariant = inv;
SourceLocation = sourceLocation;
}
public Invariant Invariant { get; set; }

public PLanguageType Type => PrimitiveType.Bool;

public ParserRuleContext SourceLocation { get; set; }
}

public class InvariantGroupRefExpr : IPExpr {
public InvariantGroupRefExpr(InvariantGroup invGroup, ParserRuleContext sourceLocation)
{
InvariantGroup = invGroup;
SourceLocation = sourceLocation;
}
public InvariantGroup InvariantGroup { get; set; }
public List<Invariant> Invariants => InvariantGroup.Invariants;

public PLanguageType Type => PrimitiveType.Bool;

public ParserRuleContext SourceLocation { get; set; }
}
}
17 changes: 17 additions & 0 deletions Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ public override object VisitAxiomDecl(PParser.AxiomDeclContext context)
return null;
}

public override object VisitInvariantGroupDecl(PParser.InvariantGroupDeclContext context)
{
var name = context.name.GetText();
var decl = CurrentScope.Put(name, context);
nodesToDeclarations.Put(context, decl);
context.invariantDecl().Select(Visit).ToList();
return null;
}

public override object VisitProveUsingCmd(PParser.ProveUsingCmdContext context)
{
var name = $"proof_cmd_{CurrentScope.ProofCommands.Count()}";
var decl = CurrentScope.Put(name, context);
nodesToDeclarations.Put(context, decl);
return null;
}

public override object VisitAssumeOnStartDecl(PParser.AssumeOnStartDeclContext context)
{
var name = $"init{CurrentScope.AssumeOnStarts.Count()}";
Expand Down
69 changes: 69 additions & 0 deletions Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Antlr4.Runtime;
using Antlr4.Runtime.Tree;
using Plang.Compiler.TypeChecker.AST;
using Plang.Compiler.TypeChecker.AST.Declarations;
using Plang.Compiler.TypeChecker.AST.Expressions;
using Plang.Compiler.TypeChecker.AST.States;
using Plang.Compiler.TypeChecker.Types;
using Plang.Compiler.Util;
Expand Down Expand Up @@ -693,6 +695,73 @@ public override object VisitAxiomDecl(PParser.AxiomDeclContext context)

return inv;
}

public override object VisitInvariantGroupDecl(PParser.InvariantGroupDeclContext context)
{
var invGroup = (InvariantGroup) nodesToDeclarations.Get(context);
invGroup.Invariants = context.invariantDecl().Select(Visit).Cast<Invariant>().ToList();
return invGroup;
}

private List<Invariant> ToInvariant(IPExpr e, ParserRuleContext context)
{
if (e is InvariantGroupRefExpr invGroupRef) return invGroupRef.Invariants;
if (e is InvariantRefExpr invRef) return [invRef.Invariant];
if (!PrimitiveType.Bool.IsSameTypeAs(e.Type.Canonicalize()))
{
throw Handler.TypeMismatch(context, e.Type, PrimitiveType.Bool);
}
Invariant inv = new Invariant($"tmp_inv_{Guid.NewGuid()}", e, context);
return [inv];
}

public override object VisitProveUsingCmd(PParser.ProveUsingCmdContext context)
{
var proofCmd = (ProofCommand) nodesToDeclarations.Get(context);
var temporaryFunction = new Function(proofCmd.Name, context);
temporaryFunction.Scope = CurrentScope.MakeChildScope();
var exprVisitor = new ExprVisitor(temporaryFunction, Handler);
List<IPExpr> premises = [];
List<IPExpr> goals = [];
List<IPExpr> excepts = context._excludes.Select(exprVisitor.Visit).ToList();
if (context.premisesAll == null)
{
premises = context._premises.Select(exprVisitor.Visit).ToList();
}
else
{
premises = CurrentScope.AllDecls.OfType<Invariant>().Select(x => (IPExpr) new InvariantRefExpr(x, context)).ToList();
}
if (context.goalsAll == null)
{
goals = context._targets.Select(exprVisitor.Visit).ToList();
}
else
{
goals = CurrentScope.AllDecls.OfType<Invariant>().Select(x => (IPExpr) new InvariantRefExpr(x, context)).ToList();
}
if (premises.Count == context._premises.Count)
{
proofCmd.Premises = premises.Zip(context._premises, (x, y) => ToInvariant(x, y)).SelectMany(x => x).ToList();
}
else
{
proofCmd.Premises = premises.SelectMany(x => ToInvariant(x, context)).ToList();
}
if (goals.Count == context._targets.Count)
{
proofCmd.Goals = goals.Zip(context._targets, (x, y) => ToInvariant(x, y)).SelectMany(x => x).ToList();
}
else
{
proofCmd.Goals = goals.SelectMany(x => ToInvariant(x, context)).ToList();
}
proofCmd.Excepts = excepts.Zip(context._excludes, (x, y) => ToInvariant(x, y)).SelectMany(x => x).ToList();
// exclude things appear in `goals` from `premises`
proofCmd.Premises = proofCmd.Premises.Except(proofCmd.Goals).Except(proofCmd.Excepts).ToList();
proofCmd.Goals = proofCmd.Goals.Except(proofCmd.Excepts).ToList();
return proofCmd;
}

public override object VisitAssumeOnStartDecl(PParser.AssumeOnStartDeclContext context)
{
Expand Down
10 changes: 10 additions & 0 deletions Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,16 @@ public override IPExpr VisitPrimitive(PParser.PrimitiveContext context)
return new SpecRefExpr(context, mac);
}

if (table.Lookup(symbolName, out Invariant inv))
{
return new InvariantRefExpr(inv, context);
}

if (table.Lookup(symbolName, out InvariantGroup invGroup))
{
return new InvariantGroupRefExpr(invGroup, context);
}

throw handler.MissingDeclaration(context.iden(), "variable, enum element, spec machine, or event", symbolName);
}

Expand Down
Loading
Loading