Skip to content

Commit

Permalink
Stately Code Generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Esther Sue committed Jul 25, 2023
1 parent f3c6cb7 commit 191c133
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 3 deletions.
11 changes: 11 additions & 0 deletions Src/PCompiler/CompilerCore/Backend/Stately/CompilationContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Plang.Compiler.Backend.Stately;

internal class CompilationContext : CompilationContextBase
{
public CompilationContext(ICompilerConfiguration job) : base(job)
{
FileName = $"{ProjectName}.ts";
}

public string FileName { get; set; }
}
127 changes: 127 additions & 0 deletions Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Plang.Compiler.TypeChecker;
using Plang.Compiler.TypeChecker.AST;
using Plang.Compiler.TypeChecker.AST.Declarations;
using Plang.Compiler.TypeChecker.AST.Statements;
using Plang.Compiler.TypeChecker.AST.States;

namespace Plang.Compiler.Backend.Stately {
public class StatelyCodeGenerator : ICodeGenerator
{
public bool HasCompilationStage => false;
public IEnumerable<CompiledFile> GenerateCode(ICompilerConfiguration job, Scope globalScope)
{
var context = new CompilationContext(job);
var statelySource = GenerateSource(context, globalScope);
return new List<CompiledFile> { statelySource };
}

private CompiledFile GenerateSource(CompilationContext context, Scope globalScope)
{
var source = new CompiledFile(context.FileName);
WriteSourcePrologue(context, source.Stream);
// write the top level declarations
foreach (var decl in globalScope.AllDecls)
{
WriteDecl(context, source.Stream, decl);
}

return source;
}

private void WriteDecl(CompilationContext context, StringWriter output, IPDecl decl)
{
string declName;

Check warning on line 38 in Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs

View workflow job for this annotation

GitHub Actions / Build-And-Test-Ubuntu

The variable 'declName' is declared but never used

Check warning on line 38 in Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs

View workflow job for this annotation

GitHub Actions / Build-And-Test-Ubuntu

The variable 'declName' is declared but never used

Check warning on line 38 in Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs

View workflow job for this annotation

GitHub Actions / Build-And-Test-Windows

The variable 'declName' is declared but never used

Check warning on line 38 in Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs

View workflow job for this annotation

GitHub Actions / Build-And-Test-Windows

The variable 'declName' is declared but never used

Check warning on line 38 in Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs

View workflow job for this annotation

GitHub Actions / Build-And-Test-MacOS

The variable 'declName' is declared but never used

Check warning on line 38 in Src/PCompiler/CompilerCore/Backend/Stately/StatelyCodeGenerator.cs

View workflow job for this annotation

GitHub Actions / Build-And-Test-MacOS

The variable 'declName' is declared but never used
switch (decl)
{
case Machine machine:
if (!machine.IsSpec)
{
WriteMachine(context, output, machine);
}

break;
}
}

private void WriteMachine(CompilationContext context, StringWriter output, Machine machine)
{

context.WriteLine(output, $"const {machine.Name} = createMachine<Context>({{");
context.WriteLine(output, $"id: \"{machine.Name}\",");

//Code start state of machine.
context.WriteLine(output,$"initial: \"{machine.StartState.Name}\", ");

//Code up the states in each machine.
context.WriteLine(output, "states: {");
foreach (State state in machine.States)
{

context.WriteLine(output,$"{state.Name}: {{");
WriteState(context, output, state);
context.WriteLine(output, state.Equals(machine.States.Last()) ? "}" : "},");
}
context.WriteLine(output, "}");
context.WriteLine(output, "});");
}

private void WriteState(CompilationContext context, StringWriter output, State state)
{
//Entry function exists!
if (state.Entry != null) {
foreach (var s in state.Entry.Body.Statements) {
if (s.GetType() == typeof(GotoStmt)) {
var x = (GotoStmt)s;
context.WriteLine(output, "always: [");
context.WriteLine(output, $"{{target: '{x.State.Name}'}}");
context.WriteLine(output, "]");
}
}
}
var gotoStmts = new List<(String, String)>();
foreach (var pair in state.AllEventHandlers)
{
var handledEvent = pair.Key;

//context.WriteLine(output, $"{pair.Value}");
switch (pair.Value)
{
case EventGotoState goAct:
gotoStmts.Add((goAct.Trigger.Name, goAct.Target.Name));
break;
case EventDoAction doAct:
foreach (var stmt in doAct.Target.Body.Statements)
{
if (stmt.GetType() == typeof(GotoStmt))
{
var gotoS = (GotoStmt)stmt;
gotoStmts.Add((doAct.Trigger.Name, gotoS.State.Name));
}
}
break;

}
}
if (gotoStmts.Any())
{
context.WriteLine(output, "on: {");
foreach (var stmt in gotoStmts)
{
context.WriteLine(output, $"{stmt.Item1} : {{ target: \"{stmt.Item2}\"}},");
}
context.WriteLine(output, "}");
}

}
private void WriteSourcePrologue(CompilationContext context, StringWriter output)
{
context.WriteLine(output, "import { createMachine, assign } from 'xstate';");
context.WriteLine(output, "interface Context {retries: number;}");
}
}
}
2 changes: 2 additions & 0 deletions Src/PCompiler/CompilerCore/Backend/TargetLanguage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Plang.Compiler.Backend.C;
using Plang.Compiler.Backend.CSharp;
using Plang.Compiler.Backend.Java;
using Plang.Compiler.Backend.Stately;
using Plang.Compiler.Backend.Symbolic;

namespace Plang.Compiler.Backend
Expand All @@ -17,6 +18,7 @@ static TargetLanguage()
RegisterCodeGenerator(CompilerOutput.C, new CCodeGenerator());
RegisterCodeGenerator(CompilerOutput.Java, new JavaCompiler());
RegisterCodeGenerator(CompilerOutput.Symbolic, new SymbolicCodeGenerator());
RegisterCodeGenerator(CompilerOutput.Stately, new StatelyCodeGenerator());
}

private static void RegisterCodeGenerator(CompilerOutput name, ICodeGenerator generator)
Expand Down
3 changes: 2 additions & 1 deletion Src/PCompiler/CompilerCore/CompilerOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public enum CompilerOutput
C,
Symbolic,
CSharp,
Java
Java,
Stately
}
}
5 changes: 3 additions & 2 deletions Src/PCompiler/PCommandLine/Options/PCompilerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ internal PCompilerOptions()
pfilesGroup.AddArgument("projname", "pn", "Project name for the compiled output");
pfilesGroup.AddArgument("outdir", "o", "Dump output to directory (absolute or relative path)");

var modes = Parser.AddArgument("mode", "md", "Compilation mode :: (bugfinding, verification, coverage, pobserve). (default: bugfinding)");
modes.AllowedValues = new List<string>() { "bugfinding", "verification", "coverage", "pobserve" };
var modes = Parser.AddArgument("mode", "md", "Compilation mode :: (bugfinding, verification, coverage, pobserve, stately). (default: bugfinding)");
modes.AllowedValues = new List<string>() { "bugfinding", "verification", "coverage", "pobserve", "stately" };
modes.IsHidden = true;
}

Expand Down Expand Up @@ -163,6 +163,7 @@ private static void UpdateConfigurationWithParsedArgument(CompilerConfiguration
"verification" => CompilerOutput.Symbolic,
"coverage" => CompilerOutput.Symbolic,
"pobserve" => CompilerOutput.Java,
"stately" => CompilerOutput.Stately,
_ => compilerConfiguration.OutputLanguage
};
compilerConfiguration.Backend = TargetLanguage.GetCodeGenerator(compilerConfiguration.OutputLanguage);
Expand Down

0 comments on commit 191c133

Please sign in to comment.