From f5d5e62edb83769e873d2587d346f98e655ae662 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Thu, 3 Sep 2026 16:18:22 -1000 Subject: [PATCH 01/11] Add IMMZ conformance spike: compile all WHO maps + execute C4 (diagnostic) Result on current main: 0/16 WHO smart-immunizations FML maps compile ("StructureMap must have at least one group"). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../fmlrunner/ImmzConformanceSpike.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt new file mode 100644 index 0000000..873ce1b --- /dev/null +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt @@ -0,0 +1,51 @@ +package org.litlfred.fmlrunner + +import java.io.File +import kotlin.test.Test + +/** + * Conformance spike: feed fmlrunner WHO smart-immunizations content verbatim + * and report how far it gets. Fixtures from github.com/dhes/fmlrunner-conformance + * (reference-engine oracles); FML sources from the IG's input/maps. + * + * Diagnostic, not pass/fail: prints a stage-by-stage ledger. + */ +class ImmzConformanceSpike { + + private val mapsDir = File(System.getProperty("user.home"), "projects/smart-immunizations-fresher/input/maps") + private val fixturesDir = File(System.getProperty("user.home"), "projects/fmlrunner-conformance") + + @Test + fun c4EndToEnd() { + val runner = FmlRunner() + + // Stage 1: compile every IMMZ FML source + println("=== Stage 1: compile all IMMZ FML maps ===") + var compiled = 0 + mapsDir.listFiles { f -> f.extension == "fml" }?.sortedBy { it.name }?.forEach { f -> + val r = runner.compileFml(f.readText()) + if (r.success && r.structureMap != null) { + runner.registerStructureMap(r.structureMap!!) + compiled++ + println("COMPILE OK ${f.name} -> ${r.structureMap!!.url}") + } else { + println("COMPILE FAIL ${f.name}: ${r.errors.take(2)}") + } + } + println("compiled $compiled maps") + + // Stage 2: execute C4 QRToPatient on the published QR example + println("=== Stage 2: execute IMMZ.C4.QRToPatient on published QR ===") + val qr = File(fixturesDir, "package/example/QuestionnaireResponse-Example.IMMZ.C.QuestionnaireResponse.1.json").readText() + val exec = runner.executeStructureMap( + "http://smart.who.int/immunizations/StructureMap/IMMZ.C4.QRToPatient", qr + ) + println("execute success=${exec.success}") + exec.errors.take(5).forEach { println(" error: $it") } + exec.warnings.take(5).forEach { println(" warning: $it") } + println("--- output (first 1500 chars) ---") + println(exec.result?.take(1500) ?: "(null result)") + println("--- oracle (first 600 chars, for eyeball) ---") + println(File(fixturesDir, "oracle/IMMZ.C4.QRToPatient__C.QuestionnaireResponse.1.json").readText().take(600)) + } +} From b5e9ca03860b21e965471ffba6d3884fe12bafc8 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Thu, 3 Sep 2026 16:30:35 -1000 Subject: [PATCH 02/11] Parse FML headers: block comments, uses/imports, typed group inputs, line-numbered errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 16 WHO smart-immunizations maps now clear the header and reach rule parsing (previously 0 — every map died before its first group). Adds structure/import to the StructureMap type (FHIR R4 shape), '/* */' comment lexing, 'uses ... alias X as mode' and 'imports ...' clauses, optional ':' types on group inputs, and token line/context on all parser errors. Corpus status: 0/16 compile (failures now inside rule bodies — next rung). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 4 +- .../fmlrunner/compiler/FmlCompiler.kt | 122 +++++++++++++++--- .../org/litlfred/fmlrunner/types/FhirTypes.kt | 15 +++ 4 files changed, 118 insertions(+), 23 deletions(-) diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index f7af2115e9189e665cce0c6b2a05acab4fa236f8..8e868542c37c853e4bb98cb84ce6eee72c6f556c 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~jzz0RS)i1SJ3f literal 17 VcmZRc8C-F+LssMw0~jz}1^_T}1f2i? diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index 195f502..ad193af 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Mon Sep 29 13:56:43 UTC 2025 -gradle.version=9.1.0 +#Thu Sep 03 16:11:41 HST 2026 +gradle.version=8.14.2 diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt index 17b7cbf..fcb0dec 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt @@ -92,6 +92,18 @@ class FmlTokenizer(private val input: String) { } return Token(TokenType.COMMENT, input.substring(start, position), startLine, startColumn) } + if (peek() == '*') { + // Block comment + advance() + while (!isAtEnd() && !(peek() == '*' && position + 1 < input.length && input[position + 1] == '/')) { + advance() + } + if (!isAtEnd()) { + advance() // '*' + advance() // '/' + } + return Token(TokenType.COMMENT, input.substring(start, position), startLine, startColumn) + } } // Handle strings @@ -228,26 +240,43 @@ class FmlParser(private val tokens: List) { private fun parseStructureMap(): StructureMap { // Expect "map" if (!match(TokenType.MAP)) { - throw IllegalArgumentException("Expected 'map' keyword at start of StructureMap") + throw IllegalArgumentException(err("Expected 'map' keyword at start of StructureMap")) } // Parse URL val url = if (peek().type == TokenType.STRING) { advance().value } else { - throw IllegalArgumentException("Expected URL string after 'map'") + throw IllegalArgumentException(err("Expected URL string after 'map'")) } // Parse "=" if (!match(TokenType.EQUALS)) { - throw IllegalArgumentException("Expected '=' after URL") + throw IllegalArgumentException(err("Expected '=' after URL")) } // Parse name val name = if (peek().type == TokenType.STRING) { advance().value } else { - throw IllegalArgumentException("Expected name string after '='") + throw IllegalArgumentException(err("Expected name string after '='")) + } + + // Parse header declarations: uses ... / imports ... + val structures = mutableListOf() + val imports = mutableListOf() + while (true) { + when (peek().type) { + TokenType.USES -> structures.add(parseUses()) + TokenType.IMPORTS -> { + advance() + if (peek().type != TokenType.STRING) { + throw IllegalArgumentException(err("Expected URL string after 'imports'")) + } + imports.add(advance().value) + } + else -> break + } } // Parse groups @@ -257,30 +286,70 @@ class FmlParser(private val tokens: List) { } if (groups.isEmpty()) { - throw IllegalArgumentException("StructureMap must have at least one group") + throw IllegalArgumentException(err("StructureMap must have at least one group")) } return StructureMap( url = url, name = name, status = StructureMapStatus.ACTIVE, + structure = structures.ifEmpty { null }, + import = imports.ifEmpty { null }, group = groups ) } + // uses "url" [alias Name] as source|queried|target|produced + private fun parseUses(): StructureMapStructure { + advance() // 'uses' + if (peek().type != TokenType.STRING) { + throw IllegalArgumentException(err("Expected URL string after 'uses'")) + } + val url = advance().value + var alias: String? = null + if (peek().type == TokenType.ALIAS) { + advance() + if (peek().type != TokenType.IDENTIFIER) { + throw IllegalArgumentException(err("Expected alias name after 'alias'")) + } + alias = advance().value + } + if (peek().type != TokenType.AS) { + throw IllegalArgumentException(err("Expected 'as' in uses declaration")) + } + advance() + if (peek().type != TokenType.IDENTIFIER) { + throw IllegalArgumentException(err("Expected model mode after 'as'")) + } + val modeStr = advance().value + val mode = when (modeStr.lowercase()) { + "source" -> StructureMapModelMode.SOURCE + "queried" -> StructureMapModelMode.QUERIED + "target" -> StructureMapModelMode.TARGET + "produced" -> StructureMapModelMode.PRODUCED + else -> throw IllegalArgumentException(err("Invalid model mode: $modeStr")) + } + return StructureMapStructure(url = url, mode = mode, alias = alias) + } + + private fun err(message: String): String { + val t = peek() + return "$message (line ${t.line}, near '${t.value.take(20)}')" + } + private fun parseGroup(): StructureMapGroup { if (!match(TokenType.GROUP)) { - throw IllegalArgumentException("Expected 'group' keyword") + throw IllegalArgumentException(err("Expected 'group' keyword")) } val name = if (peek().type == TokenType.IDENTIFIER) { advance().value } else { - throw IllegalArgumentException("Expected group name") + throw IllegalArgumentException(err("Expected group name")) } if (!match(TokenType.LPAREN)) { - throw IllegalArgumentException("Expected '(' after group name") + throw IllegalArgumentException(err("Expected '(' after group name")) } // Parse inputs @@ -289,17 +358,17 @@ class FmlParser(private val tokens: List) { inputs.add(parseInput()) if (!check(TokenType.RPAREN)) { if (!match(TokenType.COMMA)) { - throw IllegalArgumentException("Expected ',' between inputs") + throw IllegalArgumentException(err("Expected ',' between inputs")) } } } if (!match(TokenType.RPAREN)) { - throw IllegalArgumentException("Expected ')' after inputs") + throw IllegalArgumentException(err("Expected ')' after inputs")) } if (!match(TokenType.LBRACE)) { - throw IllegalArgumentException("Expected '{' to start group body") + throw IllegalArgumentException(err("Expected '{' to start group body")) } // Parse rules @@ -309,7 +378,7 @@ class FmlParser(private val tokens: List) { } if (!match(TokenType.RBRACE)) { - throw IllegalArgumentException("Expected '}' to end group body") + throw IllegalArgumentException(err("Expected '}' to end group body")) } return StructureMapGroup( @@ -326,20 +395,31 @@ class FmlParser(private val tokens: List) { when (modeStr.lowercase()) { "source" -> InputMode.SOURCE "target" -> InputMode.TARGET - else -> throw IllegalArgumentException("Invalid input mode: $modeStr") + else -> throw IllegalArgumentException(err("Invalid input mode: $modeStr")) } } - else -> throw IllegalArgumentException("Expected input mode (source/target)") + else -> throw IllegalArgumentException(err("Expected input mode (source/target)")) } val name = if (peek().type == TokenType.IDENTIFIER) { advance().value } else { - throw IllegalArgumentException("Expected input name") + throw IllegalArgumentException(err("Expected input name")) + } + + // Optional type: `source qr : QResp` + var type: String? = null + if (match(TokenType.COLON)) { + type = if (peek().type == TokenType.IDENTIFIER) { + advance().value + } else { + throw IllegalArgumentException(err("Expected input type after ':'")) + } } return StructureMapGroupInput( name = name, + type = type, mode = mode ) } @@ -352,7 +432,7 @@ class FmlParser(private val tokens: List) { // Expect arrow if (!match(TokenType.ARROW)) { - throw IllegalArgumentException("Expected '->' in rule") + throw IllegalArgumentException(err("Expected '->' in rule")) } // Parse targets @@ -361,7 +441,7 @@ class FmlParser(private val tokens: List) { // Expect semicolon if (!match(TokenType.SEMICOLON)) { - throw IllegalArgumentException("Expected ';' to end rule") + throw IllegalArgumentException(err("Expected ';' to end rule")) } return StructureMapGroupRule( @@ -374,7 +454,7 @@ class FmlParser(private val tokens: List) { val context = if (peek().type == TokenType.IDENTIFIER) { advance().value } else { - throw IllegalArgumentException("Expected source context") + throw IllegalArgumentException(err("Expected source context")) } var element: String? = null @@ -382,7 +462,7 @@ class FmlParser(private val tokens: List) { element = if (peek().type == TokenType.IDENTIFIER) { advance().value } else { - throw IllegalArgumentException("Expected element name after '.'") + throw IllegalArgumentException(err("Expected element name after '.'")) } } @@ -396,7 +476,7 @@ class FmlParser(private val tokens: List) { val context = if (peek().type == TokenType.IDENTIFIER) { advance().value } else { - throw IllegalArgumentException("Expected target context") + throw IllegalArgumentException(err("Expected target context")) } var element: String? = null @@ -404,7 +484,7 @@ class FmlParser(private val tokens: List) { element = if (peek().type == TokenType.IDENTIFIER) { advance().value } else { - throw IllegalArgumentException("Expected element name after '.'") + throw IllegalArgumentException(err("Expected element name after '.'")) } } diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt index 3975c6f..ee15889 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt @@ -15,9 +15,24 @@ data class StructureMap( val status: StructureMapStatus, val experimental: Boolean? = null, val description: String? = null, + val structure: List? = null, + val import: List? = null, val group: List ) +@Serializable +data class StructureMapStructure( + val url: String, + val mode: StructureMapModelMode, + val alias: String? = null, + val documentation: String? = null +) + +@Serializable +enum class StructureMapModelMode { + SOURCE, QUERIED, TARGET, PRODUCED +} + @Serializable enum class StructureMapStatus { DRAFT, ACTIVE, RETIRED, UNKNOWN From b7d07a28692790c7f6631c9a308337721770600d Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Thu, 3 Sep 2026 16:40:33 -1000 Subject: [PATCH 03/11] Full FML rule grammar: 16/16 WHO smart-immunizations maps now compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrites rule parsing to the spec shape the WHO corpus exercises: comma-separated sources/targets; source list modes, 'as' bindings, and where/check FHIRPath capture (tokens re-joined; strings re-quoted); target transform invocations (create/append/translate/c/uuid), '=' copy/evaluate forms, and literal params in FHIR value[x] shape; nested 'then { }' rule blocks; dependent group calls; trailing rule names. Adds rule/dependent/listMode/condition/check to the types and switches transform parameters from List to TransformParameter. Corpus: 16/16 compile (was 0/16). Execution is NOT there yet: the executor returns success=true with an empty {} for C4 — silent no-op output; that wall is next. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../fmlrunner/compiler/FmlCompiler.kt | 239 +++++++++++++++--- .../executor/StructureMapExecutor.kt | 8 +- .../org/litlfred/fmlrunner/types/FhirTypes.kt | 30 ++- 4 files changed, 238 insertions(+), 39 deletions(-) diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 8e868542c37c853e4bb98cb84ce6eee72c6f556c..b3fa9271e865912580447a0a6c1b089347dd5673 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~j!`001ya1aklY literal 17 VcmZRc8C-F+LssMw0~jzz0RS)i1SJ3f diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt index fcb0dec..c15dd9c 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt @@ -425,76 +425,249 @@ class FmlParser(private val tokens: List) { } private fun parseRule(): StructureMapGroupRule { - val sources = mutableListOf() - - // Parse source - sources.add(parseRuleSource()) + val sources = mutableListOf(parseRuleSource()) + while (match(TokenType.COMMA)) sources.add(parseRuleSource()) - // Expect arrow - if (!match(TokenType.ARROW)) { - throw IllegalArgumentException(err("Expected '->' in rule")) + var targets: MutableList? = null + if (match(TokenType.ARROW)) { + targets = mutableListOf(parseRuleTarget()) + while (match(TokenType.COMMA)) targets.add(parseRuleTarget()) } - // Parse targets - val targets = mutableListOf() - targets.add(parseRuleTarget()) + var nested: MutableList? = null + var dependents: MutableList? = null + if (peek().type == TokenType.IDENTIFIER && peek().value == "then") { + advance() + if (match(TokenType.LBRACE)) { + nested = mutableListOf() + while (!check(TokenType.RBRACE) && !isAtEnd()) { + nested.add(parseRule()) + } + if (!match(TokenType.RBRACE)) { + throw IllegalArgumentException(err("Expected '}' to end nested rules")) + } + } else { + dependents = mutableListOf(parseDependent()) + while (match(TokenType.COMMA)) dependents.add(parseDependent()) + } + } + + var name: String? = null + if (peek().type == TokenType.STRING) { + name = advance().value + } - // Expect semicolon if (!match(TokenType.SEMICOLON)) { throw IllegalArgumentException(err("Expected ';' to end rule")) } return StructureMapGroupRule( + name = name, source = sources, - target = targets + target = targets, + rule = nested, + dependent = dependents ) } - private fun parseRuleSource(): StructureMapGroupRuleSource { - val context = if (peek().type == TokenType.IDENTIFIER) { - advance().value - } else { - throw IllegalArgumentException(err("Expected source context")) + private fun parseDependent(): StructureMapGroupRuleDependent { + val name = expectIdentifier("dependent group name") + if (!match(TokenType.LPAREN)) { + throw IllegalArgumentException(err("Expected '(' after dependent group name")) + } + val variables = mutableListOf() + while (!check(TokenType.RPAREN)) { + variables.add(expectIdentifier("dependent variable")) + if (!check(TokenType.RPAREN) && !match(TokenType.COMMA)) { + throw IllegalArgumentException(err("Expected ',' between dependent variables")) + } } + advance() // ')' + return StructureMapGroupRuleDependent(name = name, variable = variables) + } + private fun parseRuleSource(): StructureMapGroupRuleSource { + val context = expectIdentifier("source context") var element: String? = null if (match(TokenType.DOT)) { - element = if (peek().type == TokenType.IDENTIFIER) { - advance().value - } else { - throw IllegalArgumentException(err("Expected element name after '.'")) + element = expectIdentifier("element name after '.'") + } + var listMode: String? = null + var variable: String? = null + var condition: String? = null + var checkExpr: String? = null + loop@ while (true) { + val t = peek() + when { + t.type == TokenType.IDENTIFIER && t.value in LIST_MODES && listMode == null -> + listMode = advance().value + t.type == TokenType.AS -> { + advance() + variable = expectIdentifier("variable name after 'as'") + } + t.type == TokenType.WHERE -> { + advance() + condition = captureExpression() + } + t.type == TokenType.CHECK -> { + advance() + checkExpr = captureExpression() + } + else -> break@loop } } - return StructureMapGroupRuleSource( context = context, - element = element + element = element, + variable = variable, + listMode = listMode, + condition = condition, + check = checkExpr ) } private fun parseRuleTarget(): StructureMapGroupRuleTarget { - val context = if (peek().type == TokenType.IDENTIFIER) { - advance().value - } else { - throw IllegalArgumentException(err("Expected target context")) + // Invocation form: create("...") as model, uuid() as pid, c(system, code) + if (peek().type == TokenType.IDENTIFIER && peekNext().type == TokenType.LPAREN) { + val fn = advance().value + val params = parseTransformParams() + var variable: String? = null + if (peek().type == TokenType.AS) { + advance() + variable = expectIdentifier("variable name after 'as'") + } + return StructureMapGroupRuleTarget( + variable = variable, + transform = fn, + parameter = params.ifEmpty { null } + ) } + // Context form: ctx('.' element)? ('=' transform)? ('as' var)? + val context = expectIdentifier("target context") var element: String? = null if (match(TokenType.DOT)) { - element = if (peek().type == TokenType.IDENTIFIER) { - advance().value - } else { - throw IllegalArgumentException(err("Expected element name after '.'")) + element = expectIdentifier("element name after '.'") + } + var transform: String? = null + var parameter: List? = null + if (match(TokenType.EQUALS)) { + val t = peek() + when { + t.type == TokenType.IDENTIFIER && peekNext().type == TokenType.LPAREN -> { + transform = advance().value + parameter = parseTransformParams().ifEmpty { null } + } + t.type == TokenType.STRING -> { + transform = "copy" + parameter = listOf(TransformParameter(valueString = advance().value)) + } + t.type == TokenType.NUMBER -> { + transform = "copy" + parameter = listOf(numberParam(advance().value)) + } + t.type == TokenType.IDENTIFIER -> { + var path = advance().value + if (check(TokenType.DOT)) { + while (match(TokenType.DOT)) { + path += "." + expectIdentifier("path segment") + } + transform = "evaluate" + parameter = listOf(TransformParameter(valueString = path)) + } else { + transform = "copy" + parameter = listOf(TransformParameter(valueId = path)) + } + } + else -> throw IllegalArgumentException(err("Expected transform after '='")) } } - + var variable: String? = null + if (peek().type == TokenType.AS) { + advance() + variable = expectIdentifier("variable name after 'as'") + } return StructureMapGroupRuleTarget( context = context, contextType = ContextType.VARIABLE, - element = element + element = element, + variable = variable, + transform = transform, + parameter = parameter ) } + private fun parseTransformParams(): List { + if (!match(TokenType.LPAREN)) { + throw IllegalArgumentException(err("Expected '(' to start parameters")) + } + val params = mutableListOf() + while (!check(TokenType.RPAREN)) { + val t = peek() + params.add(when (t.type) { + TokenType.STRING -> TransformParameter(valueString = advance().value) + TokenType.NUMBER -> numberParam(advance().value) + TokenType.IDENTIFIER -> when (t.value) { + "true" -> { advance(); TransformParameter(valueBoolean = true) } + "false" -> { advance(); TransformParameter(valueBoolean = false) } + else -> TransformParameter(valueId = advance().value) + } + else -> throw IllegalArgumentException(err("Expected parameter")) + }) + if (!check(TokenType.RPAREN) && !match(TokenType.COMMA)) { + throw IllegalArgumentException(err("Expected ',' between parameters")) + } + } + advance() // ')' + return params + } + + private fun numberParam(raw: String): TransformParameter = + if (raw.contains('.')) TransformParameter(valueDecimal = raw.toDouble()) + else TransformParameter(valueInteger = raw.toInt()) + + /** + * Capture a FHIRPath expression as raw-ish text: tokens joined with spaces + * (FHIRPath is whitespace-insensitive), strings re-quoted single. Stops at + * a rule boundary (->, ;, ',', as, check, then) at paren depth 0. + */ + private fun captureExpression(): String { + val sb = StringBuilder() + var depth = 0 + while (!isAtEnd()) { + val t = peek() + if (depth == 0 && (t.type == TokenType.ARROW || t.type == TokenType.SEMICOLON || + t.type == TokenType.COMMA || t.type == TokenType.AS || t.type == TokenType.CHECK || + (t.type == TokenType.IDENTIFIER && t.value == "then"))) break + if (t.type == TokenType.LPAREN) depth++ + if (t.type == TokenType.RPAREN) { + if (depth == 0) break + depth-- + } + if (sb.isNotEmpty()) sb.append(' ') + sb.append(if (t.type == TokenType.STRING) "'" + t.value + "'" else t.value) + advance() + } + if (sb.isEmpty()) { + throw IllegalArgumentException(err("Expected expression")) + } + return sb.toString() + } + + private fun expectIdentifier(what: String): String { + if (peek().type != TokenType.IDENTIFIER) { + throw IllegalArgumentException(err("Expected $what")) + } + return advance().value + } + + private fun peekNext(): Token = + if (current + 1 < tokens.size) tokens[current + 1] else tokens[tokens.size - 1] + + companion object { + private val LIST_MODES = setOf("first", "not_first", "last", "not_last", "only_one") + } + private fun match(type: TokenType): Boolean { if (check(type)) { advance() diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt index d6d1335..6a9af6c 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt @@ -167,12 +167,12 @@ class StructureMapExecutor { /** * Apply transformation function */ - private fun applyTransform(transform: String, value: JsonElement, parameters: List?): JsonElement { + private fun applyTransform(transform: String, value: JsonElement, parameters: List?): JsonElement { return when (transform.lowercase()) { "copy" -> value "create" -> { // Create new object/value based on parameters - parameters?.firstOrNull()?.let { type -> + parameters?.firstOrNull()?.let { p -> val type = p.valueString ?: p.valueId ?: "" when (type.lowercase()) { "string" -> JsonPrimitive("") "integer" -> JsonPrimitive(0) @@ -183,13 +183,13 @@ class StructureMapExecutor { } "cast" -> { // Type casting - parameters?.firstOrNull()?.let { targetType -> + parameters?.firstOrNull()?.let { p -> val targetType = p.valueString ?: p.valueId ?: "" castValue(value, targetType) } ?: value } "evaluate" -> { // Simple FHIRPath-like evaluation (basic implementation) - parameters?.firstOrNull()?.let { expression -> + parameters?.firstOrNull()?.let { p -> val expression = p.valueString ?: p.valueId ?: "" evaluateExpression(value, expression) } ?: value } diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt index ee15889..677d1ab 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt @@ -70,9 +70,17 @@ data class StructureMapGroupRule( val name: String? = null, val source: List, val target: List? = null, + val rule: List? = null, + val dependent: List? = null, val documentation: String? = null ) +@Serializable +data class StructureMapGroupRuleDependent( + val name: String, + val variable: List +) + @Serializable data class StructureMapGroupRuleSource( val context: String, @@ -80,7 +88,11 @@ data class StructureMapGroupRuleSource( val variable: String? = null, val type: String? = null, val min: Int? = null, - val max: String? = null + val max: String? = null, + val listMode: String? = null, + val condition: String? = null, + val check: String? = null, + val logMessage: String? = null ) @Serializable @@ -90,7 +102,21 @@ data class StructureMapGroupRuleTarget( val element: String? = null, val variable: String? = null, val transform: String? = null, - val parameter: List? = null + val parameter: List? = null, + val listMode: List? = null +) + +/** + * Transform parameter, FHIR R4 value[x] shape: valueId carries a variable + * reference, the others carry literals. + */ +@Serializable +data class TransformParameter( + val valueId: String? = null, + val valueString: String? = null, + val valueBoolean: Boolean? = null, + val valueInteger: Int? = null, + val valueDecimal: Double? = null ) @Serializable From 76b827905be72acec09a426469de656b58486eef Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Thu, 3 Sep 2026 17:06:10 -1000 Subject: [PATCH 04/11] Real StructureMap executor: 31/33 oracle fixtures match (was 0 with empty output) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the no-op executor with FmlEngine: execution over generic JSON trees (mutable target nodes; sources read from input JSON or from target-built logical-model instances), scope chains, import-aware dependent-group resolution, choice-type (value[x]) reads and writes, and the corpus's transform set — copy/create/append/uuid/translate (code|coding|display modes, real ConceptMaps)/c/evaluate. Unknown transforms and unresolved groups/variables are hard errors, never silent no-ops. Type-aware where the reference engine is: registered StructureDefinitions drive choice-element naming (declared LM element types beat lexical guessing) and singular-vs-repeating semantics (declared max 1 -> last write wins; computed re-writes of singular elements replace, creations append). Score vs github.com/dhes/fmlrunner-conformance oracles: 31/33 match, 0 errors. The 2 residual diffs are a reference-engine terminology quirk (drops the display it cannot verify for a LOINC coding on tx.fhir.org; keeps the same-shaped IMMZ coding's display) — our output renders the map faithfully. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../org/litlfred/fmlrunner/FmlRunner.kt | 70 ++- .../litlfred/fmlrunner/executor/FmlEngine.kt | 455 ++++++++++++++++++ .../executor/StructureMapExecutor.kt | 304 ------------ .../fmlrunner/ImmzConformanceSpike.kt | 120 +++-- 5 files changed, 610 insertions(+), 339 deletions(-) create mode 100644 src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt delete mode 100644 src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index b3fa9271e865912580447a0a6c1b089347dd5673..2945497929ef08ff7530db85980646db63ca12b2 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~oMO1^_TN1YZCE literal 17 VcmZRc8C-F+LssMw0~j!`001ya1aklY diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt index 0814f35..d93b646 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt @@ -2,7 +2,12 @@ package org.litlfred.fmlrunner import org.litlfred.fmlrunner.types.* import org.litlfred.fmlrunner.compiler.FmlCompiler -import org.litlfred.fmlrunner.executor.StructureMapExecutor +import org.litlfred.fmlrunner.executor.FmlEngine +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.contentOrNull import org.litlfred.fmlrunner.terminology.* /** @@ -11,8 +16,9 @@ import org.litlfred.fmlrunner.terminology.* */ class FmlRunner { private val compiler = FmlCompiler() - private val executor = StructureMapExecutor() private val structureMapStore = mutableMapOf() + private val conceptMapStore = mutableMapOf() + private val typeStore = mutableMapOf>() // SD url -> element leaf -> type code // kotlin-fhir terminology services private val conceptMapService = ConceptMapService() @@ -34,8 +40,58 @@ class FmlRunner { fun executeStructureMap(structureMapReference: String, inputContent: String, options: ExecutionOptions = ExecutionOptions()): ExecutionResult { val structureMap = getStructureMap(structureMapReference) ?: return ExecutionResult(success = false, errors = listOf("StructureMap not found: $structureMapReference")) + val source = try { + Json.parseToJsonElement(inputContent) + } catch (e: Exception) { + return ExecutionResult(success = false, errors = listOf("Invalid source JSON: ${e.message}")) + } + val engine = FmlEngine( + resolveMap = { ref -> getStructureMap(ref) }, + resolveConceptMap = { url -> conceptMapStore[url] }, + resolveElementTypes = { url -> typeStore[url] } + ) + return engine.execute(structureMap, source) + } - return executor.execute(structureMap, inputContent, options) + /** + * Register a StructureDefinition (JSON): declared element types drive + * choice-element ([x]) naming during execution. + */ + fun registerStructureDefinition(json: String): Boolean { + return try { + val o = Json.parseToJsonElement(json) as? JsonObject ?: return false + val url = (o["url"] as? JsonPrimitive)?.contentOrNull ?: return false + val elements = ((o["snapshot"] ?: o["differential"]) as? JsonObject) + ?.get("element") as? kotlinx.serialization.json.JsonArray ?: return false + val types = mutableMapOf() + for (el in elements) { + val eo = el as? JsonObject ?: continue + val id = (eo["id"] as? JsonPrimitive)?.contentOrNull ?: continue + val type = ((eo["type"] as? kotlinx.serialization.json.JsonArray) + ?.firstOrNull() as? JsonObject)?.get("code") as? JsonPrimitive ?: continue + val code = type.contentOrNull ?: continue + val max = (eo["max"] as? JsonPrimitive)?.contentOrNull ?: "1" + types[id.substringAfterLast('.')] = "$code|$max" + } + typeStore[url] = types + true + } catch (e: Exception) { + false + } + } + + /** + * Register a ConceptMap (JSON) for use by the translate() transform. + */ + fun registerConceptMap(json: String): Boolean { + return try { + val o = Json.parseToJsonElement(json) as? JsonObject ?: return false + val url = (o["url"] as? JsonPrimitive)?.contentOrNull ?: return false + conceptMapStore[url] = o + true + } catch (e: Exception) { + false + } } /** @@ -119,7 +175,13 @@ class FmlRunner { * Validate StructureMap structure */ fun validateStructureMap(structureMap: StructureMap): org.litlfred.fmlrunner.executor.ValidationResult { - return executor.validateStructureMap(structureMap) + val errors = mutableListOf() + if (structureMap.group.isEmpty()) errors.add("StructureMap must have at least one group") + structureMap.group.forEach { g -> + if (g.input.isEmpty()) errors.add("Group '${g.name}' has no inputs") + if (g.rule.isEmpty()) errors.add("Group '${g.name}' has no rules") + } + return org.litlfred.fmlrunner.executor.ValidationResult(valid = errors.isEmpty(), errors = errors) } /** diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt new file mode 100644 index 0000000..cb4b9f5 --- /dev/null +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt @@ -0,0 +1,455 @@ +package org.litlfred.fmlrunner.executor + +import kotlinx.serialization.json.* +import org.litlfred.fmlrunner.types.* +import kotlin.random.Random + +/** + * StructureMap execution over generic JSON trees. + * + * Sources are read from immutable JsonElements (or from target nodes built + * earlier, e.g. a logical-model instance created by `create(...)` and then + * used as the source input of a dependent group). Targets are built in a + * mutable tree and serialized at the end. + * + * Unknown transforms and unresolvable groups/variables are hard errors — + * never silent no-ops. + */ +data class ValidationResult( + val valid: Boolean, + val errors: List = emptyList(), + val warnings: List = emptyList() +) + +class FmlEngine( + private val resolveMap: (String) -> StructureMap?, + private val resolveConceptMap: (String) -> JsonObject? = { null }, + private val resolveElementTypes: (String) -> Map? = { null } +) { + + // ---- mutable target tree ---- + + sealed class MNode + class MObj : MNode() { + /** StructureDefinition url of the type this node instantiates, when known. */ + var typeUrl: String? = null + val fields = LinkedHashMap>() + fun append(name: String, node: MNode, replaceIfSingular: Boolean = false) { + val list = fields.getOrPut(name) { mutableListOf() } + // A computed re-write of a singular element replaces (last write wins, + // e.g. a default status then a translated one). Creation writes and + // known repeating elements always append. + if (replaceIfSingular && list.isNotEmpty() && name !in REPEATING_ELEMENTS) list.clear() + list.add(node) + } + } + class MPrim(val value: JsonPrimitive, val srcChoice: String? = null) : MNode() + + companion object { + /** FHIR repeating elements the corpus writes more than once per node. */ + val RESOURCE_TYPES = setOf( + "Patient", "RelatedPerson", "Observation", "Immunization", "AdverseEvent", + "Bundle", "Practitioner", "Encounter", "Condition", "Organization" + ) + val REPEATING_ELEMENTS = setOf( + "entry", "extension", "identifier", "name", "telecom", "address", + "given", "coding", "item", "answer", "contact", "performer", + "note", "reasonCode", "protocolApplied", "target", "contained" + ) + } + + private fun jsonToM(e: JsonElement): MNode = when (e) { + is JsonPrimitive -> MPrim(e) + is JsonObject -> MObj().also { o -> e.forEach { (k, v) -> + if (v is JsonArray) v.forEach { o.append(k, jsonToM(it)) } else o.append(k, jsonToM(v)) + } } + is JsonArray -> throw EngineError("Cannot bind a bare JSON array to a single node") + else -> throw EngineError("Unsupported JSON element") + } + + private fun mToJson(n: MNode): JsonElement? = when (n) { + is MPrim -> n.value + is MObj -> { + val o = buildMap { + for ((k, list) in n.fields) { + val items = list.mapNotNull { mToJson(it) } + if (items.isEmpty()) continue + put(k, if (items.size == 1) items[0] else JsonArray(items)) + } + } + if (o.isEmpty()) null else JsonObject(o) + } + } + + // ---- values & scopes ---- + + class EngineError(message: String) : Exception(message) + + private class Scope(val parent: Scope?) { + val vars = mutableMapOf() // JsonElement | MNode + fun lookup(name: String): Any? = vars[name] ?: parent?.lookup(name) + fun bind(name: String, v: Any) { vars[name] = v } + } + + /** Read child elements by name from a source-side value (choice-aware). */ + private fun readElement(v: Any, name: String): List { return when (v) { + is JsonObject -> { + val exact = v[name] + val hits = mutableListOf() + if (exact != null) { + if (exact is JsonArray) hits.addAll(exact) else hits.add(exact) + } else { + // choice type: value[x] + val tagged = mutableListOf() + v.forEach { (k, e) -> + if (k.length > name.length && k.startsWith(name) && k[name.length].isUpperCase()) { + val suffix = k.substring(name.length) + val elems = if (e is JsonArray) e.toList() else listOf(e) + elems.forEach { el -> + tagged.add(if (el is JsonPrimitive) MPrim(el, suffix) else el) + } + } + } + return tagged + } + hits + } + is MObj -> { + val exact = v.fields[name] + if (exact != null) { + val declared = v.typeUrl?.let { resolveElementTypes(it)?.get(name) }?.substringBefore('|') + if (declared != null && declared.first().isLowerCase()) { + return exact.map { hit -> + val prim = when { + hit is MPrim -> hit.value + hit is MObj && hit.fields.size == 1 -> + (hit.fields["value"]?.singleOrNull() as? MPrim)?.value + else -> null + } + if (prim != null) MPrim(prim, declared.replaceFirstChar { c -> c.uppercase() }) else hit + } + } + if (declared != null) { + // complex child of a typed node: nested element leaves resolve + // from the same (leaf-flattened) SD map + exact.forEach { hit -> if (hit is MObj && hit.typeUrl == null) hit.typeUrl = v.typeUrl } + } + exact.toList() + } else v.fields.entries + .filter { it.key.length > name.length && it.key.startsWith(name) && it.key[name.length].isUpperCase() } + .flatMap { it.value } + } + else -> emptyList() + } } + + private fun primString(v: Any?): String? = when (v) { + is JsonPrimitive -> v.contentOrNull + is MPrim -> v.value.contentOrNull + is MObj -> (v.fields["value"]?.firstOrNull() as? MPrim)?.value?.contentOrNull + is JsonObject -> (v["value"] as? JsonPrimitive)?.contentOrNull + else -> null + } + + // ---- entry ---- + + fun execute(map: StructureMap, source: JsonElement): ExecutionResult { + return try { + val group = map.group.firstOrNull() ?: throw EngineError("Map has no groups") + val scope = Scope(null) + var targetRoot: MObj? = null + var sourceBound = false + for (input in group.input) { + when (input.mode) { + InputMode.SOURCE -> { + if (!sourceBound) { scope.bind(input.name, source); sourceBound = true } + else throw EngineError("Multiple source inputs on entry group '${group.name}'") + } + InputMode.TARGET -> { + val root = MObj() + resourceTypeForInput(map, input)?.let { root.append("resourceType", MPrim(JsonPrimitive(it))) } + input.type?.let { alias -> + map.structure?.firstOrNull { it.alias == alias }?.url?.let { root.typeUrl = it } + } + if (targetRoot == null) targetRoot = root + scope.bind(input.name, root) + } + } + } + val root = targetRoot ?: throw EngineError("Entry group '${group.name}' has no target input") + executeRules(group.rule, map, scope) + val json = mToJson(root) ?: JsonObject(emptyMap()) + ExecutionResult(success = true, result = Json.encodeToString(JsonElement.serializer(), json)) + } catch (e: EngineError) { + ExecutionResult(success = false, errors = listOf(e.message ?: "engine error")) + } + } + + /** Entry target typed as a core FHIR resource gets its resourceType. */ + private fun resourceTypeForInput(map: StructureMap, input: StructureMapGroupInput): String? { + val type = input.type ?: return null + val url = map.structure?.firstOrNull { it.alias == type }?.url ?: return null + return if (url.startsWith("http://hl7.org/fhir/StructureDefinition/")) url.substringAfterLast('/') else null + } + + // ---- rules ---- + + private fun executeRules(rules: List, map: StructureMap, scope: Scope) { + for (rule in rules) executeRule(rule, map, scope) + } + + private fun executeRule(rule: StructureMapGroupRule, map: StructureMap, scope: Scope) { + val src = rule.source.firstOrNull() ?: throw EngineError("Rule '${rule.name}' has no source") + if (rule.source.size > 1) throw EngineError("Multi-source rules not supported (rule '${rule.name}')") + + val ctx = scope.lookup(src.context) ?: throw EngineError("Unknown source context '${src.context}'") + var items: List = if (src.element != null) readElement(ctx, src.element!!) else listOf(ctx) + + when (src.listMode) { + null -> {} + "first" -> items = items.take(1) + "last" -> items = items.takeLast(1) + "only_one" -> if (items.size > 1) throw EngineError("only_one matched ${items.size} (rule '${rule.name}')") + else -> throw EngineError("Unsupported listMode '${src.listMode}'") + } + src.condition?.let { cond -> + items = items.filter { candidate -> + val condScope = Scope(scope) + src.variable?.let { condScope.bind(it, candidate) } + evalCondition(cond, candidate, condScope) + } + } + + for (item in items) { + val ruleScope = Scope(scope) + src.variable?.let { ruleScope.bind(it, item) } + rule.target?.forEach { executeTarget(it, ruleScope) } + rule.rule?.let { executeRules(it, map, ruleScope) } + rule.dependent?.forEach { dep -> executeDependent(dep, map, ruleScope) } + } + } + + private fun executeDependent(dep: StructureMapGroupRuleDependent, map: StructureMap, scope: Scope) { + val found = resolveGroup(dep.name, map, mutableSetOf()) + ?: throw EngineError("Group '${dep.name}' not found in map or imports") + val (group, owningMap) = found + if (group.input.size != dep.variable.size) { + throw EngineError("Group '${dep.name}' expects ${group.input.size} args, got ${dep.variable.size}") + } + val callScope = Scope(null) + group.input.forEachIndexed { i, input -> + val arg = scope.lookup(dep.variable[i]) + ?: throw EngineError("Unknown variable '${dep.variable[i]}' passed to '${dep.name}'") + callScope.bind(input.name, arg) + } + executeRules(group.rule, owningMap, callScope) + } + + private fun resolveGroup( + name: String, map: StructureMap, visited: MutableSet + ): Pair? { + map.url?.let { if (!visited.add(it)) return null } + map.group.firstOrNull { it.name == name }?.let { return it to map } + map.import?.forEach { url -> + val imported = resolveMap(url) ?: throw EngineError("Imported map not registered: $url") + resolveGroup(name, imported, visited)?.let { return it } + } + return null + } + + // ---- targets ---- + + private fun executeTarget(t: StructureMapGroupRuleTarget, scope: Scope) { + val computed: MNode? = t.transform?.let { applyTransform(it, t.parameter ?: emptyList(), scope) } + + if (t.context != null) { + val node = scope.lookup(t.context!!) as? MObj + ?: throw EngineError("Target context '${t.context}' is not a target node") + var element = t.element ?: throw EngineError("Target context '${t.context}' without element") + var placed = computed ?: MObj() + if (computed != null && isChoiceWrite(element, node)) { + val (suffix, unwrapped) = choiceSuffix(computed) + element += suffix + placed = unwrapped + } + val declaredMax = node.typeUrl + ?.let { resolveElementTypes(it)?.get(t.element!!) }?.substringAfter('|', "?") + node.append(element, placed, replaceIfSingular = computed != null || declaredMax == "1") + t.variable?.let { scope.bind(it, placed) } + } else { + val v = computed ?: throw EngineError("Target with neither context nor transform") + t.variable?.let { scope.bind(it, v) } + } + } + + private fun applyTransform(name: String, params: List, scope: Scope): MNode { + fun arg(i: Int): TransformParameter = + params.getOrNull(i) ?: throw EngineError("Transform '$name' missing parameter $i") + fun argValue(i: Int): Any { + val p = arg(i) + return p.valueId?.let { scope.lookup(it) ?: throw EngineError("Unknown variable '$it' in '$name'") } + ?: p.valueString?.let { JsonPrimitive(it) } + ?: p.valueInteger?.let { JsonPrimitive(it) } + ?: p.valueDecimal?.let { JsonPrimitive(it) } + ?: p.valueBoolean?.let { JsonPrimitive(it) } + ?: throw EngineError("Empty parameter $i for '$name'") + } + + return when (name) { + "copy" -> when (val v = argValue(0)) { + is JsonElement -> jsonToM(v) + is MNode -> v // share the node: later writes through the variable alias the target + else -> throw EngineError("copy: unsupported value") + } + "create" -> MObj().also { o -> + val type = primString(argValue(0)) ?: throw EngineError("create: missing type") + if (type in RESOURCE_TYPES) o.append("resourceType", MPrim(JsonPrimitive(type))) + if (type.contains('/')) o.typeUrl = type + } + "append" -> MPrim(JsonPrimitive(params.indices.joinToString("") { i -> + primString(argValue(i)) ?: throw EngineError("append: parameter $i has no primitive value") + })) + "uuid" -> MPrim(JsonPrimitive(randomUuid())) + "c" -> MObj().also { o -> + o.append("system", MPrim(JsonPrimitive(primString(argValue(0)) ?: ""))) + o.append("code", MPrim(JsonPrimitive(primString(argValue(1)) ?: ""))) + if (params.size > 2) o.append("display", MPrim(JsonPrimitive(primString(argValue(2)) ?: ""))) + } + "translate" -> { + val src0 = argValue(0) + val code = primString(src0) + ?: readElement(src0, "code").firstOrNull()?.let { primString(it) } + ?: throw EngineError("translate: source has no code") + val cmUrl = primString(argValue(1)) ?: throw EngineError("translate: missing ConceptMap url") + val cm = resolveConceptMap(cmUrl) ?: throw EngineError("translate: ConceptMap not registered: $cmUrl") + val mode = if (params.size > 2) primString(argValue(2)) ?: "code" else "code" + val hit = translateCode(cm, code) + ?: throw EngineError("translate: no mapping for '$code' in $cmUrl") + when (mode) { + "code" -> MPrim(JsonPrimitive(hit.code)) + "display" -> MPrim(JsonPrimitive(hit.display ?: hit.code)) + "coding", "Coding" -> MObj().also { o -> + hit.system?.let { o.append("system", MPrim(JsonPrimitive(it))) } + o.append("code", MPrim(JsonPrimitive(hit.code))) + } + else -> throw EngineError("translate: unsupported output mode '$mode'") + } + } + "evaluate" -> { + val expr = primString(argValue(0)) ?: throw EngineError("evaluate: missing expression") + val v = evalPath(expr, null, scope).firstOrNull() + ?: throw EngineError("evaluate: '$expr' yielded nothing") + when (v) { is JsonElement -> jsonToM(v); is MNode -> v; else -> throw EngineError("evaluate: bad value") } + } + else -> throw EngineError("Unsupported transform '$name'") + } + } + + /** + * A write to one of these elements is a FHIR choice type ([x]) in the + * corpus's target resources: occurrence[x] on Immunization; value[x] on + * Extension (discriminated by the sibling url set in the same rule) and + * on resources like Observation (discriminated by resourceType). + */ + private fun isChoiceWrite(element: String, node: MObj): Boolean = when (element) { + "occurrence", "effective", "onset", "doseNumber", "seriesDoses" -> true + "value" -> node.fields.containsKey("url") || node.fields.containsKey("resourceType") + else -> false + } + + private val dateRe = Regex("\\d{4}(-\\d{2}(-\\d{2})?)?") + private val dateTimeRe = Regex("\\d{4}-\\d{2}-\\d{2}T.*") + + private fun choiceSuffix(v: MNode): Pair { + // provenance from the source's own value[x] key wins + (v as? MPrim)?.srcChoice?.let { return it to v } + if (v is MObj && v.fields.size == 1) { + (v.fields["value"]?.singleOrNull() as? MPrim)?.srcChoice?.let { tag -> + return tag to (v.fields["value"]!!.single()) + } + } + // Quantity shape (value + unit) + if (v is MObj && v.fields.containsKey("value") && v.fields.containsKey("unit")) return "Quantity" to v + // Coding shape + if (v is MObj && v.fields.containsKey("code") && v.fields.containsKey("system")) return "Coding" to v + // primitive (possibly wrapped as {value: prim}) + val prim: JsonPrimitive? = when { + v is MPrim -> v.value + v is MObj && v.fields.size == 1 -> (v.fields["value"]?.singleOrNull() as? MPrim)?.value + else -> null + } + if (prim != null) { + val content = prim.contentOrNull ?: "" + val suffix = when { + prim.booleanOrNull != null && !prim.isString -> "Boolean" + prim.intOrNull != null && !prim.isString -> "Integer" + prim.doubleOrNull != null && !prim.isString -> "Decimal" + dateTimeRe.matches(content) -> "DateTime" + dateRe.matches(content) -> "Date" + else -> "String" + } + return suffix to MPrim(prim) + } + return "String" to v + } + + private data class TranslateHit(val code: String, val system: String?, val display: String?) + + private fun translateCode(cm: JsonObject, code: String): TranslateHit? { + val groups = cm["group"] as? JsonArray ?: return null + for (g in groups) { + val go = g as? JsonObject ?: continue + val elements = go["element"] as? JsonArray ?: continue + for (el in elements) { + val o = el as? JsonObject ?: continue + if ((o["code"] as? JsonPrimitive)?.contentOrNull == code) { + val tgt = (o["target"] as? JsonArray)?.firstOrNull() as? JsonObject ?: continue + val tCode = (tgt["code"] as? JsonPrimitive)?.contentOrNull ?: continue + return TranslateHit( + code = tCode, + system = (go["target"] as? JsonPrimitive)?.contentOrNull, + display = (tgt["display"] as? JsonPrimitive)?.contentOrNull + ) + } + } + } + return null + } + + // ---- condition evaluation (corpus-scoped FHIRPath subset) ---- + + /** Handles `path = 'literal'` and bare `path` (existence). */ + private fun evalCondition(expr: String, focus: Any, scope: Scope): Boolean { + val eq = expr.split('=', limit = 2) + return if (eq.size == 2) { + val expected = eq[1].trim().removeSurrounding("'") + evalPath(eq[0].trim(), focus, scope).any { primString(it) == expected } + } else { + evalPath(expr.trim(), focus, scope).isNotEmpty() + } + } + + private fun evalPath(path: String, focus: Any?, scope: Scope): List { + val segments = path.split('.').map { it.trim() } + if (segments.isEmpty()) return emptyList() + var current: List = + scope.lookup(segments[0])?.let { listOf(it) } + ?: focus?.let { f -> + val first = readElement(f, segments[0]) + if (first.isEmpty() && segments.size == 1) return emptyList() else return@let first + } + ?: return emptyList() + val startIdx = if (scope.lookup(segments[0]) != null) 1 else 1 + for (i in startIdx until segments.size) { + current = current.flatMap { readElement(it, segments[i]) } + } + return current + } + + private fun randomUuid(): String { + val b = Random.nextBytes(16) + b[6] = ((b[6].toInt() and 0x0f) or 0x40).toByte() + b[8] = ((b[8].toInt() and 0x3f) or 0x80).toByte() + val hex = b.joinToString("") { (it.toInt() and 0xff).toString(16).padStart(2, '0') } + return "${hex.substring(0,8)}-${hex.substring(8,12)}-${hex.substring(12,16)}-${hex.substring(16,20)}-${hex.substring(20)}" + } +} diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt deleted file mode 100644 index 6a9af6c..0000000 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/StructureMapExecutor.kt +++ /dev/null @@ -1,304 +0,0 @@ -package org.litlfred.fmlrunner.executor - -import org.litlfred.fmlrunner.types.* -import kotlinx.serialization.json.* -// kotlin-fhirpath for FHIRPath evaluation from https://github.com/jingtang10/kotlin-fhirpath -// Note: JitPack access still blocked - will integrate when network firewall allows -// import com.github.jingtang10.kotlin.fhirpath.FHIRPathEngine -// import com.github.jingtang10.kotlin.fhirpath.FHIRPathEngineFactory - -/** - * StructureMap execution engine - executes StructureMaps on input data - * Ready for kotlin-fhirpath library integration when network access allows - */ -class StructureMapExecutor { - // kotlin-fhirpath engine integration ready when network allows - // private val fhirPathEngine: FHIRPathEngine = FHIRPathEngineFactory.create() - - /** - * Execute a StructureMap on input content - */ - fun execute(structureMap: StructureMap, inputContent: String, options: ExecutionOptions = ExecutionOptions()): ExecutionResult { - return try { - // Basic validation - if (structureMap.group.isEmpty()) { - return ExecutionResult( - success = false, - errors = listOf("StructureMap must have at least one group") - ) - } - - // Parse input JSON - val json = Json { ignoreUnknownKeys = true } - val inputData = json.parseToJsonElement(inputContent) - - // Execute the main group (first group by convention) - val mainGroup = structureMap.group.first() - val result = executeGroup(mainGroup, inputData, options) - - ExecutionResult( - success = true, - result = Json.encodeToString(JsonElement.serializer(), result) - ) - } catch (e: Exception) { - ExecutionResult( - success = false, - errors = listOf("Execution failed: ${e.message}") - ) - } - } - - /** - * Execute a StructureMap group - */ - private fun executeGroup(group: StructureMapGroup, inputData: JsonElement, options: ExecutionOptions): JsonElement { - // Create target data structure - val targetData = JsonObject(emptyMap()).toMutableMap() - - // Find source and target inputs - val sourceInput = group.input.find { it.mode == InputMode.SOURCE } - val targetInput = group.input.find { it.mode == InputMode.TARGET } - - if (sourceInput == null || targetInput == null) { - throw IllegalArgumentException("Group must have both source and target inputs") - } - - // Create execution context - val context = ExecutionContext( - sourceData = inputData, - targetData = targetData, - sourceContext = sourceInput.name, - targetContext = targetInput.name - ) - - // Execute rules - for (rule in group.rule) { - executeRule(rule, context, options) - } - - return JsonObject(targetData) - } - - /** - * Execute a single rule - */ - private fun executeRule(rule: StructureMapGroupRule, context: ExecutionContext, options: ExecutionOptions) { - // Process each source - for (source in rule.source) { - val sourceValue = extractSourceValue(source, context) - - // Process targets if available - rule.target?.forEach { target -> - applyTargetMapping(source, target, sourceValue, context, options) - } - } - } - - /** - * Extract value from source - */ - private fun extractSourceValue(source: StructureMapGroupRuleSource, context: ExecutionContext): JsonElement? { - return try { - when { - source.context == context.sourceContext && source.element != null -> { - // Extract from source data - extractElementValue(context.sourceData, source.element) - } - source.context == context.sourceContext && source.element == null -> { - // Use entire source - context.sourceData - } - else -> null - } - } catch (e: Exception) { - null - } - } - - /** - * Apply target mapping - */ - private fun applyTargetMapping( - source: StructureMapGroupRuleSource, - target: StructureMapGroupRuleTarget, - sourceValue: JsonElement?, - context: ExecutionContext, - options: ExecutionOptions - ) { - if (sourceValue == null) return - - val targetElement = target.element ?: return - - // Apply transformation if specified - val transformedValue = if (target.transform != null) { - applyTransform(target.transform, sourceValue, target.parameter) - } else { - sourceValue - } - - // Set target value - setTargetValue(context, targetElement, transformedValue) - } - - /** - * Extract element value from JSON - */ - private fun extractElementValue(jsonElement: JsonElement, elementPath: String): JsonElement? { - return when (jsonElement) { - is JsonObject -> jsonElement[elementPath] - is JsonArray -> { - // Handle array access - val index = elementPath.toIntOrNull() - if (index != null && index < jsonElement.size) { - jsonElement[index] - } else null - } - else -> null - } - } - - /** - * Set target value in context - */ - private fun setTargetValue(context: ExecutionContext, elementPath: String, value: JsonElement) { - context.targetData[elementPath] = value - } - - /** - * Apply transformation function - */ - private fun applyTransform(transform: String, value: JsonElement, parameters: List?): JsonElement { - return when (transform.lowercase()) { - "copy" -> value - "create" -> { - // Create new object/value based on parameters - parameters?.firstOrNull()?.let { p -> val type = p.valueString ?: p.valueId ?: "" - when (type.lowercase()) { - "string" -> JsonPrimitive("") - "integer" -> JsonPrimitive(0) - "boolean" -> JsonPrimitive(false) - else -> JsonObject(emptyMap()) - } - } ?: value - } - "cast" -> { - // Type casting - parameters?.firstOrNull()?.let { p -> val targetType = p.valueString ?: p.valueId ?: "" - castValue(value, targetType) - } ?: value - } - "evaluate" -> { - // Simple FHIRPath-like evaluation (basic implementation) - parameters?.firstOrNull()?.let { p -> val expression = p.valueString ?: p.valueId ?: "" - evaluateExpression(value, expression) - } ?: value - } - else -> value // Unknown transform, return original value - } - } - - /** - * Cast value to target type - */ - private fun castValue(value: JsonElement, targetType: String): JsonElement { - return when (targetType.lowercase()) { - "string" -> JsonPrimitive(value.toString().trim('"')) - "integer" -> { - val stringValue = if (value is JsonPrimitive) value.content else value.toString() - JsonPrimitive(stringValue.toIntOrNull() ?: 0) - } - "boolean" -> { - val stringValue = if (value is JsonPrimitive) value.content else value.toString() - JsonPrimitive(stringValue.toBooleanStrictOrNull() ?: false) - } - else -> value - } - } - - /** - * Expression evaluation using kotlin-fhirpath engine - */ - private fun evaluateExpression(context: JsonElement, expression: String): JsonElement { - return try { - when (expression) { - "true" -> JsonPrimitive(true) - "false" -> JsonPrimitive(false) - else -> { - // Property access for expressions - if (context is JsonObject && context.containsKey(expression)) { - context[expression] ?: JsonNull - } else { - JsonNull - } - } - } - } catch (e: Exception) { - JsonNull - } - } - - /** - * Validate StructureMap structure - */ - fun validateStructureMap(structureMap: StructureMap): ValidationResult { - val errors = mutableListOf() - - if (structureMap.group.isEmpty()) { - errors.add("StructureMap must have at least one group") - } - - for ((index, group) in structureMap.group.withIndex()) { - if (group.name.isBlank()) { - errors.add("Group $index must have a name") - } - - if (group.input.isEmpty()) { - errors.add("Group '${group.name}' must have at least one input") - } - - val sourceInputs = group.input.filter { it.mode == InputMode.SOURCE } - val targetInputs = group.input.filter { it.mode == InputMode.TARGET } - - if (sourceInputs.isEmpty()) { - errors.add("Group '${group.name}' must have at least one source input") - } - - if (targetInputs.isEmpty()) { - errors.add("Group '${group.name}' must have at least one target input") - } - - if (group.rule.isEmpty()) { - errors.add("Group '${group.name}' must have at least one rule") - } - - for ((ruleIndex, rule) in group.rule.withIndex()) { - if (rule.source.isEmpty()) { - errors.add("Rule $ruleIndex in group '${group.name}' must have at least one source") - } - } - } - - return ValidationResult( - valid = errors.isEmpty(), - errors = errors - ) - } -} - -/** - * Execution context for rule processing - */ -private data class ExecutionContext( - val sourceData: JsonElement, - val targetData: MutableMap, - val sourceContext: String, - val targetContext: String -) - -/** - * Validation result - */ -data class ValidationResult( - val valid: Boolean, - val errors: List -) \ No newline at end of file diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt index 873ce1b..68fa144 100644 --- a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt @@ -1,51 +1,109 @@ package org.litlfred.fmlrunner +import kotlinx.serialization.json.* import java.io.File import kotlin.test.Test /** * Conformance spike: feed fmlrunner WHO smart-immunizations content verbatim - * and report how far it gets. Fixtures from github.com/dhes/fmlrunner-conformance - * (reference-engine oracles); FML sources from the IG's input/maps. - * - * Diagnostic, not pass/fail: prints a stage-by-stage ledger. + * and score it against the reference-engine oracles + * (github.com/dhes/fmlrunner-conformance). Diagnostic, not pass/fail: + * prints a per-fixture ledger. */ class ImmzConformanceSpike { private val mapsDir = File(System.getProperty("user.home"), "projects/smart-immunizations-fresher/input/maps") private val fixturesDir = File(System.getProperty("user.home"), "projects/fmlrunner-conformance") - @Test - fun c4EndToEnd() { + private fun loadRunner(): FmlRunner { val runner = FmlRunner() - - // Stage 1: compile every IMMZ FML source - println("=== Stage 1: compile all IMMZ FML maps ===") - var compiled = 0 mapsDir.listFiles { f -> f.extension == "fml" }?.sortedBy { it.name }?.forEach { f -> val r = runner.compileFml(f.readText()) - if (r.success && r.structureMap != null) { - runner.registerStructureMap(r.structureMap!!) - compiled++ - println("COMPILE OK ${f.name} -> ${r.structureMap!!.url}") - } else { - println("COMPILE FAIL ${f.name}: ${r.errors.take(2)}") + if (r.success && r.structureMap != null) runner.registerStructureMap(r.structureMap!!) + else println("COMPILE FAIL ${f.name}: ${r.errors.take(2)}") + } + File(fixturesDir, "package").listFiles { f -> f.name.startsWith("ConceptMap-") }?.forEach { + runner.registerConceptMap(it.readText()) + } + File(fixturesDir, "package").listFiles { f -> f.name.startsWith("StructureDefinition-") }?.forEach { + runner.registerStructureDefinition(it.readText()) + } + return runner + } + + private fun mapUrlFor(family: String): String { + val name = if (family == "C") "IMMZ.C4.QRToPatient" else "IMMZ.$family.QRToBundle" + return "http://smart.who.int/immunizations/StructureMap/$name" + } + + @Test + fun scoreAllFixtures() { + val runner = loadRunner() + println("=== Conformance score: 33 fixtures vs oracle ===") + var match = 0; var diff = 0; var error = 0 + File(fixturesDir, "package/example").listFiles { f -> + f.name.startsWith("QuestionnaireResponse-Example.IMMZ.") + }?.sortedBy { it.name }?.forEach { qrFile -> + val short = qrFile.name.removePrefix("QuestionnaireResponse-Example.IMMZ.").removeSuffix(".json") + val family = short.substringBefore('.') + val mapName = if (family == "C") "IMMZ.C4.QRToPatient" else "IMMZ.$family.QRToBundle" + val oracleFile = File(fixturesDir, "oracle/${mapName}__${short}.json") + val exec = runner.executeStructureMap(mapUrlFor(family), qrFile.readText()) + if (!exec.success || exec.result == null) { + error++ + println("ERROR $short: ${exec.errors.firstOrNull()}") + return@forEach } + val ours = normalize(Json.parseToJsonElement(exec.result!!)) + val oracle = normalize(Json.parseToJsonElement(oracleFile.readText())) + val divergence = firstDiff(oracle, ours, "$") + if (divergence == null) { match++; println("MATCH $short") } + else { diff++; println("DIFF $short at $divergence") } } - println("compiled $compiled maps") - - // Stage 2: execute C4 QRToPatient on the published QR example - println("=== Stage 2: execute IMMZ.C4.QRToPatient on published QR ===") - val qr = File(fixturesDir, "package/example/QuestionnaireResponse-Example.IMMZ.C.QuestionnaireResponse.1.json").readText() - val exec = runner.executeStructureMap( - "http://smart.who.int/immunizations/StructureMap/IMMZ.C4.QRToPatient", qr - ) - println("execute success=${exec.success}") - exec.errors.take(5).forEach { println(" error: $it") } - exec.warnings.take(5).forEach { println(" warning: $it") } - println("--- output (first 1500 chars) ---") - println(exec.result?.take(1500) ?: "(null result)") - println("--- oracle (first 600 chars, for eyeball) ---") - println(File(fixturesDir, "oracle/IMMZ.C4.QRToPatient__C.QuestionnaireResponse.1.json").readText().take(600)) + println("== score: $match match, $diff diff, $error error / 33") } + + // --- normalization: sequence-number UUIDs, unwrap singleton arrays --- + + private val uuidRe = Regex("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}") + + private fun normalize(e: JsonElement): JsonElement { + val compact = Json.encodeToString(JsonElement.serializer(), e) + val seen = LinkedHashMap() + val renumbered = uuidRe.replace(compact) { m -> + seen.getOrPut(m.value.lowercase()) { "uuid-${seen.size + 1}" } + } + return unwrap(Json.parseToJsonElement(renumbered)) + } + + private fun unwrap(e: JsonElement): JsonElement = when (e) { + is JsonArray -> if (e.size == 1) unwrap(e[0]) else JsonArray(e.map { unwrap(it) }) + is JsonObject -> JsonObject(e.mapValues { unwrap(it.value) }) + else -> e + } + + private fun firstDiff(a: JsonElement, b: JsonElement, path: String): String? { + if (a::class != b::class) return "$path (kind: oracle=${a::class.simpleName} ours=${b::class.simpleName})" + when (a) { + is JsonObject -> { + b as JsonObject + for (k in a.keys + b.keys) { + val av = a[k]; val bv = b[k] + if (av == null) return "$path.$k (extra in ours: ${short(bv)})" + if (bv == null) return "$path.$k (missing in ours; oracle=${short(av)})" + firstDiff(av, bv, "$path.$k")?.let { return it } + } + } + is JsonArray -> { + b as JsonArray + if (a.size != b.size) return "$path (size: oracle=${a.size} ours=${b.size})" + a.indices.forEach { i -> firstDiff(a[i], b[i], "$path[$i]")?.let { return it } } + } + else -> if (a != b) return "$path (oracle=${short(a)} ours=${short(b)})" + } + return null + } + + private fun short(e: JsonElement?): String = + (e?.toString() ?: "null").let { if (it.length > 60) it.take(60) + "…" else it } } From e454ea5382f9e9586ac28751af54c105714ca208 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Fri, 4 Sep 2026 15:04:50 -1000 Subject: [PATCH 05/11] c() resolves display from registered CodeSystems: 33/33 oracle fixtures match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2 residual diffs were not an oracle quirk to waive — they were a c() semantics gap: the reference engine resolves Coding.display from terminology, ignoring the transform's third argument, and omits the display when the code system is unavailable (e.g. unlicensed LOINC). Implemented: registerCodeSystem() feeds a display store; c() looks up (system, code) and emits no display on a miss. LOINC's absence now falls out naturally instead of being explained away. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- ...kotlin-stdlib-2.1.0-commonMain-ITmP6A.klib | Bin 0 -> 189164 bytes ...st-2.1.0-annotationsCommonMain-D3q3YQ.klib | Bin 0 -> 1544 bytes ...est-2.1.0-assertionsCommonMain-D3q3YQ.klib | Bin 0 -> 6027 bytes ...linx-datetime-0.4.1-commonMain-c2T0hA.klib | Bin 0 -> 11152 bytes ...lization-core-1.6.0-commonMain-X2nJrA.klib | Bin 0 -> 31798 bytes ...lization-json-1.6.0-commonMain-VuRrcQ.klib | Bin 0 -> 20019 bytes gradle/wrapper/gradle-wrapper.properties | 9 + gradlew | 248 ++++++++++++++++++ gradlew.bat | 82 ++++++ .../org/litlfred/fmlrunner/FmlRunner.kt | 29 +- .../litlfred/fmlrunner/executor/FmlEngine.kt | 14 +- .../fmlrunner/ImmzConformanceSpike.kt | 9 + 14 files changed, 387 insertions(+), 6 deletions(-) create mode 100644 .kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-stdlib-2.1.0-commonMain-ITmP6A.klib create mode 100644 .kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.1.0-annotationsCommonMain-D3q3YQ.klib create mode 100644 .kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.1.0-assertionsCommonMain-D3q3YQ.klib create mode 100644 .kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-datetime-0.4.1-commonMain-c2T0hA.klib create mode 100644 .kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.0-commonMain-X2nJrA.klib create mode 100644 .kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.0-commonMain-VuRrcQ.klib create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 2945497929ef08ff7530db85980646db63ca12b2..df86b606b69020635af7b5aef910360ea92646ad 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~oM60st@O1P%ZI literal 17 VcmZRc8C-F+LssMw0~oMO1^_TN1YZCE diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index ad193af..05d99d3 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Thu Sep 03 16:11:41 HST 2026 +#Fri Sep 04 15:03:25 HST 2026 gradle.version=8.14.2 diff --git a/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-stdlib-2.1.0-commonMain-ITmP6A.klib b/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-stdlib-2.1.0-commonMain-ITmP6A.klib new file mode 100644 index 0000000000000000000000000000000000000000..ba9601256572af81083acf6ec39f74d734664fe2 GIT binary patch literal 189164 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 literal 0 HcmV?d00001 diff --git a/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.1.0-assertionsCommonMain-D3q3YQ.klib b/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.1.0-assertionsCommonMain-D3q3YQ.klib new file mode 100644 index 0000000000000000000000000000000000000000..22d6f1b691d3767ebc0c2ff64388b3e7098bcb09 GIT binary patch literal 6027 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 LZ)X&gPw)O8In@|2 literal 0 HcmV?d00001 diff --git a/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.0-commonMain-X2nJrA.klib b/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.0-commonMain-X2nJrA.klib new file mode 100644 index 0000000000000000000000000000000000000000..bed07a77c7fb5f0a0fc87494d814aad08da70fb3 GIT binary patch literal 31798 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 literal 0 HcmV?d00001 diff --git a/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.0-commonMain-VuRrcQ.klib b/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.0-commonMain-VuRrcQ.klib new file mode 100644 index 0000000000000000000000000000000000000000..cf196f8f6e8e39de3c851327e9ff5b6cb351af7d GIT binary patch literal 20019 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 IRL;Nv0NH>K_5c6? literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..eb84db6 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..249efbb --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# gradlew start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh gradlew +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8508ef6 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,82 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt index d93b646..c7fcc88 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt @@ -19,6 +19,7 @@ class FmlRunner { private val structureMapStore = mutableMapOf() private val conceptMapStore = mutableMapOf() private val typeStore = mutableMapOf>() // SD url -> element leaf -> type code + private val displayStore = mutableMapOf() // "system|code" -> display // kotlin-fhir terminology services private val conceptMapService = ConceptMapService() @@ -48,11 +49,37 @@ class FmlRunner { val engine = FmlEngine( resolveMap = { ref -> getStructureMap(ref) }, resolveConceptMap = { url -> conceptMapStore[url] }, - resolveElementTypes = { url -> typeStore[url] } + resolveElementTypes = { url -> typeStore[url] }, + resolveDisplay = { system, code -> displayStore["$system|$code"] } ) return engine.execute(structureMap, source) } + /** + * Register a CodeSystem (JSON): concept displays back the c() transform, + * which resolves display from terminology (matching the reference engine) + * rather than from its optional third argument. + */ + fun registerCodeSystem(json: String): Boolean { + return try { + val o = Json.parseToJsonElement(json) as? JsonObject ?: return false + val url = (o["url"] as? JsonPrimitive)?.contentOrNull ?: return false + fun walk(concepts: kotlinx.serialization.json.JsonArray?) { + concepts?.forEach { c -> + val co = c as? JsonObject ?: return@forEach + val code = (co["code"] as? JsonPrimitive)?.contentOrNull + val display = (co["display"] as? JsonPrimitive)?.contentOrNull + if (code != null && display != null) displayStore["$url|$code"] = display + walk(co["concept"] as? kotlinx.serialization.json.JsonArray) + } + } + walk(o["concept"] as? kotlinx.serialization.json.JsonArray) + true + } catch (e: Exception) { + false + } + } + /** * Register a StructureDefinition (JSON): declared element types drive * choice-element ([x]) naming during execution. diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt index cb4b9f5..ef7ba37 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt @@ -24,7 +24,8 @@ data class ValidationResult( class FmlEngine( private val resolveMap: (String) -> StructureMap?, private val resolveConceptMap: (String) -> JsonObject? = { null }, - private val resolveElementTypes: (String) -> Map? = { null } + private val resolveElementTypes: (String) -> Map? = { null }, + private val resolveDisplay: (String, String) -> String? = { _, _ -> null } ) { // ---- mutable target tree ---- @@ -310,9 +311,14 @@ class FmlEngine( })) "uuid" -> MPrim(JsonPrimitive(randomUuid())) "c" -> MObj().also { o -> - o.append("system", MPrim(JsonPrimitive(primString(argValue(0)) ?: ""))) - o.append("code", MPrim(JsonPrimitive(primString(argValue(1)) ?: ""))) - if (params.size > 2) o.append("display", MPrim(JsonPrimitive(primString(argValue(2)) ?: ""))) + val system = primString(argValue(0)) ?: "" + val code = primString(argValue(1)) ?: "" + o.append("system", MPrim(JsonPrimitive(system))) + o.append("code", MPrim(JsonPrimitive(code))) + // Display comes from terminology, matching the reference engine — + // the optional third argument is ignored (the reference drops + // displays it cannot resolve, e.g. unlicensed code systems). + resolveDisplay(system, code)?.let { o.append("display", MPrim(JsonPrimitive(it))) } } "translate" -> { val src0 = argValue(0) diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt index 68fa144..9ac6a8e 100644 --- a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt @@ -28,6 +28,15 @@ class ImmzConformanceSpike { File(fixturesDir, "package").listFiles { f -> f.name.startsWith("StructureDefinition-") }?.forEach { runner.registerStructureDefinition(it.readText()) } + File(fixturesDir, "package").listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { + runner.registerCodeSystem(it.readText()) + } + // HL7 terminology CodeSystems the reference engine resolves via its loaded + // terminology packages (from the local FHIR package cache) + File(System.getProperty("user.home"), ".fhir/packages/hl7.terminology.r4#6.2.0/package") + .listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { + runner.registerCodeSystem(it.readText()) + } return runner } From 381e2e91bd9c2cbf9349f95e68cc0582a34ca442 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Sat, 5 Sep 2026 07:22:58 -1000 Subject: [PATCH 06/11] Parse full WHO org FML corpus (54/54) Grammar gaps found by an org-wide parse sweep (ddcc, smart-ot, smart-example-immz) and closed: - source type cast: entry.resource : Patient - comma-less multiline group signatures - element names that are quoted strings (src."-260") or FML keywords (Name.prefix), and keywords in value/parameter positions - parenthesized FHIRPath as target transform and as transform argument - anonymous expression targets: (expr) as var FmlParseSweep jvmTest runs the sweep over FML_SWEEP_DIR and tallies failures by error signature. Oracle regression unchanged: 33/33. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- .../fmlrunner/compiler/FmlCompiler.kt | 108 ++++++++++++++++-- .../org/litlfred/fmlrunner/FmlParseSweep.kt | 62 ++++++++++ 4 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 src/jvmTest/kotlin/org/litlfred/fmlrunner/FmlParseSweep.kt diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index df86b606b69020635af7b5aef910360ea92646ad..44fb867654c9eceea293b0c9f29efd3e83a4843c 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~oNL0{}2{1e*W= literal 17 VcmZRc8C-F+LssMw0~oM60st@O1P%ZI diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index 05d99d3..83fb26c 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Fri Sep 04 15:03:25 HST 2026 +#Sat Sep 05 07:04:23 HST 2026 gradle.version=8.14.2 diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt index c15dd9c..7d42f88 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/compiler/FmlCompiler.kt @@ -352,15 +352,12 @@ class FmlParser(private val tokens: List) { throw IllegalArgumentException(err("Expected '(' after group name")) } - // Parse inputs + // Parse inputs; the comma separator is optional (ddcc declares + // multiline signatures without commas) val inputs = mutableListOf() while (!check(TokenType.RPAREN)) { inputs.add(parseInput()) - if (!check(TokenType.RPAREN)) { - if (!match(TokenType.COMMA)) { - throw IllegalArgumentException(err("Expected ',' between inputs")) - } - } + if (!check(TokenType.RPAREN)) match(TokenType.COMMA) } if (!match(TokenType.RPAREN)) { @@ -490,7 +487,12 @@ class FmlParser(private val tokens: List) { val context = expectIdentifier("source context") var element: String? = null if (match(TokenType.DOT)) { - element = expectIdentifier("element name after '.'") + element = expectElementName() + } + // Optional type cast: `entry.resource : Patient` + var type: String? = null + if (match(TokenType.COLON)) { + type = expectIdentifier("source type after ':'") } var listMode: String? = null var variable: String? = null @@ -520,6 +522,7 @@ class FmlParser(private val tokens: List) { context = context, element = element, variable = variable, + type = type, listMode = listMode, condition = condition, check = checkExpr @@ -543,11 +546,27 @@ class FmlParser(private val tokens: List) { ) } + // Anonymous expression target: `(expr) as var` — no context, the + // evaluated value is only bound to the variable + if (peek().type == TokenType.LPAREN) { + val expr = captureParenExpression() + var variable: String? = null + if (peek().type == TokenType.AS) { + advance() + variable = expectIdentifier("variable name after 'as'") + } + return StructureMapGroupRuleTarget( + variable = variable, + transform = "evaluate", + parameter = listOf(TransformParameter(valueString = expr)) + ) + } + // Context form: ctx('.' element)? ('=' transform)? ('as' var)? val context = expectIdentifier("target context") var element: String? = null if (match(TokenType.DOT)) { - element = expectIdentifier("element name after '.'") + element = expectElementName() } var transform: String? = null var parameter: List? = null @@ -558,6 +577,11 @@ class FmlParser(private val tokens: List) { transform = advance().value parameter = parseTransformParams().ifEmpty { null } } + // Parenthesized FHIRPath: `doseNumber = (dose.toInteger() + 1)` + t.type == TokenType.LPAREN -> { + transform = "evaluate" + parameter = listOf(TransformParameter(valueString = captureParenExpression())) + } t.type == TokenType.STRING -> { transform = "copy" parameter = listOf(TransformParameter(valueString = advance().value)) @@ -566,6 +590,10 @@ class FmlParser(private val tokens: List) { transform = "copy" parameter = listOf(numberParam(advance().value)) } + t.type in KEYWORD_TYPES -> { + transform = "copy" + parameter = listOf(TransformParameter(valueId = advance().value)) + } t.type == TokenType.IDENTIFIER -> { var path = advance().value if (check(TokenType.DOT)) { @@ -612,6 +640,9 @@ class FmlParser(private val tokens: List) { "false" -> { advance(); TransformParameter(valueBoolean = false) } else -> TransformParameter(valueId = advance().value) } + // Parenthesized FHIRPath argument: evaluate(src, (($this - age)...)) + TokenType.LPAREN -> TransformParameter(valueString = captureParenExpression()) + in KEYWORD_TYPES -> TransformParameter(valueId = advance().value) else -> throw IllegalArgumentException(err("Expected parameter")) }) if (!check(TokenType.RPAREN) && !match(TokenType.COMMA)) { @@ -655,17 +686,76 @@ class FmlParser(private val tokens: List) { } private fun expectIdentifier(what: String): String { - if (peek().type != TokenType.IDENTIFIER) { + if (peek().type != TokenType.IDENTIFIER && peek().type !in KEYWORD_TYPES) { throw IllegalArgumentException(err("Expected $what")) } return advance().value } + /** + * Element names may be plain identifiers, FML keywords used as names + * (Name.prefix), or quoted strings (ICAO/DCC numeric keys: src."-260"). + */ + private fun expectElementName(): String { + val t = peek() + if (t.type == TokenType.IDENTIFIER || t.type == TokenType.STRING || t.type in KEYWORD_TYPES) { + return advance().value + } + throw IllegalArgumentException(err("Expected element name after '.'")) + } + + /** + * Capture a parenthesized FHIRPath expression: consumes from the opening + * '(' through its matching ')', returning the inner text with spacing + * reconstructed (no space around '.', after '(', before ')' or ',', + * before a call's '(', or after '$'). + */ + private fun captureParenExpression(): String { + if (!match(TokenType.LPAREN)) { + throw IllegalArgumentException(err("Expected '(' to start expression")) + } + val sb = StringBuilder() + var depth = 1 + var prev: Token? = null + while (!isAtEnd()) { + val t = peek() + if (t.type == TokenType.RPAREN) { + depth-- + if (depth == 0) { advance(); break } + } + if (t.type == TokenType.LPAREN) depth++ + if (sb.isNotEmpty() && needSpace(prev, t)) sb.append(' ') + sb.append(if (t.type == TokenType.STRING) "'" + t.value + "'" else t.value) + prev = t + advance() + } + if (depth != 0) { + throw IllegalArgumentException(err("Unbalanced parentheses in expression")) + } + return sb.toString() + } + + private fun needSpace(prev: Token?, t: Token): Boolean { + if (prev == null) return false + if (t.type == TokenType.DOT || t.type == TokenType.COMMA || t.type == TokenType.RPAREN) return false + if (prev.type == TokenType.DOT || prev.type == TokenType.LPAREN) return false + if (t.type == TokenType.LPAREN && + (prev.type == TokenType.IDENTIFIER || prev.type in KEYWORD_TYPES)) return false + if (prev.value == "$") return false + return true + } + private fun peekNext(): Token = if (current + 1 < tokens.size) tokens[current + 1] else tokens[tokens.size - 1] companion object { private val LIST_MODES = setOf("first", "not_first", "last", "not_last", "only_one") + private val KEYWORD_TYPES = setOf( + TokenType.MAP, TokenType.USES, TokenType.IMPORTS, TokenType.CONCEPTMAP, + TokenType.PREFIX, TokenType.GROUP, TokenType.INPUT, TokenType.RULE, + TokenType.WHERE, TokenType.CHECK, TokenType.LOG, TokenType.AS, + TokenType.ALIAS, TokenType.MODE + ) } private fun match(type: TokenType): Boolean { diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/FmlParseSweep.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/FmlParseSweep.kt new file mode 100644 index 0000000..ce1dd76 --- /dev/null +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/FmlParseSweep.kt @@ -0,0 +1,62 @@ +package org.litlfred.fmlrunner + +import org.litlfred.fmlrunner.compiler.FmlCompiler +import java.io.File +import kotlin.test.Test + +/** + * Parse-only sweep over every .fml file WHO publishes (org-wide census). + * Diagnostic, not pass/fail: prints a per-file ledger plus a failure tally + * grouped by error signature — the grammar backlog, prioritized by frequency. + * + * Point FML_SWEEP_DIR at a directory of /.fml subdirectories. + */ +class FmlParseSweep { + + @Test + fun sweep() { + val root = File( + System.getenv("FML_SWEEP_DIR") + ?: return println("SWEEP SKIPPED: FML_SWEEP_DIR not set") + ) + val files = root.walkTopDown() + .filter { it.extension == "fml" } + .sortedBy { it.relativeTo(root).path } + .toList() + val compiler = FmlCompiler() + var ok = 0 + val failures = mutableListOf>() + for (f in files) { + val rel = f.relativeTo(root).path + val r = try { + compiler.compile(f.readText()) + } catch (e: Exception) { + failures += rel to "EXCEPTION ${e.message}" + println("SWEEP FAIL $rel :: EXCEPTION ${e.message}") + continue + } + if (r.success && r.structureMap != null) { + ok++ + println("SWEEP OK $rel (${r.structureMap!!.group.size} groups)") + } else { + val err = r.errors.firstOrNull() ?: "no error message" + failures += rel to err + println("SWEEP FAIL $rel :: $err") + } + } + println("SWEEP score: $ok/${files.size}") + // Tally by error signature: strip file-specific line/token detail so + // identical grammar gaps group together. + val signature = { e: String -> + e.replace(Regex("\\(line \\d+, near '[^']*'\\)"), "") + .replace(Regex("'[^']*'"), "'…'") + .trim() + } + failures.groupBy { signature(it.second) } + .entries.sortedByDescending { it.value.size } + .forEach { (sig, hits) -> + println("SWEEP TALLY ${hits.size}x :: $sig") + hits.forEach { println("SWEEP - ${it.first}") } + } + } +} From cd4ce480dcbeb05705c43158caaf19b172c2b9f6 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Sat, 5 Sep 2026 10:43:54 -1000 Subject: [PATCH 07/11] NCSA corpus spike: score vs ddcc/smart-ot oracles (baseline 0/14) Two mechanisms: logical-model roots need resourceType emission; bare target contexts (-> tgt then ...) unsupported by the executor. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- .../fmlrunner/NcsaConformanceSpike.kt | 144 ++++++++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 44fb867654c9eceea293b0c9f29efd3e83a4843c..2b015fe79244867cfa2d12177a44100db1c55e81 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~oNr1pqLT1iAnK literal 17 VcmZRc8C-F+LssMw0~oNL0{}2{1e*W= diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index 83fb26c..77aa5e0 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Sat Sep 05 07:04:23 HST 2026 +#Sat Sep 05 10:43:04 HST 2026 gradle.version=8.14.2 diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt new file mode 100644 index 0000000..eca5b5b --- /dev/null +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt @@ -0,0 +1,144 @@ +package org.litlfred.fmlrunner + +import kotlinx.serialization.json.* +import java.io.File +import kotlin.test.Test + +/** + * Conformance spike for the CC-BY-NC-SA WHO corpus (ddcc, smart-ot): + * 14 reference-engine oracles in ~/projects/fmlrunner-conformance-ncsa. + * Diagnostic, not pass/fail: prints a per-fixture ledger. + */ +class NcsaConformanceSpike { + + private val home = File(System.getProperty("user.home")) + private val corpus = File(home, "projects/fmlrunner-conformance-ncsa") + + private fun registerPackage(runner: FmlRunner, dir: File) { + dir.listFiles { f -> f.name.startsWith("ConceptMap-") }?.forEach { + runner.registerConceptMap(it.readText()) + } + dir.listFiles { f -> f.name.startsWith("StructureDefinition-") }?.forEach { + runner.registerStructureDefinition(it.readText()) + } + dir.listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { + runner.registerCodeSystem(it.readText()) + } + } + + private fun loadRunner(): FmlRunner { + val runner = FmlRunner() + for (repo in listOf("ddcc", "smart-ot")) { + File(corpus, "$repo/maps").listFiles { f -> f.extension == "fml" } + ?.sortedBy { it.name }?.forEach { f -> + val r = runner.compileFml(f.readText()) + if (r.success && r.structureMap != null) runner.registerStructureMap(r.structureMap!!) + else println("NCSA COMPILE FAIL ${f.name}: ${r.errors.take(1)}") + } + registerPackage(runner, File(corpus, "$repo/package")) + } + registerPackage(runner, File(home, ".fhir/packages/hl7.fhir.uv.shc-vaccination#1.0.0/package")) + File(home, ".fhir/packages/hl7.terminology.r4#6.2.0/package") + .listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { + runner.registerCodeSystem(it.readText()) + } + return runner + } + + private data class Fixture(val label: String, val mapUrl: String, val input: File, val oracle: File) + + private fun fixtures(): List { + val list = mutableListOf() + val otBase = "http://worldhealthorganization.github.io/smart-ot/StructureMap" + val ddBase = "http://smart.who.int/ddcc/StructureMap" + val otQr = File(corpus, "smart-ot/package/example/QuestionnaireResponse-Response1.json") + for (m in listOf("MeaslesQuestionnaireToLogicalModel", "MeaslesQuestionnaireToResources")) { + list.add(Fixture("ot/$m", "$otBase/$m", otQr, File(corpus, "oracle/smart-ot/${m}__Response1.json"))) + } + File(corpus, "ddcc/package/example").listFiles { f -> + f.name.startsWith("QuestionnaireResponse-DDCCVSQuestionnaireResponse") + }?.sortedBy { it.name }?.forEach { f -> + val short = f.name.removePrefix("QuestionnaireResponse-DDCCVSQuestionnaireResponse").removeSuffix(".json") + list.add(Fixture("ddcc/QResp-$short", "$ddBase/QRespToVSCoreDataSet", f, + File(corpus, "oracle/ddcc/QRespToVSCoreDataSet__${short}.json"))) + } + File(corpus, "ddcc/package/example").listFiles { f -> + f.name.startsWith("Bundle-Example") + }?.sortedBy { it.name }?.forEach { f -> + val short = f.name.removePrefix("Bundle-Example").removePrefix("-").removeSuffix(".json") + list.add(Fixture("ddcc/toSHC-$short", "$ddBase/DDCCtoSHC", f, + File(corpus, "oracle/ddcc/DDCCtoSHC__${short}.json"))) + } + return list + } + + @Test + fun scoreAllFixtures() { + val runner = loadRunner() + val all = fixtures() + println("NCSA === Conformance score: ${all.size} fixtures vs oracle ===") + var match = 0; var diff = 0; var error = 0 + for (fx in all) { + val exec = try { + runner.executeStructureMap(fx.mapUrl, fx.input.readText()) + } catch (e: Exception) { + error++; println("NCSA ERROR ${fx.label}: EXCEPTION ${e.message?.take(160)}"); continue + } + if (!exec.success || exec.result == null) { + error++ + println("NCSA ERROR ${fx.label}: ${exec.errors.firstOrNull()?.take(160)}") + continue + } + val ours = normalize(Json.parseToJsonElement(exec.result!!)) + val oracle = normalize(Json.parseToJsonElement(fx.oracle.readText())) + val divergence = firstDiff(oracle, ours, "$") + if (divergence == null) { match++; println("NCSA MATCH ${fx.label}") } + else { diff++; println("NCSA DIFF ${fx.label} at $divergence") } + } + println("NCSA == score: $match match, $diff diff, $error error / ${all.size}") + } + + // --- normalization: sequence-number UUIDs, unwrap singleton arrays --- + + private val uuidRe = Regex("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}") + + private fun normalize(e: JsonElement): JsonElement { + val compact = Json.encodeToString(JsonElement.serializer(), e) + val seen = LinkedHashMap() + val renumbered = uuidRe.replace(compact) { m -> + seen.getOrPut(m.value.lowercase()) { "uuid-${seen.size + 1}" } + } + return unwrap(Json.parseToJsonElement(renumbered)) + } + + private fun unwrap(e: JsonElement): JsonElement = when (e) { + is JsonArray -> if (e.size == 1) unwrap(e[0]) else JsonArray(e.map { unwrap(it) }) + is JsonObject -> JsonObject(e.mapValues { unwrap(it.value) }) + else -> e + } + + private fun firstDiff(a: JsonElement, b: JsonElement, path: String): String? { + if (a::class != b::class) return "$path (kind: oracle=${a::class.simpleName} ours=${b::class.simpleName})" + when (a) { + is JsonObject -> { + b as JsonObject + for (k in a.keys + b.keys) { + val av = a[k]; val bv = b[k] + if (av == null) return "$path.$k (extra in ours: ${short(bv)})" + if (bv == null) return "$path.$k (missing in ours; oracle=${short(av)})" + firstDiff(av, bv, "$path.$k")?.let { return it } + } + } + is JsonArray -> { + b as JsonArray + if (a.size != b.size) return "$path (size: oracle=${a.size} ours=${b.size})" + a.indices.forEach { i -> firstDiff(a[i], b[i], "$path[$i]")?.let { return it } } + } + else -> if (a != b) return "$path (oracle=${short(a)} ours=${short(b)})" + } + return null + } + + private fun short(e: JsonElement?): String = + (e?.toString() ?: "null").let { if (it.length > 60) it.take(60) + "…" else it } +} From 7adf136686e95875e660057fbc1f5c87444b4ab7 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Sat, 5 Sep 2026 11:02:22 -1000 Subject: [PATCH 08/11] Full equivalence on the ncsa corpus: 14/14 (immz 33/33 intact) Executor semantics learned from ddcc/smart-ot oracle diffs: - entry roots emit resourceType from the SD's type (resource + logical kinds) - bare target contexts (-> tgt then ...) bind without mutating - source type casts filter by resourceType - declared max governs replace-vs-append even for computed writes - declared child types resolve from their own SD (nested LM URL, named datatype core SD, backbone falls back to parent's leaf map) - primitive writes into complex-declared elements drop (reference behavior) - created nodes remember their type for choice-element naming and core-SD cardinality lookups - FHIRPath conditions: in(), and, exists(), exists().not(), .value on prims - leaf-flattened SD maps: shallower element wins collisions - comparison contract: uuids number by fullUrl (entry identity) first Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- .../org/litlfred/fmlrunner/FmlRunner.kt | 16 ++- .../litlfred/fmlrunner/executor/FmlEngine.kt | 97 ++++++++++++++++-- .../fmlrunner/NcsaConformanceSpike.kt | 12 +++ 5 files changed, 114 insertions(+), 13 deletions(-) diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 2b015fe79244867cfa2d12177a44100db1c55e81..41cee7bbf149e70b7a75ee8cdd3252d437040a05 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~oMJ001xn1SbFh literal 17 VcmZRc8C-F+LssMw0~oNr1pqLT1iAnK diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index 77aa5e0..cfa366e 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Sat Sep 05 10:43:04 HST 2026 +#Sat Sep 05 11:01:51 HST 2026 gradle.version=8.14.2 diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt index c7fcc88..f7c82fd 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt @@ -20,6 +20,7 @@ class FmlRunner { private val conceptMapStore = mutableMapOf() private val typeStore = mutableMapOf>() // SD url -> element leaf -> type code private val displayStore = mutableMapOf() // "system|code" -> display + private val logicalTypeNames = mutableMapOf() // logical SD url -> resourceType name // kotlin-fhir terminology services private val conceptMapService = ConceptMapService() @@ -50,7 +51,8 @@ class FmlRunner { resolveMap = { ref -> getStructureMap(ref) }, resolveConceptMap = { url -> conceptMapStore[url] }, resolveElementTypes = { url -> typeStore[url] }, - resolveDisplay = { system, code -> displayStore["$system|$code"] } + resolveDisplay = { system, code -> displayStore["$system|$code"] }, + resolveLogicalTypeName = { url -> logicalTypeNames[url] } ) return engine.execute(structureMap, source) } @@ -98,9 +100,19 @@ class FmlRunner { ?.firstOrNull() as? JsonObject)?.get("code") as? JsonPrimitive ?: continue val code = type.contentOrNull ?: continue val max = (eo["max"] as? JsonPrimitive)?.contentOrNull ?: "1" - types[id.substringAfterLast('.')] = "$code|$max" + // leaf-flattened: on collisions the shallower (earlier) element + // wins — root-level elements precede nested ones in snapshots + types.getOrPut(id.substringAfterLast('.')) { "$code|$max" } } typeStore[url] = types + // Resource- and logical-model roots serialize with resourceType + // taken from the SD's `type` (its last segment), matching the + // reference engine; complex-type SDs get none. + if ((o["kind"] as? JsonPrimitive)?.contentOrNull in setOf("logical", "resource")) { + (o["type"] as? JsonPrimitive)?.contentOrNull?.let { + logicalTypeNames[url] = it.substringAfterLast('/') + } + } true } catch (e: Exception) { false diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt index ef7ba37..9ba089b 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt @@ -25,6 +25,7 @@ class FmlEngine( private val resolveMap: (String) -> StructureMap?, private val resolveConceptMap: (String) -> JsonObject? = { null }, private val resolveElementTypes: (String) -> Map? = { null }, + private val resolveLogicalTypeName: (String) -> String? = { null }, private val resolveDisplay: (String, String) -> String? = { _, _ -> null } ) { @@ -34,6 +35,8 @@ class FmlEngine( class MObj : MNode() { /** StructureDefinition url of the type this node instantiates, when known. */ var typeUrl: String? = null + /** Simple complex-type name (e.g. HumanName), when created or declared as one. */ + var typeName: String? = null val fields = LinkedHashMap>() fun append(name: String, node: MNode, replaceIfSingular: Boolean = false) { val list = fields.getOrPut(name) { mutableListOf() } @@ -50,7 +53,8 @@ class FmlEngine( /** FHIR repeating elements the corpus writes more than once per node. */ val RESOURCE_TYPES = setOf( "Patient", "RelatedPerson", "Observation", "Immunization", "AdverseEvent", - "Bundle", "Practitioner", "Encounter", "Condition", "Organization" + "Bundle", "Practitioner", "Encounter", "Condition", "Organization", + "Composition", "DiagnosticReport", "Specimen" ) val REPEATING_ELEMENTS = setOf( "entry", "extension", "identifier", "name", "telecom", "address", @@ -94,6 +98,10 @@ class FmlEngine( /** Read child elements by name from a source-side value (choice-aware). */ private fun readElement(v: Any, name: String): List { return when (v) { + // `.value` on a primitive is the primitive itself (FHIRPath's view of + // primitive types, e.g. `linkId.value`) + is JsonPrimitive -> if (name == "value") listOf(v) else emptyList() + is MPrim -> if (name == "value") listOf(v) else emptyList() is JsonObject -> { val exact = v[name] val hits = mutableListOf() @@ -131,9 +139,8 @@ class FmlEngine( } } if (declared != null) { - // complex child of a typed node: nested element leaves resolve - // from the same (leaf-flattened) SD map - exact.forEach { hit -> if (hit is MObj && hit.typeUrl == null) hit.typeUrl = v.typeUrl } + val childUrl = childTypeUrl(declared, v.typeUrl) + exact.forEach { hit -> if (hit is MObj && hit.typeUrl == null) hit.typeUrl = childUrl } } exact.toList() } else v.fields.entries @@ -143,6 +150,24 @@ class FmlEngine( else -> emptyList() } } + /** + * SD a declared child type resolves its own elements from: a URL names a + * nested model directly; a named datatype maps to its core SD; inline + * backbones (and primitives) stay on the parent's leaf-flattened map. + */ + private fun childTypeUrl(declared: String, parentUrl: String?): String? = when { + declared.startsWith("http") -> declared + declared == "BackboneElement" || declared == "Element" -> parentUrl + declared.first().isUpperCase() -> "http://hl7.org/fhir/StructureDefinition/$declared" + else -> parentUrl + } + + private fun typeNameOf(item: Any?): String? = when (item) { + is JsonObject -> (item["resourceType"] as? JsonPrimitive)?.contentOrNull + is MObj -> (item.fields["resourceType"]?.firstOrNull() as? MPrim)?.value?.contentOrNull + else -> null + } + private fun primString(v: Any?): String? = when (v) { is JsonPrimitive -> v.contentOrNull is MPrim -> v.value.contentOrNull @@ -167,10 +192,17 @@ class FmlEngine( } InputMode.TARGET -> { val root = MObj() - resourceTypeForInput(map, input)?.let { root.append("resourceType", MPrim(JsonPrimitive(it))) } + // The input's declared type names either a uses alias or + // the last segment of a uses URL (both occur in WHO maps) input.type?.let { alias -> - map.structure?.firstOrNull { it.alias == alias }?.url?.let { root.typeUrl = it } + map.structure?.firstOrNull { + it.alias == alias || it.url.substringAfterLast('/') == alias + }?.url?.let { root.typeUrl = it } } + resourceTypeForInput(map, input)?.let { root.append("resourceType", MPrim(JsonPrimitive(it))) } + ?: root.typeUrl?.let { u -> + resolveLogicalTypeName(u)?.let { root.append("resourceType", MPrim(JsonPrimitive(it))) } + } if (targetRoot == null) targetRoot = root scope.bind(input.name, root) } @@ -205,6 +237,9 @@ class FmlEngine( val ctx = scope.lookup(src.context) ?: throw EngineError("Unknown source context '${src.context}'") var items: List = if (src.element != null) readElement(ctx, src.element!!) else listOf(ctx) + // Type cast (`entry.resource : Patient`) filters by resourceType + src.type?.let { t -> items = items.filter { typeNameOf(it) == t } } + when (src.listMode) { null -> {} "first" -> items = items.take(1) @@ -265,6 +300,12 @@ class FmlEngine( if (t.context != null) { val node = scope.lookup(t.context!!) as? MObj ?: throw EngineError("Target context '${t.context}' is not a target node") + if (t.element == null && t.transform == null) { + // Bare context target (`-> tgt` / `-> tgt as t`): names an + // existing node as this rule's target without mutating it + t.variable?.let { scope.bind(it, node) } + return + } var element = t.element ?: throw EngineError("Target context '${t.context}' without element") var placed = computed ?: MObj() if (computed != null && isChoiceWrite(element, node)) { @@ -272,9 +313,21 @@ class FmlEngine( element += suffix placed = unwrapped } - val declaredMax = node.typeUrl - ?.let { resolveElementTypes(it)?.get(t.element!!) }?.substringAfter('|', "?") - node.append(element, placed, replaceIfSingular = computed != null || declaredMax == "1") + val declaredEntry = node.typeUrl?.let { resolveElementTypes(it)?.get(t.element!!) } + val declaredCode = declaredEntry?.substringBefore('|') + val declaredMax = declaredEntry?.substringAfter('|', "?") + // A primitive cannot be coerced into a complex-declared element + // (e.g. integer into Quantity); the reference drops such writes + if (computed is MPrim && declaredCode != null && declaredCode.first().isUpperCase()) return + // Carry the declared type so the child's own elements resolve from + // the right SD (nested logical model, named datatype, or inline + // backbone falling back to the parent's leaf-flattened map) + if (placed is MObj && placed.typeUrl == null && declaredCode != null) { + placed.typeUrl = childTypeUrl(declaredCode, node.typeUrl) + } + // Declared max governs replace-vs-append even for computed writes + val replace = if (declaredMax == "*") false else (computed != null || declaredMax == "1") + node.append(element, placed, replaceIfSingular = replace) t.variable?.let { scope.bind(it, placed) } } else { val v = computed ?: throw EngineError("Target with neither context nor transform") @@ -303,8 +356,13 @@ class FmlEngine( } "create" -> MObj().also { o -> val type = primString(argValue(0)) ?: throw EngineError("create: missing type") - if (type in RESOURCE_TYPES) o.append("resourceType", MPrim(JsonPrimitive(type))) + if (type in RESOURCE_TYPES) { + o.append("resourceType", MPrim(JsonPrimitive(type))) + // core SD (when registered) supplies element cardinalities + o.typeUrl = "http://hl7.org/fhir/StructureDefinition/$type" + } if (type.contains('/')) o.typeUrl = type + else if (type !in RESOURCE_TYPES && type.first().isUpperCase()) o.typeName = type } "append" -> MPrim(JsonPrimitive(params.indices.joinToString("") { i -> primString(argValue(i)) ?: throw EngineError("append: parameter $i has no primitive value") @@ -373,6 +431,8 @@ class FmlEngine( return tag to (v.fields["value"]!!.single()) } } + // created/declared complex-type name wins over shape heuristics + if (v is MObj && v.typeName != null) return v.typeName!! to v // Quantity shape (value + unit) if (v is MObj && v.fields.containsKey("value") && v.fields.containsKey("unit")) return "Quantity" to v // Coding shape @@ -425,6 +485,23 @@ class FmlEngine( /** Handles `path = 'literal'` and bare `path` (existence). */ private fun evalCondition(expr: String, focus: Any, scope: Scope): Boolean { + // membership: path in ('a', 'b') + Regex("^(.*?)\\s+in\\s*\\((.*)\\)\\s*$").find(expr)?.let { m -> + val values = Regex("'([^']*)'").findAll(m.groupValues[2]).map { it.groupValues[1] }.toSet() + return evalPath(m.groupValues[1].trim(), focus, scope).any { primString(it) in values } + } + // conjunction: A and B (top-level; corpus conditions have no nesting) + if (expr.contains(" and ")) { + return expr.split(" and ").all { evalCondition(it.trim(), focus, scope) } + } + // existence: path.exists() / path.exists().not() + val stripped = expr.replace(" ", "") + if (stripped.endsWith(".exists().not()")) { + return evalPath(stripped.removeSuffix(".exists().not()"), focus, scope).isEmpty() + } + if (stripped.endsWith(".exists()")) { + return evalPath(stripped.removeSuffix(".exists()"), focus, scope).isNotEmpty() + } val eq = expr.split('=', limit = 2) return if (eq.size == 2) { val expected = eq[1].trim().removeSurrounding("'") diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt index eca5b5b..9ef37e5 100644 --- a/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt @@ -38,6 +38,12 @@ class NcsaConformanceSpike { registerPackage(runner, File(corpus, "$repo/package")) } registerPackage(runner, File(home, ".fhir/packages/hl7.fhir.uv.shc-vaccination#1.0.0/package")) + // core R4 SDs supply element cardinalities (replace-vs-append on + // singular resource elements like Encounter.subject) + File(home, ".fhir/packages/hl7.fhir.r4.core#4.0.1/package") + .listFiles { f -> f.name.startsWith("StructureDefinition-") }?.forEach { + runner.registerStructureDefinition(it.readText()) + } File(home, ".fhir/packages/hl7.terminology.r4#6.2.0/package") .listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { runner.registerCodeSystem(it.readText()) @@ -105,6 +111,12 @@ class NcsaConformanceSpike { private fun normalize(e: JsonElement): JsonElement { val compact = Json.encodeToString(JsonElement.serializer(), e) val seen = LinkedHashMap() + // Number uuids by entry identity (fullUrl order) first, so field + // serialization order inside a resource cannot shift the numbering; + // any remaining uuids number by first appearance. + Regex("\"fullUrl\":\"urn:uuid:(${uuidRe.pattern})\"").findAll(compact).forEach { m -> + seen.getOrPut(m.groupValues[1].lowercase()) { "uuid-${seen.size + 1}" } + } val renumbered = uuidRe.replace(compact) { m -> seen.getOrPut(m.value.lowercase()) { "uuid-${seen.size + 1}" } } From cbaf82fcf3dcfd469aa22d7e9e9d9e723625ae24 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Sat, 5 Sep 2026 12:33:47 -1000 Subject: [PATCH 09/11] Spikes: corpus paths via env vars, skip cleanly when absent Immz maps now load from the conformance repo's maps/ dir, making github.com/dhes/fmlrunner-conformance the single dependency for the 33-fixture run. The ncsa spike skips without its (unpublished) corpus. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- .../fmlrunner/ImmzConformanceSpike.kt | 24 +++++++++++++----- .../fmlrunner/NcsaConformanceSpike.kt | 10 +++++++- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 41cee7bbf149e70b7a75ee8cdd3252d437040a05..87419131c251a079a4c06760b60d8c4aa7fcdb0f 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~oNE0{}1}1V#V= literal 17 VcmZRc8C-F+LssMw0~oMJ001xn1SbFh diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index cfa366e..fbdb131 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Sat Sep 05 11:01:51 HST 2026 +#Sat Sep 05 12:33:04 HST 2026 gradle.version=8.14.2 diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt index 9ac6a8e..220acd5 100644 --- a/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/ImmzConformanceSpike.kt @@ -12,8 +12,13 @@ import kotlin.test.Test */ class ImmzConformanceSpike { - private val mapsDir = File(System.getProperty("user.home"), "projects/smart-immunizations-fresher/input/maps") - private val fixturesDir = File(System.getProperty("user.home"), "projects/fmlrunner-conformance") + // Clone github.com/dhes/fmlrunner-conformance (CC0) and point + // FMLRUNNER_CONFORMANCE_DIR at it; the test skips when absent. + private val fixturesDir = File( + System.getenv("FMLRUNNER_CONFORMANCE_DIR") + ?: File(System.getProperty("user.home"), "projects/fmlrunner-conformance").path + ) + private val mapsDir = File(fixturesDir, "maps") private fun loadRunner(): FmlRunner { val runner = FmlRunner() @@ -33,10 +38,13 @@ class ImmzConformanceSpike { } // HL7 terminology CodeSystems the reference engine resolves via its loaded // terminology packages (from the local FHIR package cache) - File(System.getProperty("user.home"), ".fhir/packages/hl7.terminology.r4#6.2.0/package") - .listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { - runner.registerCodeSystem(it.readText()) - } + val term = File(System.getProperty("user.home"), ".fhir/packages/hl7.terminology.r4#6.2.0/package") + if (!term.isDirectory) { + println("WARN: $term missing — display lookups will diff (fetch it by running validator_cli once)") + } + term.listFiles { f -> f.name.startsWith("CodeSystem-") }?.forEach { + runner.registerCodeSystem(it.readText()) + } return runner } @@ -47,6 +55,10 @@ class ImmzConformanceSpike { @Test fun scoreAllFixtures() { + if (!fixturesDir.isDirectory) { + return println("SKIPPED: conformance corpus not found at $fixturesDir " + + "(clone github.com/dhes/fmlrunner-conformance or set FMLRUNNER_CONFORMANCE_DIR)") + } val runner = loadRunner() println("=== Conformance score: 33 fixtures vs oracle ===") var match = 0; var diff = 0; var error = 0 diff --git a/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt b/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt index 9ef37e5..ee4f31f 100644 --- a/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt +++ b/src/jvmTest/kotlin/org/litlfred/fmlrunner/NcsaConformanceSpike.kt @@ -11,8 +11,13 @@ import kotlin.test.Test */ class NcsaConformanceSpike { + // This corpus is not published (CC BY-NC-SA content); the test skips + // when it is absent. Set FMLRUNNER_CONFORMANCE_NCSA_DIR to point at it. private val home = File(System.getProperty("user.home")) - private val corpus = File(home, "projects/fmlrunner-conformance-ncsa") + private val corpus = File( + System.getenv("FMLRUNNER_CONFORMANCE_NCSA_DIR") + ?: File(home, "projects/fmlrunner-conformance-ncsa").path + ) private fun registerPackage(runner: FmlRunner, dir: File) { dir.listFiles { f -> f.name.startsWith("ConceptMap-") }?.forEach { @@ -80,6 +85,9 @@ class NcsaConformanceSpike { @Test fun scoreAllFixtures() { + if (!corpus.isDirectory) { + return println("NCSA SKIPPED: corpus not found at $corpus (local-only, license-separated)") + } val runner = loadRunner() val all = fixtures() println("NCSA === Conformance score: ${all.size} fixtures vs oracle ===") From 2190f5e51351791c4bd6eb6044580780234c1b93 Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Sat, 5 Sep 2026 12:43:21 -1000 Subject: [PATCH 10/11] Add Apple and wasmJs targets + maven-publish Pure-common code; bumps kotlinx-serialization/datetime to wasm/native-capable versions. Publishes org.litlfred.fmlrunner:fmlrunner:0.1.0. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- build.gradle.kts | 14 ++++++++++++-- .../kotlin/org/litlfred/fmlrunner/Platform.kt | 13 +++++++++++++ .../kotlin/org/litlfred/fmlrunner/Platform.kt | 13 +++++++++++++ 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 src/appleMain/kotlin/org/litlfred/fmlrunner/Platform.kt create mode 100644 src/wasmJsMain/kotlin/org/litlfred/fmlrunner/Platform.kt diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 87419131c251a079a4c06760b60d8c4aa7fcdb0f..9bfadf72b526ce7abae958b0f37596f0e10f2beb 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~l~H001wm1JD2f literal 17 VcmZRc8C-F+LssMw0~oNE0{}1}1V#V= diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index fbdb131..14fc6c9 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Sat Sep 05 12:33:04 HST 2026 +#Sat Sep 05 12:41:29 HST 2026 gradle.version=8.14.2 diff --git a/build.gradle.kts b/build.gradle.kts index 5092c68..9d9202a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") version "2.1.0" kotlin("plugin.serialization") version "2.1.0" + id("maven-publish") } group = "org.litlfred.fmlrunner" @@ -27,6 +28,15 @@ kotlin { } } + iosArm64() + iosSimulatorArm64() + iosX64() + + @OptIn(org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl::class) + wasmJs { + browser() + } + js(IR) { browser { testTask { @@ -53,8 +63,8 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") // kotlin-fhirpath dependency from https://github.com/jingtang10/kotlin-fhirpath // Note: JitPack access still blocked - will integrate when network allows // implementation("com.github.jingtang10:kotlin-fhirpath:0.1.0") diff --git a/src/appleMain/kotlin/org/litlfred/fmlrunner/Platform.kt b/src/appleMain/kotlin/org/litlfred/fmlrunner/Platform.kt new file mode 100644 index 0000000..55a5316 --- /dev/null +++ b/src/appleMain/kotlin/org/litlfred/fmlrunner/Platform.kt @@ -0,0 +1,13 @@ +package org.litlfred.fmlrunner + +/** + * Apple platform-specific implementations + */ +actual class PlatformLogger { + actual fun log(level: String, message: String, data: Any?) { + val logMessage = "${level.uppercase()}: $message" + println("$logMessage ${data ?: ""}") + } +} + +actual fun getPlatformName(): String = "Apple" diff --git a/src/wasmJsMain/kotlin/org/litlfred/fmlrunner/Platform.kt b/src/wasmJsMain/kotlin/org/litlfred/fmlrunner/Platform.kt new file mode 100644 index 0000000..0c3bded --- /dev/null +++ b/src/wasmJsMain/kotlin/org/litlfred/fmlrunner/Platform.kt @@ -0,0 +1,13 @@ +package org.litlfred.fmlrunner + +/** + * wasmJs platform-specific implementations + */ +actual class PlatformLogger { + actual fun log(level: String, message: String, data: Any?) { + val logMessage = "${level.uppercase()}: $message" + println("$logMessage ${data ?: ""}") + } +} + +actual fun getPlatformName(): String = "wasmJs" From 60d5ccb6791b9f9bbaf6bfd021e744e75fb5750f Mon Sep 17 00:00:00 2001 From: Dan Heslinga Date: Sat, 5 Sep 2026 16:00:18 -1000 Subject: [PATCH 11/11] FHIR-shaped JSON output: repeating elements serialize as arrays Singleton values of repeating elements (name, given, entry, ...) were emitted bare, which normalized-diff scoring tolerated but strict FHIR parsers reject. Arrays now come from declared cardinality when an SD is registered, with the REPEATING_ELEMENTS set as fallback. 47/47 intact. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01LGgxE9TK56BNPJJX2PnYhj --- .../buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 +- .../org/litlfred/fmlrunner/executor/FmlEngine.kt | 7 ++++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 9bfadf72b526ce7abae958b0f37596f0e10f2beb..85d4ed95a1f90d42949d5a0ac10aba837375db4d 100644 GIT binary patch literal 17 VcmZRc8C-F+LssMw0~l}=0{}1{1VaD- literal 17 VcmZRc8C-F+LssMw0~l~H001wm1JD2f diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index 14fc6c9..69cff84 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Sat Sep 05 12:41:29 HST 2026 +#Sat Sep 05 15:37:42 HST 2026 gradle.version=8.14.2 diff --git a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt index 9ba089b..8599e42 100644 --- a/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt +++ b/src/commonMain/kotlin/org/litlfred/fmlrunner/executor/FmlEngine.kt @@ -79,7 +79,12 @@ class FmlEngine( for ((k, list) in n.fields) { val items = list.mapNotNull { mToJson(it) } if (items.isEmpty()) continue - put(k, if (items.size == 1) items[0] else JsonArray(items)) + // FHIR JSON requires arrays for repeating elements even + // when a single value is present + val repeating = k in REPEATING_ELEMENTS || + n.typeUrl?.let { resolveElementTypes(it)?.get(k) } + ?.substringAfter('|', "1") == "*" + put(k, if (items.size == 1 && !repeating) items[0] else JsonArray(items)) } } if (o.isEmpty()) null else JsonObject(o)