Created
September 6, 2021 05:53
-
-
Save brianpos/2f2d33a0f22ef566947bc4a5b7dc1eb8 to your computer and use it in GitHub Desktop.
StructureMap Serialization for FHIR Mapping Language
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// https://hl7.org/fhir/mapping.g4 | |
/// </summary> | |
public class StructureMap_Serializer | |
{ | |
public string Write_structureMap(StructureMap sm) | |
{ | |
// mapId structure* imports* group+ EOF | |
StringBuilder sb = new StringBuilder(); | |
sb.AppendLine(Write_mapId(sm)); | |
foreach (var structure_ in sm.Structure) | |
sb.AppendLine(Write_structure(structure_)); | |
foreach (var import in sm.Import) | |
sb.AppendLine(Write_imports(import)); | |
foreach (var group in sm.Group) | |
sb.AppendLine(Write_group(group)); | |
return sb.ToString(); | |
} | |
string Write_mapId(StructureMap sm) | |
{ | |
// 'map' url '=' identifier | |
return string.Join(" ", | |
"map", Write_url(sm.Url), "=", Write_identifier(sm.Name)); | |
} | |
string Write_url(string value) | |
{ | |
// DELIMITEDIDENTIFIER | |
return Write_delimitedIdentifier(value); | |
} | |
string Write_delimitedIdentifier(string value) | |
{ | |
var delimited = value.Replace("\"", "\\\""); | |
return $"\"{delimited}\""; | |
} | |
string Write_identifier(string value) | |
{ | |
// IDENTIFIER | |
// | DELIMITEDIDENTIFIER | |
if (string.IsNullOrEmpty(value)) | |
return null; | |
Regex r = new Regex("^([A-Za-z]|'_')([A-Za-z0-9]|'_')*$"); | |
if (r.IsMatch(value)) | |
return value; | |
return "\"" + value.Replace("\"", "\\\"") + "\""; | |
} | |
string Write_structure(StructureMap.StructureComponent structure_) | |
{ | |
// 'uses' url structureAlias? 'as' modelMode | |
return String.Join(" ", | |
"uses", Write_url(structure_.Url), Write_structureAlias(structure_.Alias), "as", structure_.Mode.GetLiteral()); | |
} | |
string Write_structureAlias(string alias) | |
{ | |
// 'alias' identifier | |
if (!string.IsNullOrEmpty(alias)) | |
return String.Join(" ", | |
"alias", Write_identifier(alias)); | |
return null; | |
} | |
string Write_imports(string url) | |
{ | |
// 'imports' url | |
return String.Join(" ", | |
"imports", Write_url(url)); | |
} | |
string Write_group(StructureMap.GroupComponent group) | |
{ | |
// 'group' identifier parameters extends? typeMode? rules | |
StringBuilder sb = new StringBuilder(); | |
sb.Append("group "); | |
sb.Append(Write_identifier(group.Name)); | |
sb.Append(" " + Write_parameters(group.Input)); | |
if (!String.IsNullOrEmpty(group.Extends)) | |
sb.Append(" " + Write_extends(group.Extends)); | |
if (group.TypeMode.HasValue) | |
sb.Append(" " + Write_typeMode(group.TypeMode.GetLiteral())); | |
sb.Append(Write_rules(group.Rule)); | |
return sb.ToString(); | |
} | |
string Write_rules(IEnumerable<StructureMap.RuleComponent> rules) | |
{ | |
// '{' rule+ '}' | |
StringBuilder sb = new StringBuilder(); | |
sb.AppendLine(); | |
sb.AppendLine("{"); | |
foreach (var rule in rules) | |
sb.AppendLine(Write_rule(rule)); | |
sb.AppendLine("}"); | |
return sb.ToString(); | |
} | |
string Write_typeMode(string typeMode) | |
{ | |
// '<<' groupTypeMode '>>' | |
return "<<" + typeMode + ">>"; | |
} | |
string Write_extends(string extends) | |
{ | |
// 'extends' identifier | |
return string.Join(" ", | |
"extends", Write_identifier(extends)); | |
} | |
string Write_parameters(IEnumerable<StructureMap.InputComponent> inputs) | |
{ | |
// '(' parameter (',' parameter)+ ')' | |
return "(" + string.Join(", ", inputs.Select(input => Write_parameter(input))) + ")"; | |
} | |
string Write_parameter(StructureMap.InputComponent input) | |
{ | |
// inputMode identifier type? | |
return String.Join(" ", | |
input.Mode.GetLiteral(), Write_identifier(input.Name), Write_type(input.Type)); | |
} | |
string Write_type(string type) | |
{ | |
// ':' identifier | |
return ": " + Write_identifier(type); | |
} | |
string Write_rule(StructureMap.RuleComponent rule) | |
{ | |
// ruleSources ('->' ruleTargets)? dependent? ruleName? ';' | |
StringBuilder sb = new StringBuilder(); | |
sb.Append(Write_ruleSources(rule.Source)); | |
if (rule.Target.Any()) | |
{ | |
sb.Append(" -> "); | |
sb.Append(Write_ruleTargets(rule.Target)); | |
} | |
if (rule.Dependent.Any()) | |
{ | |
sb.Append(" " + Write_dependent(rule, rule.Dependent)); | |
} | |
if (!string.IsNullOrEmpty(rule.Name)) | |
sb.Append(" " + Write_ruleName(rule.Name)); | |
sb.Append(";"); | |
if (!string.IsNullOrEmpty(rule.Documentation)) | |
sb.Append("// " + rule.Documentation); | |
return sb.ToString(); | |
} | |
string Write_ruleName(string name) | |
{ | |
// DELIMITEDIDENTIFIER | |
return Write_delimitedIdentifier(name); | |
} | |
string Write_ruleSources(IEnumerable<StructureMap.SourceComponent> sources) | |
{ | |
// ruleSource (',' ruleSource)* | |
return String.Join(", ", sources.Select(source => Write_ruleSource(source))); | |
} | |
string Write_ruleSource(StructureMap.SourceComponent source) | |
{ | |
// ruleContext sourceType? sourceDefault? sourceListMode? alias? whereClause? checkClause? log? | |
StringBuilder sb = new StringBuilder(); | |
sb.Append(" " + Write_ruleContext(source.Context, source.Element)); | |
if (!string.IsNullOrEmpty(source.Type)) | |
{ | |
sb.Append(" " + Write_sourceType(source)); | |
} | |
if (source.DefaultValue != null) | |
{ | |
sb.Append(" " + Write_sourceDefault(source)); | |
} | |
if (source.ListMode.HasValue) | |
{ | |
sb.Append($" {source.ListMode.GetLiteral()}"); | |
} | |
if (!string.IsNullOrEmpty(source.Variable)) | |
{ | |
sb.Append(" " + Write_alias(source.Variable)); | |
} | |
if (!string.IsNullOrEmpty(source.Condition)) | |
{ | |
sb.Append(" " + Write_whereClause(source.Condition)); | |
} | |
if (!string.IsNullOrEmpty(source.Check)) | |
{ | |
sb.Append(" " + Write_checkClause(source.Check)); | |
} | |
if (!string.IsNullOrEmpty(source.LogMessage)) | |
{ | |
sb.Append(" " + Write_log(source.LogMessage)); | |
} | |
return sb.ToString(); | |
} | |
string Write_ruleTargets(IEnumerable<StructureMap.TargetComponent> targets) | |
{ | |
// ruleTarget (',' ruleTarget)* | |
return String.Join(", ", targets.Select(target => Write_ruleTarget(target))); | |
} | |
string Write_sourceType(StructureMap.SourceComponent source) | |
{ | |
// identifier (INTEGER '..' upperBound)? | |
StringBuilder sb = new StringBuilder(); | |
sb.Append(Write_identifier(source.Type)); | |
if (source.Min.HasValue || !string.IsNullOrEmpty(source.Max)) | |
{ | |
sb.Append(" ("); | |
sb.Append(source.Min); | |
sb.Append(" .. "); | |
sb.Append(Write_upperBound(source.Max)); | |
sb.Append(")"); | |
} | |
return sb.ToString(); | |
} | |
string Write_upperBound(string upper) | |
{ | |
// INTEGER | |
// | '*' | |
if (!string.IsNullOrEmpty(upper)) | |
return upper; | |
return "*"; | |
} | |
string Write_ruleContext(string context, string element) | |
{ | |
// identifier ('.' identifier)? | |
if (!string.IsNullOrEmpty(element)) | |
return Write_identifier(context) + "." + Write_identifier(element); | |
return Write_identifier(context); | |
} | |
string Write_sourceDefault(Element value) | |
{ | |
// 'default' fhirPath | |
if (value is FhirString fs) | |
return "default " + Write_fhirPath(fs.Value); | |
return null; | |
} | |
string Write_alias(string value) | |
{ | |
// 'as' identifier | |
return "as " + Write_identifier(value); | |
} | |
string Write_whereClause(string value) | |
{ | |
// 'where' fhirPath | |
return " where " + Write_fhirPath(value); | |
} | |
string Write_checkClause(string value) | |
{ | |
// 'check' fhirPath | |
return " check " + Write_fhirPath(value); | |
} | |
string Write_log(string fhirpath) | |
{ | |
// 'log' fhirPath | |
return "log " + Write_fhirPath(fhirpath); | |
} | |
string Write_dependent(StructureMap.RuleComponent rule, IEnumerable<StructureMap.DependentComponent> dependents) | |
{ | |
// 'then' (invocation | rules) | |
if (rule.Rule.Any()) | |
return " then" + Write_rules(rule.Rule); | |
return " then" + Write_invocation(rule); | |
} | |
string Write_ruleTarget(StructureMap.TargetComponent target) | |
{ | |
// ruleContext ('=' transform)? alias? targetListMode? | |
// | invocation alias? // alias is not required when simply invoking a group | |
StringBuilder sb = new StringBuilder(); | |
if (!string.IsNullOrEmpty(target.Context)) | |
{ | |
sb.Append(" " + Write_ruleContext(target.Context, target.Element)); | |
if (target.Transform.HasValue) | |
sb.Append(" = " + Write_transform(target)); | |
if (!string.IsNullOrEmpty(target.Variable)) | |
{ | |
sb.Append(" " + Write_alias(target.Variable)); | |
} | |
if (target.ListMode.Any()) | |
sb.Append(" " + target.ListMode.First().GetLiteral()); | |
} | |
else | |
{ | |
// invocation | |
if (!string.IsNullOrEmpty(target.Variable)) | |
{ | |
sb.Append(" " + Write_alias(target.Variable)); | |
} | |
} | |
return sb.ToString(); | |
} | |
string Write_transform(StructureMap.TargetComponent target) | |
{ | |
if (target.Transform == StructureMap.StructureMapTransform.Copy) | |
{ | |
return Write_ruleContext(target.Context, target.Element); | |
} | |
if (target.Transform == StructureMap.StructureMapTransform.Evaluate && target.Parameter.Count() == 1) | |
{ | |
if (target.Parameter.First().Value is FhirString fs) | |
{ | |
string value = fs.Value; | |
value.Replace("\"", "\\\""); | |
return $"\"{value}\""; | |
} | |
} | |
// literal // trivial constant transform | |
// | ruleContext // 'copy' transform | |
// | invocation // other named transforms | |
return ""; | |
} | |
string Write_invocation(StructureMap.RuleComponent rule) | |
{ | |
// identifier '(' paramList? ')' | |
// return $"{target.Transform.GetLiteral()}({Write_paramList(target.Parameter)})"; | |
return ""; | |
} | |
string Write_invocation(StructureMap.TargetComponent target) | |
{ | |
// identifier '(' paramList? ')' | |
return $"{target.Transform.GetLiteral()}({Write_paramList(target.Parameter)})"; | |
} | |
string Write_paramList(IEnumerable<StructureMap.ParameterComponent> parameters) | |
{ | |
// param (',' param)* | |
return String.Join(", ", parameters.Select(parameter => Write_param(parameter))); | |
} | |
string Write_param(StructureMap.ParameterComponent parameter) | |
{ | |
// literal | |
// | identifier | |
if (parameter.Value is Id id) | |
return id.Value; | |
if (parameter.Value is FhirString fs) | |
return fs.Value; | |
if (parameter.Value is FhirBoolean fb) | |
return fb.Value.ToString(); | |
if (parameter.Value is Integer i) | |
return i.Value.ToString(); | |
if (parameter.Value is FhirDecimal fd) | |
return fd.Value.ToString(); | |
return ""; | |
} | |
string Write_fhirPath(string fhirpath) | |
{ | |
// literal // insert reference to FhirPath grammar here | |
return fhirpath; | |
} | |
/* | |
literal | |
: INTEGER | |
| NUMBER | |
| STRING | |
| DATETIME | |
| TIME | |
| BOOL | |
; | |
groupTypeMode | |
: 'types' | 'type+' | |
; | |
sourceListMode | |
: 'first' | 'not_first' | 'last' | 'not_last' | 'only_one' | |
; | |
targetListMode | |
: 'first' | 'share' | 'last' | 'collate' | |
; | |
inputMode | |
: 'source' | 'target' | |
; | |
modelMode // StructureMapModelMode binding | |
: 'source' | 'queried' | 'target' | 'produced' | |
; | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment