diff --git a/Project.toml b/Project.toml index 253eb6e..3e7e167 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" ExportAll = "ad2082ca-a69e-11e9-38fa-e96309a31fe4" ImmutableList = "4a558cac-c1ed-11e9-20da-3584bcd8709a" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" [compat] julia = "1.1" diff --git a/src/MetaModelica.jl b/src/MetaModelica.jl index ce65f49..e65feb9 100644 --- a/src/MetaModelica.jl +++ b/src/MetaModelica.jl @@ -3,7 +3,9 @@ module MetaModelica import MacroTools import MacroTools: @capture import ExportAll - #= +import Setfield: @set! +import Setfield: @set +#= Have to treat the types slightly different. Precompilation of the types need to occur before everything else =# @@ -18,17 +20,16 @@ include("matchcontinue.jl") include("functionInheritance.jl") include("metaRuntime.jl") include("shouldFail.jl") +include("utilityMacros.jl") export @match, @matchcontinue, MatchFailure, ModelicaReal, ModelicaInteger export @Uniontype, @Record, @UniontypeDecl, @ExtendedFunction, @ExtendedAnonFunction export List, list, Nil, nil, Cons, cons, =>, Option, SOME, NONE, SourceInfo, SOURCEINFO export @do_threaded_for, <|, @shouldFail, sourceInfo, _cons, @importDBG +export @assign include("exportmetaRuntime.jl") include("dangerous.jl") include("array.jl") - -#=============================# end - diff --git a/src/matchcontinue.jl b/src/matchcontinue.jl index 9a532d7..881cab4 100644 --- a/src/matchcontinue.jl +++ b/src/matchcontinue.jl @@ -15,9 +15,10 @@ limitations under the License. The code is based on https://github.com/RelationalAI-oss/Rematch.jl with - changed to allow keyword argument matching on a struct as well as - supporting @matchcontinue (try the next case when any exception is thrown). - """ + changed to allow keyword argument matching on a struct, matching on the immutable list construct + accompanying MetaModelica. + It also provides @matchcontinue macro (try the next case when any exception is thrown). +""" include("fixLines.jl") @@ -421,7 +422,7 @@ end end Return `result` for the first matching `pattern`. If there are no matches, throw `MatchFailure`. - """ +""" macro match(value, cases) res = handle_match_cases(value, cases ; mathcontinue = false) replaceLineNum(res, @__FILE__, __source__) diff --git a/src/utilityMacros.jl b/src/utilityMacros.jl new file mode 100644 index 0000000..7ea7e23 --- /dev/null +++ b/src/utilityMacros.jl @@ -0,0 +1,35 @@ +import Setfield +""" + Helper function for the assignmacro, see @assign + We have one case where we assign a immutable structure to an immutable structure or something to a primitive variable. + If it is not a primitive we assign to a subcomponent of that structure. We then clone the structure with that particular field changed. +""" +function assignFunc(expr) + res = if @capture(expr, lhs_._= rhs_) + if !isprimitivetype(typeof(lhs)) + Setfield.setmacro(identity, expr, overwrite=true) + else + quote + $(esc(expr)) + end + end + else + quote + $(esc(expr)) + end + end + return res +end + +""" + This macro reimplements the MetaModelica assignment semantics using + setfield to assign to variables. + For assignments using primitives, the regular Julia assignment is generated. + For cases where deeply nested immutable structures are manipulated we use setfield +E.g.: + a.b.c = 5 + Where a is a nested immutable struct +""" +macro assign(expr) + assignFunc(expr) +end diff --git a/test/runtimeTest.jl b/test/runtimeTest.jl index 1ee6cee..95658bc 100644 --- a/test/runtimeTest.jl +++ b/test/runtimeTest.jl @@ -198,5 +198,24 @@ end @test "AB" == "A" + "B" end +@testset "Testing MetaModelica assignment semantics" begin + struct A + a + end + struct B + b + end + struct C + c + end + nested = A(B(C(1))) + @assign nested.a.b.c = 4 + @test nested.a.b.c == 4 + @assign a = 4 + @test a == 4 + @assign simple = 4 + @test simple == 4 +end + end #=End runtime tests=# end #=End module=#