From ccb29370d6c829182caf0729b30d58bfe2e5e90c Mon Sep 17 00:00:00 2001 From: JKRT Date: Sat, 10 Oct 2026 09:57:40 +0200 Subject: [PATCH 1/4] Grammar: break modifiers (Modelica 3.6 selective model extension) extends A(break x), extends A(break connect(a, b)) and modifier values x = break, as in omc's Modelica.g (Absyn INHERITANCEBREAK and BREAK; needs the Absyn with them). Assisted-by: Claude Opus 5.5 --- lib/parser/Modelica.g | 61 +++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/lib/parser/Modelica.g b/lib/parser/Modelica.g index 622a25b..3172886 100644 --- a/lib/parser/Modelica.g +++ b/lib/parser/Modelica.g @@ -595,7 +595,7 @@ implicit_import_name returns [void* ast] // allowing the comment. extends_clause returns [void* ast] @init { OM_PUSHZ3(path, mod, ann); } : - EXTENDS path=name_path (mod=class_modification)? (ann=annotation)? + EXTENDS path=name_path (mod=class_or_inheritance_modification)? (ann=annotation)? { ast = Absyn__EXTENDS(path,or_nil(mod),mmc_mk_some_or_none(ann)); } @@ -741,37 +741,66 @@ declaration returns [void* ast] */ modification returns [void* ast] -@init { OM_PUSHZ2(e.ast, cm); eq = 0; } : - ( cm=class_modification ( eq=EQUALS e=expression[metamodelica_enabled()] )? - | eq=EQUALS e=expression[metamodelica_enabled()] - | eq=ASSIGN e=expression[metamodelica_enabled()] {c_add_source_message(NULL,2, ErrorType_syntax, ErrorLevel_warning, ":= in modifiers has been deprecated", +@init { OM_PUSHZ2(e, cm); eq = 0; } : + ( cm=class_modification ( eq=EQUALS e=modification_expression )? + | eq=EQUALS e=modification_expression + | eq=ASSIGN e=modification_expression {c_add_source_message(NULL,2, ErrorType_syntax, ErrorLevel_warning, ":= in modifiers has been deprecated", NULL, 0, $start->line, $start->charPosition+1, LT(1)->line, LT(1)->charPosition+1, ModelicaParser_readonly, ModelicaParser_filename_C_testsuiteFriendly);} ) { - $ast = Absyn__CLASSMOD(or_nil(cm), e.ast ? Absyn__EQMOD(e.ast,PARSER_INFO($eq)) : Absyn__NOMOD); + $ast = Absyn__CLASSMOD(or_nil(cm), e ? Absyn__EQMOD(e,PARSER_INFO($eq)) : Absyn__NOMOD); } ; finally{ OM_POP(2); } +/* A modifier's value, or `break` to remove the binding (Modelica 3.6). */ +modification_expression returns [void* ast] +@init { OM_PUSHZ1(e.ast); } : + e=expression[metamodelica_enabled()] { ast = e.ast; } + | BREAK { ast = Absyn__BREAK; } + ; + finally{ OM_POP(1); } + class_modification returns [void* ast] @init { OM_PUSHZ2(as, ast); } : - LPAR ( as=argument_list )? RPAR { ast = or_nil(as); } + LPAR ( as=argument_list[0] )? RPAR { ast = or_nil(as); } ; finally{ OM_POP(2); } -argument_list returns [void* ast] -@init { OM_PUSHZ3(a, as, ast); } : - a=argument ( COMMA as=argument_list )? +/* The modification of an extends clause, which may also break inherited elements (Modelica 3.6 + selective model extension). */ +class_or_inheritance_modification returns [void* ast] +@init { OM_PUSHZ2(as, ast); } : + LPAR ( as=argument_list[1] )? RPAR { ast = or_nil(as); } + ; + finally{ OM_POP(2); } + +argument_list [int canHaveBreak] returns [void* ast] +@init { OM_PUSHZ4(a, b.ast, as, ast); } : + (a=argument | {canHaveBreak == 1}? b=inheritance_modification) ( COMMA as=argument_list[canHaveBreak] )? { - if (!a) - { - fprintf(stderr, "crap!\n"); - } - ast = mmc_mk_cons_typed(Absyn_ElementArg, a, or_nil(as)); + ast = mmc_mk_cons_typed(Absyn_ElementArg, a ? a : b.ast, or_nil(as)); } ; - finally{ OM_POP(3); } + finally{ OM_POP(4); } + +/* `break x` (stored as connect(break, x), as omc) or `break connect(a, b)`. */ +inheritance_modification returns [void* ast] +@init { i = 0; OM_PUSHZ1(c); } : + BREAK ( c=connect_clause { $ast = Absyn__INHERITANCEBREAK(c, PARSER_INFO($start)); } + | i=IDENT + { + $ast = Absyn__INHERITANCEBREAK( + Absyn__EQ_5fCONNECT( + Absyn__CREF_5fIDENT(mmc_mk_scon("break"),mmc_mk_nil()), + Absyn__CREF_5fIDENT(token_to_scon(i),mmc_mk_nil()) + ), + PARSER_INFO($start)); + } + ) + ; + finally{ OM_POP(1); } argument returns [void* ast] @init { OM_PUSHZ2(em, er.ast); } : From a0221e1a7e6b2401c5c339b1cf744976b04aa6c6 Mon Sep 17 00:00:00 2001 From: JKRT Date: Sat, 10 Oct 2026 09:59:21 +0200 Subject: [PATCH 2/4] Test: break modifiers Assisted-by: Claude Opus 5.5 --- test/runtests.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 8861d53..264dd7b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -92,6 +92,29 @@ cd(@__DIR__) do include("metaModelicaTests.jl") #= Warning might be flaky... =# + #= Modelica 3.6 selective model extension. =# + @testset "Break modifiers" begin + local p = OMParser.parseString(""" + model B + extends A(break x, break connect(a.p, b.n), y = 2); + Real z(start = break) = break; + end B; + """) + local parts = p.classes.head.body.classParts.head.contents + local ext = parts.head.element.specification + local args = collect(ext.elementArg) + @test length(args) == 3 + @test args[1] isa OMParser.Absyn.INHERITANCEBREAK + @test args[1].cnct.connector1.name == "break" && args[1].cnct.connector2.name == "x" + @test args[2] isa OMParser.Absyn.INHERITANCEBREAK + @test args[2].cnct.connector1 isa OMParser.Absyn.CREF_QUAL + @test args[3] isa OMParser.Absyn.MODIFICATION + local comp = parts.tail.head.element.specification.components.head.component + @test comp.modification.data.eqMod.exp isa OMParser.Absyn.BREAK + #= Only extends clauses may break elements. =# + @test_throws Exception OMParser.parseString("model M A a(break x); end M;") + end + @testset "Standard Library" begin @test true == begin try From 42f35d1e757d114e0154ffa96c13ed4542621d90 Mon Sep 17 00:00:00 2001 From: JKRT Date: Sat, 10 Oct 2026 11:13:53 +0200 Subject: [PATCH 3/4] Header: a record missing from the loaded Absyn fails only where it is built The constructors are looked up by name without asserts; the syntax that builds a record the loaded Absyn lacks raises a Julia error instead. A library built from a newer grammar then still parses everything else with an older Absyn. Assisted-by: Claude Opus 5.5 --- lib/parser/GenerateJLHeader.jl | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/parser/GenerateJLHeader.jl b/lib/parser/GenerateJLHeader.jl index 528cf11..49569d5 100644 --- a/lib/parser/GenerateJLHeader.jl +++ b/lib/parser/GenerateJLHeader.jl @@ -178,6 +178,10 @@ function programExternalHeaderJulia(allDataTypes, moduleName) local jlValues::String = generateJL_Values(allDataTypes) #= Generate all JL values=# println(buffer, jlValues) + println(buffer, "jl_value_t *OMParser_missingAbsyn(const char *name) {") + println(buffer, " jl_errorf(\"The loaded Absyn package has no Absyn.%s, which this OMParser library builds: update Absyn.\", name);") + println(buffer, " return NULL;") + println(buffer, "}") println(buffer, "void OpenModelica_initAbsynReferences() {") #= Get the code in the body of initAbsynReferences =# local jlAsserts = generateJL_Asserts(allDataTypes, moduleName) @@ -278,10 +282,13 @@ function generateJL_Asserts(allDataTypes, moduleName) local qualifiedName = getSuperTypePath(dataType) #= Get qualified path for basic datatype =# local baseTypeStr = components[2] - local assertStr1 = "assert(($qualifiedName = jl_get_function($(moduleName), \"$(baseTypeStr)\")));" - local assertStr2 = "assert(($(qualifiedName)_type = jl_get_global($(moduleName), jl_symbol(\"$(baseTypeStr)\"))));" - println(buffer, assertStr1) - println(buffer, assertStr2) + #= Not asserted: a record the loaded Absyn lacks (an older Absyn than the grammar's) stays + NULL, and only the syntax that builds it fails (OMParser_missingAbsyn), so a library built + from a newer grammar still works with an older Absyn. =# + local assignStr1 = "$qualifiedName = jl_get_function($(moduleName), \"$(baseTypeStr)\");" + local assignStr2 = "$(qualifiedName)_type = jl_get_global($(moduleName), jl_symbol(\"$(baseTypeStr)\"));" + println(buffer, assignStr1) + println(buffer, assignStr2) #=TODO is the double underscore important?=# end end @@ -300,6 +307,7 @@ This is followed by a function definition function generateExternalDeclarations(allSuperTypes) local buffer = IOBuffer() println(buffer, "/* Extern declarations */") + println(buffer, "jl_value_t *OMParser_missingAbsyn(const char *name);") for superType in allSuperTypes local subTypes = subtypes(superType) local components = split(string(superType), ".") @@ -325,7 +333,7 @@ function generateExternalDeclarations(allSuperTypes) local fieldNameLength = length(fieldNames) local fullName = string("Absyn__", replace(getBaseNameAsStr(subType), "_" => "_5f")) if fieldNameLength == 0 - println(buffer, "#define $(fullName) jl_call0($(qualifiedName))") + println(buffer, "#define $(fullName) ($(qualifiedName) ? jl_call0($(qualifiedName)) : OMParser_missingAbsyn(\"$(baseTypeStr)\"))") elseif fieldNameLength <= 3 local fieldNamesAsStrWithType = join(map((x) -> string("jl_value_t *", x), fieldNames), ", ") local fieldNamesAsStrWithoutType = join(map(string, fieldNames), ", ") @@ -334,6 +342,7 @@ function generateExternalDeclarations(allSuperTypes) local body = string("return ","jl_call", string(fieldNameLength), "(", qualifiedName, ", " ,fieldNamesAsStrWithoutType, ")", ";") local staticFuncEpilog = "}" println(buffer, staticFuncHeader) + println(buffer, "if (!$(qualifiedName)) return OMParser_missingAbsyn(\"$(baseTypeStr)\");") println(buffer, body) println(buffer, staticFuncEpilog) else @@ -345,6 +354,7 @@ function generateExternalDeclarations(allSuperTypes) local returnStmt = string("return ","jl_call", "(", qualifiedName, ", " ,"values, ", "$(fieldNameLength)" ,")", ";") local staticFuncEpilog = "}" println(buffer, staticFuncHeader) + println(buffer, "if (!$(qualifiedName)) return OMParser_missingAbsyn(\"$(baseTypeStr)\");") println(buffer, arrayDecl) println(buffer, returnStmt) println(buffer, staticFuncEpilog) From 1f1a3528e51de400145f6b781f22ecd9cc0a0f4c Mon Sep 17 00:00:00 2001 From: JKRT Date: Sat, 10 Oct 2026 11:14:03 +0200 Subject: [PATCH 4/4] OMParser 0.2.2: Absyn 1.4 (break modifiers) Assisted-by: Claude Opus 5.5 --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index ee7f35a..7df425a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "OMParser" uuid = "11f87224-cae7-4e99-a924-e50d12f62c59" authors = ["Adrian Pop ", "John Tinnerholm "] -version = "0.2.1" +version = "0.2.2" [deps] Absyn = "ce2f92e2-a952-11e9-0543-8b443f216f1d" @@ -20,7 +20,7 @@ ZipFile = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea" [compat] julia = "1.13" -Absyn = "=1.3.5" +Absyn = "1.4" ImmutableList = "0.4.2" MetaModelica = "0.4.2"