diff --git a/Compiler/BackEnd/BackendDAECreate.mo b/Compiler/BackEnd/BackendDAECreate.mo index 20fb5d1fb0b..7ec35a6b821 100644 --- a/Compiler/BackEnd/BackendDAECreate.mo +++ b/Compiler/BackEnd/BackendDAECreate.mo @@ -434,7 +434,7 @@ algorithm // when equations case DAE.WHEN_EQUATION(condition = e, equations = dae_elts) algorithm - if intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33) and Types.isClockOrSubTypeClock(Expression.typeof(e)) then + if Config.synchronousFeaturesAllowed() and Types.isClockOrSubTypeClock(Expression.typeof(e)) then (outEqns, outVars, eq_attrs) := createWhenClock(whenClkCnt, e, outEqns, outVars); whenClkCnt := whenClkCnt + 1; diff --git a/Compiler/FrontEnd/Ceval.mo b/Compiler/FrontEnd/Ceval.mo index 7035b75e47c..5b37ae1483d 100644 --- a/Compiler/FrontEnd/Ceval.mo +++ b/Compiler/FrontEnd/Ceval.mo @@ -1115,7 +1115,7 @@ algorithm /* case "Clock" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then cevalBuiltinClock; */ // MetaModelica type conversions case "intString" guard Config.acceptMetaModelicaGrammar() then cevalIntString; diff --git a/Compiler/FrontEnd/ClassInf.mo b/Compiler/FrontEnd/ClassInf.mo index 04571d35a6b..9492b57fa85 100644 --- a/Compiler/FrontEnd/ClassInf.mo +++ b/Compiler/FrontEnd/ClassInf.mo @@ -49,6 +49,7 @@ encapsulated package ClassInf public import SCode; public import Absyn; +protected import Config; protected import Debug; protected import Error; protected import Flags; @@ -432,7 +433,7 @@ algorithm // BTH case (SCode.R_PREDEFINED_CLOCK(),p) equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then TYPE_CLOCK(p); case (SCode.R_PREDEFINED_ENUMERATION(),p) then TYPE_ENUM(p); /* Meta Modelica extensions */ diff --git a/Compiler/FrontEnd/Inst.mo b/Compiler/FrontEnd/Inst.mo index 63fa31c58a1..3b67a30eb5c 100644 --- a/Compiler/FrontEnd/Inst.mo +++ b/Compiler/FrontEnd/Inst.mo @@ -1189,7 +1189,7 @@ algorithm // BTH case "Clock" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then DAE.T_CLOCK_DEFAULT; end match; end getBasicTypeType; @@ -1206,7 +1206,7 @@ algorithm // BTH case "Clock" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then getClockAttributeType; end match; end getBasicTypeAttrTyper; diff --git a/Compiler/FrontEnd/InstStateMachineUtil.mo b/Compiler/FrontEnd/InstStateMachineUtil.mo index ae59fcd5ba8..2fb8a5c5ad9 100644 --- a/Compiler/FrontEnd/InstStateMachineUtil.mo +++ b/Compiler/FrontEnd/InstStateMachineUtil.mo @@ -38,6 +38,7 @@ encapsulated package InstStateMachineUtil public import DAE; +protected import Config; protected import Flags; protected import List; protected import ComponentReference; @@ -949,7 +950,7 @@ algorithm case SCode.EQUATION(eEquation = SCode.EQ_NORETCALL(exp = Absyn.CALL(function_ = Absyn.CREF_IDENT(name = name)))) then (name == "transition" or name == "initialState") and - intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + Config.synchronousFeaturesAllowed(); else false; end match; @@ -967,7 +968,7 @@ algorithm case DAE.NORETCALL(exp = DAE.CALL(path = Absyn.IDENT(name))) then (name == "transition" or name == "initialState") and - intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + Config.synchronousFeaturesAllowed(); else false; end match; diff --git a/Compiler/FrontEnd/InstUtil.mo b/Compiler/FrontEnd/InstUtil.mo index 6fea47d26e7..075bf3bc933 100644 --- a/Compiler/FrontEnd/InstUtil.mo +++ b/Compiler/FrontEnd/InstUtil.mo @@ -643,7 +643,7 @@ algorithm // BTH case (_, _, SCode.CLASS(name = "Clock")) equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then (); // anything else, check for equality! @@ -665,7 +665,7 @@ algorithm case("String") then true; case("Boolean") then true; // BTH - case("Clock") then intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + case("Clock") then Config.synchronousFeaturesAllowed(); else false; end match; end isBuiltInClass; @@ -857,7 +857,7 @@ algorithm //BTH same as above but extended with Clock type if Flags.SYNCHRONOUS_FEATURES == true case (_, _, _, r, {SCode.EXTENDS(baseClassPath=Absyn.IDENT(id))}) equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); true = listMember(r, {SCode.R_TYPE(), SCode.R_CONNECTOR(false), SCode.R_CONNECTOR(true)}); true = listMember(id, {"Real", "Integer", "Boolean", "String", "Clock"}); then (); @@ -896,12 +896,12 @@ protected list rstLst; algorithm // BTH add Clock type to both lists if Flags.SYNCHRONOUS_FEATURES == true - strLst := if intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33) + strLst := if Config.synchronousFeaturesAllowed() then {"Real", "Integer", "String", "Boolean", "Clock"} else {"Real", "Integer", "String", "Boolean"}; b1 := listMember(childName, strLst); - rstLst := if intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33) + rstLst := if Config.synchronousFeaturesAllowed() then {SCode.R_TYPE(), SCode.R_PREDEFINED_INTEGER(), SCode.R_PREDEFINED_REAL(), SCode.R_PREDEFINED_STRING(), SCode.R_PREDEFINED_BOOLEAN(), SCode.R_PREDEFINED_CLOCK()} else {SCode.R_TYPE(), SCode.R_PREDEFINED_INTEGER(), SCode.R_PREDEFINED_REAL(), SCode.R_PREDEFINED_STRING(), SCode.R_PREDEFINED_BOOLEAN()}; b2 := listMember(childRestriction, rstLst); @@ -3304,7 +3304,7 @@ algorithm // BTH case (cache, _, _, _, cl as SCode.CLASS(name = "Clock"), _, _) equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then (cache,{},cl,DAE.NOMOD()); case (cache, _, _, _, cl as SCode.CLASS(restriction = SCode.R_RECORD(_), @@ -7378,7 +7378,7 @@ algorithm // you cannot redeclare a basic type, only the properties and the binding, i.e. // redeclare constant Boolean standardOrderComponents = true case DAE.REDECL(element = SCode.COMPONENT(typeSpec=Absyn.TPATH(path=path))) equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); name = Absyn.pathFirstIdent(path); // BTH @@ -7386,7 +7386,7 @@ algorithm then true; case DAE.REDECL(element = SCode.COMPONENT(typeSpec=Absyn.TPATH(path=path))) equation - false = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + false = Config.synchronousFeaturesAllowed(); name = Absyn.pathFirstIdent(path); // BTH diff --git a/Compiler/FrontEnd/NFSCodeLookup.mo b/Compiler/FrontEnd/NFSCodeLookup.mo index e49158e9579..fa0c32898d3 100644 --- a/Compiler/FrontEnd/NFSCodeLookup.mo +++ b/Compiler/FrontEnd/NFSCodeLookup.mo @@ -45,6 +45,7 @@ public import NFInstPrefix; public import SCode; public import NFSCodeEnv; +protected import Config; protected import Debug; protected import NFEnvExtends; protected import Flags; @@ -1266,7 +1267,7 @@ algorithm case "ExternalObject" then BUILTIN_EXTERNALOBJECT; case "Clock" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then BUILTIN_CLOCK; case "$RealType" then BUILTIN_REALTYPE_ITEM; case "$IntegerType" then BUILTIN_INTEGERTYPE_ITEM; diff --git a/Compiler/FrontEnd/Static.mo b/Compiler/FrontEnd/Static.mo index c10747a59d8..edb9712ce1b 100644 --- a/Compiler/FrontEnd/Static.mo +++ b/Compiler/FrontEnd/Static.mo @@ -6520,43 +6520,43 @@ algorithm case "DynamicSelect" then elabBuiltinDynamicSelect; case "Clock" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinClock; case "hold" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinHold; case "shiftSample" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinShiftSample; case "backSample" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinBackSample; case "noClock" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinNoClock; case "transition" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinTransition; case "initialState" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinInitialState; case "activeState" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinActiveState; case "ticksInState" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinTicksInState; case "timeInState" equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then elabBuiltinTimeInState; case "sourceInfo" equation diff --git a/Compiler/NFFrontEnd/NFBuiltin.mo b/Compiler/NFFrontEnd/NFBuiltin.mo index 460ee60759a..58419fc5266 100644 --- a/Compiler/NFFrontEnd/NFBuiltin.mo +++ b/Compiler/NFFrontEnd/NFBuiltin.mo @@ -105,6 +105,11 @@ encapsulated package Elements SCode.PARTS({}, {}, {}, {}, {}, {}, {}, NONE()), SCode.noComment, Absyn.dummyInfo); + constant SCode.Element CLOCK = SCode.CLASS("Clock", + SCode.defaultPrefixes, SCode.NOT_ENCAPSULATED(), SCode.NOT_PARTIAL(), SCode.R_PREDEFINED_CLOCK(), + SCode.PARTS({}, {}, {}, {}, {}, {}, {}, NONE()), + SCode.noComment, Absyn.dummyInfo) "the Clock type"; + end Elements; // An empty InstNode cache for the builtin types. This should really be an empty @@ -315,6 +320,37 @@ constant Expression ASSERTIONLEVEL_ERROR = Expression.ENUM_LITERAL( constant Expression ASSERTIONLEVEL_WARNING = Expression.ENUM_LITERAL( ASSERTIONLEVEL_TYPE, "error", 2); +// Lookup tree for Clock. Generated by makeBuiltinLookupTree. +constant LookupTree.Tree CLOCK_LOOKUP_TREE = LookupTree.Tree.NODE( + key = "quantity", value = LookupTree.Entry.COMPONENT(index = 1), height = 2, + left = LookupTree.Tree.LEAF( + key = "fixed", value = LookupTree.Entry.COMPONENT(index = 3)), + right = LookupTree.Tree.LEAF( + key = "start", value = LookupTree.Entry.COMPONENT(index = 2))); + +constant ClassTree CLOCK_CLASS_TREE = ClassTree.FLAT_TREE( + CLOCK_LOOKUP_TREE, + listArrayLiteral({}), + listArrayLiteral({ + InstNode.COMPONENT_NODE("quantity", Visibility.PUBLIC, + Pointer.createImmutable(Component.TYPE_ATTRIBUTE(Type.STRING(), Modifier.NOMOD())), InstNode.EMPTY_NODE()), + InstNode.COMPONENT_NODE("start", Visibility.PUBLIC, + Pointer.createImmutable(Component.TYPE_ATTRIBUTE(Type.CLOCK(), Modifier.NOMOD())), InstNode.EMPTY_NODE()), + InstNode.COMPONENT_NODE("fixed", Visibility.PUBLIC, + Pointer.createImmutable(Component.TYPE_ATTRIBUTE(Type.CLOCK(), Modifier.NOMOD())), InstNode.EMPTY_NODE()) + }), + listArray({}), // TODO: #4895: This should be listArrayLiteral too, but causes compilation issues. + DuplicateTree.EMPTY()); + +constant InstNode CLOCK_NODE = InstNode.CLASS_NODE("Clock", + Elements.CLOCK, Visibility.PUBLIC, + Pointer.createImmutable( + Class.PARTIAL_BUILTIN(Type.CLOCK(), CLOCK_CLASS_TREE, Modifier.NOMOD(), Restriction.CLOCK())), + EMPTY_NODE_CACHE, InstNode.EMPTY_NODE(), InstNodeType.BUILTIN_CLASS()); + +constant ComponentRef CLOCK_CREF = + ComponentRef.CREF(CLOCK_NODE, {}, Type.CLOCK(), Origin.CREF, ComponentRef.EMPTY()); + constant InstNode TIME = InstNode.COMPONENT_NODE("time", Visibility.PUBLIC, diff --git a/Compiler/NFFrontEnd/NFBuiltinCall.mo b/Compiler/NFFrontEnd/NFBuiltinCall.mo index acff7618f91..7bb7c7c5b32 100644 --- a/Compiler/NFFrontEnd/NFBuiltinCall.mo +++ b/Compiler/NFFrontEnd/NFBuiltinCall.mo @@ -40,6 +40,7 @@ encapsulated package NFBuiltinCall import Type = NFType; protected + import Config; import Ceval = NFCeval; import ComponentRef = NFComponentRef; import Dimension = NFDimension; @@ -132,6 +133,18 @@ public case "transpose" then typeTransposeCall(call, origin, info); case "vector" then typeVectorCall(call, origin, info); case "zeros" then typeZerosOnesCall("zeros", call, origin, info); + case "Clock" guard Config.synchronousFeaturesAllowed() then typeClockCall(call, origin, info); + /* + case "hold" guard Config.synchronousFeaturesAllowed() then typeHoldCall(call, origin, info); + case "shiftSample" guard Config.synchronousFeaturesAllowed() then typeShiftSampleCall(call, origin, info); + case "backSample" guard Config.synchronousFeaturesAllowed() then typeBackSampleCall(call, origin, info); + case "noClock" guard Config.synchronousFeaturesAllowed() then typeNoClockCall(call, origin, info); + case "transition" guard Config.synchronousFeaturesAllowed() then typeTransitionCall(call, origin, info); + case "initialState" guard Config.synchronousFeaturesAllowed() then typeInitialStateCall(call, origin, info); + case "activeState" guard Config.synchronousFeaturesAllowed() then typeActiveStateCall(call, origin, info); + case "ticksInState" guard Config.synchronousFeaturesAllowed() then typeTicksInStateCall(call, origin, info); + case "timeInState" guard Config.synchronousFeaturesAllowed() then typeTimeInStateCall(call, origin, info); + */ else algorithm Error.assertion(false, getInstanceName() + " got unhandled builtin function: " + Call.toString(call), sourceInfo()); @@ -1600,5 +1613,91 @@ protected result := Expression.STRING(Absyn.pathString(InstNode.scopePath(scope, includeRoot = true))); end typeGetInstanceName; + function typeClockCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type outType; + output Variability var; + protected + Type arg_ty; + list args; + list named_args; + Call ty_call; + Expression e, e1, e2; + Type t, t1, t2; + Variability v, v1, v2; + algorithm + ty_call as Call.ARG_TYPED_CALL(_, args, named_args) := Call.typeNormalCall(call, origin, info); + (callExp, outType, var) := match(args, named_args) + // Clock() - inferred clock + case ({}, {}) + then (Expression.CLKCONST(Expression.ClockKind.INFERRED_CLOCK()), Type.CLOCK(), Variability.PARAMETER); + // Clock(intervalCounter) - integer clock + case ({(e, Type.INTEGER(), v)}, {}) + then (Expression.CLKCONST(Expression.INTEGER_CLOCK(e, Expression.INTEGER(1))), Type.CLOCK(), Variability.PARAMETER); + // Clock(intervalCounter, resolution) - integer clock + case ({(e, Type.INTEGER(), v), (e1, Type.REAL(), v1)}, {}) + algorithm + e2 := Ceval.evalExp(e1); + Error.assertionOrAddSourceMessage(Expression.integerValue(e2) >= 1, + Error.WRONG_VALUE_OF_ARG, {"Clock", "resolution", Expression.toString(e2), ">= 1"}, info); + then + (Expression.CLKCONST(Expression.INTEGER_CLOCK(e, e2)), Type.CLOCK(), Variability.PARAMETER); + // Clock(intervalCounter, resolution=expression) - integer clock + case ({(e, Type.INTEGER(), v)}, {("resolution", e1, Type.REAL(), v1)}) + algorithm + e2 := Ceval.evalExp(e1); + Error.assertionOrAddSourceMessage(Expression.integerValue(e2) >= 1, + Error.WRONG_VALUE_OF_ARG, {"Clock", "resolution", Expression.toString(e2), ">= 1"}, info); + then + (Expression.CLKCONST(Expression.INTEGER_CLOCK(e, e2)), Type.CLOCK(), Variability.PARAMETER); + // Clock(interval) - real clock + case ({(e, Type.REAL(), v)}, {}) + then + (Expression.CLKCONST(Expression.REAL_CLOCK(e)), Type.CLOCK(), Variability.PARAMETER); + // Clock(condition) - boolean clock + case ({(e, Type.BOOLEAN(), v)}, {}) + then + (Expression.CLKCONST(Expression.BOOLEAN_CLOCK(e, Expression.REAL(0.0))), Type.CLOCK(), Variability.PARAMETER); + // Clock(condition, startInterval) - boolean clock + case ({(e, Type.BOOLEAN(), v), (e1, Type.REAL(), v1)}, {}) + algorithm + e2 := Ceval.evalExp(e1); + Error.assertionOrAddSourceMessage(Expression.realValue(e2) > 0.0, + Error.WRONG_VALUE_OF_ARG, {"Clock", "startInterval", Expression.toString(e2), "> 0.0"}, info); + then + (Expression.CLKCONST(Expression.BOOLEAN_CLOCK(e, e2)), Type.CLOCK(), Variability.PARAMETER); + // Clock(condition, startInterval=expression) - boolean clock + case ({(e, Type.BOOLEAN(), v)}, {("startInterval", e1, Type.REAL(), v1)}) + algorithm + e2 := Ceval.evalExp(e1); + Error.assertionOrAddSourceMessage(Expression.realValue(e2) > 0.0, + Error.WRONG_VALUE_OF_ARG, {"Clock", "startInterval", Expression.toString(e2), "> 0.0"}, info); + then + (Expression.CLKCONST(Expression.BOOLEAN_CLOCK(e, e2)), Type.CLOCK(), Variability.PARAMETER); + // Clock(c, solverMethod) - solver clock + case ({(e, Type.CLOCK(), v), (e1, Type.STRING(), v1)}, {}) + algorithm + e2 := Ceval.evalExp(e1); + then + (Expression.CLKCONST(Expression.SOLVER_CLOCK(e, e2)), Type.CLOCK(), Variability.PARAMETER); + + // Clock(c, solverMethod=string) - solver clock + case ({(e, Type.CLOCK(), v)}, {("solverMethod", e1, Type.STRING(), v1)}) + algorithm + e2 := Ceval.evalExp(e1); + then + (Expression.CLKCONST(Expression.SOLVER_CLOCK(e, e2)), Type.CLOCK(), Variability.PARAMETER); + + else + algorithm + Error.addSourceMessage(Error.WRONG_TYPE_OR_NO_OF_ARGS, {Call.toString(call), ""}, info); + then + fail(); + end match; + end typeClockCall; + annotation(__OpenModelica_Interface="frontend"); end NFBuiltinCall; diff --git a/Compiler/NFFrontEnd/NFBuiltinFuncs.mo b/Compiler/NFFrontEnd/NFBuiltinFuncs.mo index e84d550997d..8802ae49e6d 100644 --- a/Compiler/NFFrontEnd/NFBuiltinFuncs.mo +++ b/Compiler/NFFrontEnd/NFBuiltinFuncs.mo @@ -282,5 +282,92 @@ constant Function SMOOTH = Function.FUNCTION(Path.IDENT("smooth"), Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, Pointer.createImmutable(true), Pointer.createImmutable(0)); + +constant Component CLOCK_COMPONENT = Component.TYPED_COMPONENT(NFInstNode.EMPTY_NODE(), + Type.CLOCK(), NFBinding.EMPTY_BINDING, NFBinding.EMPTY_BINDING, NFComponent.DEFAULT_ATTR, NONE(), Absyn.dummyInfo); + +constant InstNode CLOCK_PARAM = InstNode.COMPONENT_NODE("s", + Visibility.PUBLIC, + Pointer.createImmutable(CLOCK_COMPONENT), InstNode.EMPTY_NODE()); + +constant InstNode CLOCK_DUMMY_NODE = NFInstNode.CLASS_NODE("Clock", + DUMMY_ELEMENT, Visibility.PUBLIC, Pointer.createImmutable(Class.NOT_INSTANTIATED()), + EMPTY_NODE_CACHE, InstNode.EMPTY_NODE(), InstNodeType.NORMAL_CLASS()); + +// Clock() - inferred clock +constant Function CLOCK_INFERED = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {}, {CLOCK_PARAM}, {}, {}, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + +// Clock(intervalCounter) - clock with Integer interval +constant Function CLOCK_INT = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {INT_PARAM}, {CLOCK_PARAM}, {}, { + Slot.SLOT("intervalCounter", SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED) + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + +// Clock(intervalCounter, resolution) - clock with Integer interval +constant Function CLOCK_INT_RESOLUTION = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {INT_PARAM, INT_PARAM}, {CLOCK_PARAM}, {}, { + Slot.SLOT("intervalCounter", SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), + Slot.SLOT("resolution", SlotType.NAMED, SOME(Expression.INTEGER(1)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + +// Clock(interval) - clock with Real interval +constant Function CLOCK_REAL = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {REAL_PARAM}, {CLOCK_PARAM}, {}, { + Slot.SLOT("interval", SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED) + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + +// Clock(condition) - Boolean clock, triggered by zero-crossing events +constant Function CLOCK_BOOL = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {BOOL_PARAM}, {CLOCK_PARAM}, {}, { + Slot.SLOT("condition", SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED) + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + +// Clock(condition, startInterval) - Boolean clock, triggered by zero-crossing events +constant Function CLOCK_BOOL_INTERVAL = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {BOOL_PARAM, REAL_PARAM}, {CLOCK_PARAM}, {}, { + Slot.SLOT("condition", SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), + Slot.SLOT("startInterval", SlotType.NAMED, SOME(Expression.REAL(0.0)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + +// Clock(c, solverMethod) - Solver clock +constant Function CLOCK_SOLVER = Function.FUNCTION(Path.IDENT("Clock"), + CLOCK_DUMMY_NODE, {CLOCK_PARAM, STRING_PARAM}, {CLOCK_PARAM}, {}, { + Slot.SLOT("condition", SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), + Slot.SLOT("solverMethod", SlotType.NAMED, NONE(), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, + Pointer.createImmutable(true), Pointer.createImmutable(0)); + + +constant InstNode CLOCK_NODE = InstNode.CLASS_NODE("Clock", + DUMMY_ELEMENT, Visibility.PUBLIC, + Pointer.createImmutable(Class.PARTIAL_BUILTIN(Type.CLOCK(), ClassTree.EMPTY_TREE(), + Modifier.NOMOD(), Restriction.TYPE())), + listArrayLiteral({ + NFInstNode.CachedData.FUNCTION({ + CLOCK_INFERED, + CLOCK_INT, + CLOCK_INT_RESOLUTION, + CLOCK_REAL, + CLOCK_BOOL, + CLOCK_BOOL_INTERVAL, + CLOCK_SOLVER + }, + true, true), + NFInstNode.CachedData.NO_CACHE(), + NFInstNode.CachedData.NO_CACHE()} + ), + InstNode.EMPTY_NODE(), InstNodeType.BUILTIN_CLASS()); + +constant ComponentRef CLOCK_CREF = + ComponentRef.CREF(CLOCK_NODE, {}, Type.INTEGER(), Origin.CREF, ComponentRef.EMPTY()); + + annotation(__OpenModelica_Interface="frontend"); end NFBuiltinFuncs; diff --git a/Compiler/NFFrontEnd/NFCall.mo b/Compiler/NFFrontEnd/NFCall.mo index 79f389d9c4a..835971a30f5 100644 --- a/Compiler/NFFrontEnd/NFCall.mo +++ b/Compiler/NFFrontEnd/NFCall.mo @@ -209,7 +209,11 @@ uniontype Call if isRecordConstructor(call) then outExp := toRecordExpression(call, ty); else - outExp := Expression.CALL(call); + if Function.hasUnboxArgs(InstNode.definition(ComponentRef.node(cref))) then + outExp := Expression.CALL(Call.unboxArgs(call)); + else + outExp := Expression.CALL(call); + end if; outExp := Inline.inlineCallExp(outExp); end if; end if; @@ -1197,6 +1201,8 @@ protected then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); case Absyn.IDENT("product") then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); + case Absyn.IDENT("previous") + then Expression.typeOf(Expression.unbox(listHead(args))); else algorithm Error.assertion(false, getInstanceName() + ": unhandled case for " + diff --git a/Compiler/NFFrontEnd/NFExpression.mo b/Compiler/NFFrontEnd/NFExpression.mo index 436bbbc4f12..bcc5d0767b2 100644 --- a/Compiler/NFFrontEnd/NFExpression.mo +++ b/Compiler/NFFrontEnd/NFExpression.mo @@ -64,6 +64,60 @@ public import NFTyping.ExpOrigin; import ExpressionSimplify; + uniontype ClockKind + record INFERRED_CLOCK + end INFERRED_CLOCK; + + record INTEGER_CLOCK + Expression intervalCounter; + Expression resolution " integer type >= 1 "; + end INTEGER_CLOCK; + + record REAL_CLOCK + Expression interval; + end REAL_CLOCK; + + record BOOLEAN_CLOCK + Expression condition; + Expression startInterval " real type >= 0.0 "; + end BOOLEAN_CLOCK; + + record SOLVER_CLOCK + Expression c; + Expression solverMethod " string type "; + end SOLVER_CLOCK; + + function toDAE + input ClockKind ick; + output DAE.ClockKind ock; + algorithm + ock := match ick + local + Expression i, ic, r, c, si, sm; + case (INFERRED_CLOCK()) then DAE.INFERRED_CLOCK(); + case (INTEGER_CLOCK(i, r)) then DAE.INTEGER_CLOCK(Expression.toDAE(i), Expression.toDAE(r)); + case (REAL_CLOCK(i)) then DAE.REAL_CLOCK(Expression.toDAE(i)); + case (BOOLEAN_CLOCK(c, si)) then DAE.BOOLEAN_CLOCK(Expression.toDAE(c), Expression.toDAE(si)); + case (SOLVER_CLOCK(c, sm)) then DAE.SOLVER_CLOCK(Expression.toDAE(c), Expression.toDAE(sm)); + end match; + end toDAE; + + function toString + input ClockKind ick; + output String ock; + algorithm + ock := match ick + local + Expression i, ic, r, c, si, sm; + case (INFERRED_CLOCK()) then "INFERRED_CLOCK()"; + case (INTEGER_CLOCK(i, r)) then "INTEGER_CLOCK(" + Expression.toString(i) + ", " + Expression.toString(r) + ")"; + case (REAL_CLOCK(i)) then "REAL_CLOCK(" + Expression.toString(i) + ")"; + case (BOOLEAN_CLOCK(c, si)) then "BOOLEAN_CLOCK(" + Expression.toString(c) + ", " + Expression.toString(si) + ")"; + case (SOLVER_CLOCK(c, sm)) then "SOLVER_CLOCK(" + Expression.toString(c) + ", " + Expression.toString(sm) + ")"; + end match; + end toString; + end ClockKind; + record INTEGER Integer value; end INTEGER; @@ -203,6 +257,10 @@ public Type ty; end EMPTY; + record CLKCONST "Clock constructors" + ClockKind clk "Clock kinds"; + end CLKCONST; + function isArray input Expression exp; output Boolean isArray; @@ -679,6 +737,13 @@ public output Expression exp = INTEGER(value); end makeInteger; + function stringValue + input Expression exp; + output String value; + algorithm + STRING(value=value) := exp; + end stringValue; + function makeIntegerArray input list values; output Expression exp; @@ -1153,6 +1218,7 @@ public output String str; protected Type t; + ClockKind clk; algorithm str := match exp case INTEGER() then intString(exp.value); @@ -1163,6 +1229,8 @@ public case ENUM_LITERAL(ty = t as Type.ENUMERATION()) then Absyn.pathString(t.typePath) + "." + exp.name; + case CLKCONST(clk) then "CLKCONST(" + ClockKind.toString(clk) + ")"; + case CREF() then ComponentRef.toString(exp.cref); case TYPENAME() then Type.typenameString(Type.arrayElementType(exp.ty)); case ARRAY() then "{" + stringDelimitList(list(toString(e) for e in exp.elements), ", ") + "}"; @@ -1207,6 +1275,7 @@ public case IF() then "if " + toString(exp.condition) + " then " + toString(exp.trueBranch) + " else " + toString(exp.falseBranch); case UNBOX() then "UNBOX(" + toString(exp.exp) + ")"; + case BOX() then "BOX(" + toString(exp.exp) + ")"; case CAST() then "CAST(" + Type.toString(exp.ty) + ", " + toString(exp.exp) + ")"; case SUBSCRIPTED_EXP() then toString(exp.exp) + Subscript.toStringList(exp.subscripts); case TUPLE_ELEMENT() then toString(exp.tupleExp) + "[" + intString(exp.index) + "]"; @@ -1280,6 +1349,7 @@ public Boolean swap; DAE.Exp dae1, dae2; list names; + ClockKind clk; case INTEGER() then DAE.ICONST(exp.value); case REAL() then DAE.RCONST(exp.value); @@ -1288,6 +1358,9 @@ public case ENUM_LITERAL(ty = ty as Type.ENUMERATION()) then DAE.ENUM_LITERAL(Absyn.suffixPath(ty.typePath, exp.name), exp.index); + case CLKCONST(clk) + then DAE.CLKCONST(ClockKind.toDAE(clk)); + case CREF() then DAE.CREF(ComponentRef.toDAE(exp.cref), Type.toDAE(exp.ty)); @@ -3330,6 +3403,7 @@ public case STRING() then Variability.CONSTANT; case BOOLEAN() then Variability.CONSTANT; case ENUM_LITERAL() then Variability.CONSTANT; + case CLKCONST(_) then Variability.DISCRETE; case CREF() then ComponentRef.variability(exp.cref); case TYPENAME() then Variability.CONSTANT; case ARRAY() then variabilityList(exp.elements); diff --git a/Compiler/NFFrontEnd/NFFunction.mo b/Compiler/NFFrontEnd/NFFunction.mo index 3e0cf42a9a0..cf872831b7f 100644 --- a/Compiler/NFFrontEnd/NFFunction.mo +++ b/Compiler/NFFrontEnd/NFFunction.mo @@ -1370,6 +1370,12 @@ uniontype Function output list body = getBody2(fn.node); end getBody; + function hasUnboxArgs + input SCode.Element def; + output Boolean res = + SCode.hasBooleanNamedAnnotationInClass(def, "__OpenModelica_UnboxArguments"); + end hasUnboxArgs; + protected function collectParams "Sorts all the function parameters as inputs, outputs and locals." @@ -1525,12 +1531,6 @@ protected SCode.hasBooleanNamedAnnotationInClass(def, "__ModelicaAssociation_Impure"); end hasImpure; - function hasUnboxArgs - input SCode.Element def; - output Boolean res = - SCode.hasBooleanNamedAnnotationInClass(def, "__OpenModelica_UnboxArguments"); - end hasUnboxArgs; - function getBuiltin input SCode.Element def; output DAE.FunctionBuiltin builtin = if SCode.isBuiltinElement(def) then diff --git a/Compiler/NFFrontEnd/NFLookup.mo b/Compiler/NFFrontEnd/NFLookup.mo index b71ad894586..643bdd8da94 100644 --- a/Compiler/NFFrontEnd/NFLookup.mo +++ b/Compiler/NFFrontEnd/NFLookup.mo @@ -54,6 +54,7 @@ import NFInstNode.CachedData; import NFComponent.Component; import Subscript = NFSubscript; import ComplexType = NFComplexType; +import Config; public type MatchType = enumeration(FOUND, NOT_FOUND, PARTIAL); @@ -254,8 +255,7 @@ algorithm (foundCref, foundScope, state) := match cref case Absyn.ComponentRef.CREF_IDENT() algorithm - (_, foundCref, foundScope, state) := - lookupSimpleCref(cref.name, cref.subscripts, scope); + (_, foundCref, foundScope, state) := lookupSimpleCref(cref.name, cref.subscripts, scope); then (foundCref, foundScope, state); @@ -647,6 +647,7 @@ algorithm case "Integer" then NFBuiltin.INTEGER_NODE; case "Boolean" then NFBuiltin.BOOLEAN_NODE; case "String" then NFBuiltin.STRING_NODE; + case "Clock" then NFBuiltin.CLOCK_NODE; case "polymorphic" then NFBuiltin.POLYMORPHIC_NODE; end match; end lookupSimpleBuiltinName; @@ -658,6 +659,7 @@ function lookupSimpleBuiltinCref output ComponentRef cref; output LookupState state; algorithm + (node, cref, state) := match name case "time" then (NFBuiltin.TIME, NFBuiltin.TIME_CREF, LookupState.PREDEF_COMP()); @@ -667,6 +669,8 @@ algorithm then (NFBuiltinFuncs.INTEGER_NODE, NFBuiltinFuncs.INTEGER_CREF, LookupState.FUNC()); case "String" then (NFBuiltinFuncs.STRING_NODE, NFBuiltinFuncs.STRING_CREF, LookupState.FUNC()); + case "Clock" guard Config.synchronousFeaturesAllowed() + then (NFBuiltinFuncs.CLOCK_NODE, NFBuiltinFuncs.CLOCK_CREF, LookupState.FUNC()); end match; if not listEmpty(subs) then diff --git a/Compiler/NFFrontEnd/NFRestriction.mo b/Compiler/NFFrontEnd/NFRestriction.mo index 7a7355c30b7..d414900eec3 100644 --- a/Compiler/NFFrontEnd/NFRestriction.mo +++ b/Compiler/NFFrontEnd/NFRestriction.mo @@ -55,6 +55,7 @@ public record RECORD_CONSTRUCTOR end RECORD_CONSTRUCTOR; record TYPE end TYPE; + record CLOCK end CLOCK; record UNKNOWN end UNKNOWN; function fromSCode @@ -70,6 +71,7 @@ public case SCode.Restriction.R_OPERATOR() then OPERATOR(); case SCode.Restriction.R_RECORD() then RECORD(sres.isOperator); case SCode.Restriction.R_TYPE() then TYPE(); + case SCode.Restriction.R_PREDEFINED_CLOCK() then CLOCK(); else MODEL(); end match; end fromSCode; @@ -89,6 +91,7 @@ public case OPERATOR() then ClassInf.State.FUNCTION(path, false); case RECORD() then ClassInf.State.RECORD(path); case TYPE() then ClassInf.State.TYPE(path); + case CLOCK() then ClassInf.State.TYPE_CLOCK(path); else ClassInf.State.UNKNOWN(path); end match; end toDAE; @@ -163,6 +166,16 @@ public end match; end isType; + function isClock + input Restriction res; + output Boolean isClock; + algorithm + isClock := match res + case CLOCK() then true; + else false; + end match; + end isClock; + function toString input Restriction res; output String str; @@ -176,6 +189,7 @@ public case OPERATOR() then "operator"; case RECORD() then "record"; case TYPE() then "type"; + case CLOCK() then "clock"; else "unknown"; end match; end toString; diff --git a/Compiler/NFFrontEnd/NFSimplifyExp.mo b/Compiler/NFFrontEnd/NFSimplifyExp.mo index 2655a92b463..bb9ef2cc4cd 100644 --- a/Compiler/NFFrontEnd/NFSimplifyExp.mo +++ b/Compiler/NFFrontEnd/NFSimplifyExp.mo @@ -157,7 +157,12 @@ algorithm if is_pure and List.all(args, Expression.isLiteral) then callExp := Ceval.evalCall(call, EvalTarget.IGNORE_ERRORS()); else - callExp := simplifyBuiltinCall(Function.nameConsiderBuiltin(call.fn), args, call); + // do not expand builtin calls if we should not scalarize + if Flags.isSet(Flags.NF_SCALARIZE) then + callExp := simplifyBuiltinCall(Function.nameConsiderBuiltin(call.fn), args, call); + else + // nothing + end if; end if; elseif Flags.isSet(Flags.NF_EVAL_CONST_ARG_FUNCS) and is_pure and List.all(args, Expression.isLiteral) then callExp := simplifyCall2(call); diff --git a/Compiler/NFFrontEnd/NFTyping.mo b/Compiler/NFFrontEnd/NFTyping.mo index 6eb5af0fea2..0d2897ef441 100644 --- a/Compiler/NFFrontEnd/NFTyping.mo +++ b/Compiler/NFFrontEnd/NFTyping.mo @@ -2708,8 +2708,14 @@ algorithm if allowVector and Type.isVector(ty) then (_, _, mk) := TypeCheck.matchTypes(Type.arrayElementType(ty), Type.BOOLEAN(), condition); + if TypeCheck.isIncompatibleMatch(mk) then + (_, _, mk) := TypeCheck.matchTypes(Type.arrayElementType(ty), Type.CLOCK(), condition); + end if; else (_, _, mk) := TypeCheck.matchTypes(ty, Type.BOOLEAN(), condition); + if TypeCheck.isIncompatibleMatch(mk) then + (_, _, mk) := TypeCheck.matchTypes(ty, Type.CLOCK(), condition); + end if; end if; if TypeCheck.isIncompatibleMatch(mk) then diff --git a/Compiler/Script/Interactive.mo b/Compiler/Script/Interactive.mo index a9bab0a5715..847f369297c 100644 --- a/Compiler/Script/Interactive.mo +++ b/Compiler/Script/Interactive.mo @@ -8539,7 +8539,7 @@ algorithm // BTH case (Absyn.IDENT(name = "Clock"),_,_) equation - true = intGe(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33); + true = Config.synchronousFeaturesAllowed(); then (Absyn.CLASS("Clock",false,false,false,Absyn.R_PREDEFINED_CLOCK(), Absyn.dummyParts,Absyn.dummyInfo),Absyn.IDENT("Clock")); diff --git a/Compiler/Util/Config.mo b/Compiler/Util/Config.mo index 4b7a4901cc3..df26a9e3ce4 100644 --- a/Compiler/Util/Config.mo +++ b/Compiler/Util/Config.mo @@ -641,5 +641,15 @@ algorithm end match; end adaptiveHomotopy; +public function synchronousFeaturesAllowed +"@autor: adrpo + checks returns true if language standard is above or equal to Modelica 3.3" + output Boolean outRes; +protected + LanguageStandard std = getLanguageStandard(); +algorithm + outRes := intGe(languageStandardInt(std), 33); +end synchronousFeaturesAllowed; + annotation(__OpenModelica_Interface="util"); end Config;