Skip to content

Commit

Permalink
[NF] Fix external object calls.
Browse files Browse the repository at this point in the history
- Change external object calls so they call the constructor instead.
- Use an empty class tree for external object so the constructor or
  destructor can't be called explicitly.
- Fix error message for when a function can't be found to say function
  instead of variable.

Belonging to [master]:
  - OpenModelica/OMCompiler#2077
  - OpenModelica/OpenModelica-testsuite#806
  • Loading branch information
perost authored and OpenModelica-Hudson committed Dec 13, 2017
1 parent f37e029 commit d71fe29
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 51 deletions.
1 change: 1 addition & 0 deletions Compiler/NFFrontEnd/NFClass.mo
Expand Up @@ -395,6 +395,7 @@ uniontype Class
case INSTANCED_CLASS() algorithm cls.restriction := res; then ();
case INSTANCED_BUILTIN() algorithm cls.restriction := res; then ();
case EXPANDED_CLASS() algorithm cls.restriction := res; then ();
// PARTIAL_BUILTIN is only used for predefined builtin types and not needed here.
case DERIVED_CLASS() algorithm cls.restriction := res; then ();
end match;
end setRestriction;
Expand Down
2 changes: 2 additions & 0 deletions Compiler/NFFrontEnd/NFClassTree.mo
Expand Up @@ -153,6 +153,8 @@ public

constant ClassTree EMPTY = ClassTree.PARTIAL_TREE(LookupTree.EMPTY(),
listArray({}), listArray({}), listArray({}), listArray({}), DuplicateTree.EMPTY());
constant ClassTree EMPTY_FLAT = ClassTree.FLAT_TREE(LookupTree.EMPTY(),
listArray({}), listArray({}), listArray({}), DuplicateTree.EMPTY());

uniontype ClassTree
record PARTIAL_TREE
Expand Down
7 changes: 2 additions & 5 deletions Compiler/NFFrontEnd/NFFunction.mo
Expand Up @@ -207,7 +207,7 @@ uniontype Function
{Dump.printComponentRefStr(functionName)}, info);
end try;

(functionRef, found_scope) := Lookup.lookupCallableName(functionName, scope, info);
(functionRef, found_scope) := Lookup.lookupFunctionName(functionName, scope, info);
prefix := ComponentRef.fromNodeList(InstNode.scopeList(found_scope));
functionRef := ComponentRef.append(functionRef, prefix);
end lookupFunction;
Expand Down Expand Up @@ -258,11 +258,8 @@ uniontype Function
input SourceInfo info;
output Boolean specialBuiltin;
protected
SCode.Element def;
SCode.Element def = InstNode.definition(fnNode);
algorithm

def := InstNode.definition(fnNode);

(fnNode, specialBuiltin) := match def
local
SCode.ClassDef cdef;
Expand Down
30 changes: 12 additions & 18 deletions Compiler/NFFrontEnd/NFInst.mo
Expand Up @@ -560,10 +560,14 @@ algorithm
node := match InstNode.name(builtin_ext)
case "ExternalObject"
algorithm
(tree, eo_ty) := makeExternalObjectType(scope, node);
tree := ClassTree.expand(tree);
c := Class.PARTIAL_BUILTIN(Type.COMPLEX(node, eo_ty), tree, Modifier.NOMOD(),
Restriction.EXTERNAL_OBJECT());
// Construct the ComplexType for the external object.
eo_ty := makeExternalObjectType(scope, node);
// Construct the Class for the external object. We use an empty class
// tree here, since the constructor and destructor is embedded in the
// ComplexType instead. Using an empty class tree makes sure it's not
// possible to call the constructor or destructor explicitly.
c := Class.PARTIAL_BUILTIN(Type.COMPLEX(node, eo_ty), NFClassTree.EMPTY_FLAT,
Modifier.NOMOD(), Restriction.EXTERNAL_OBJECT());
node := InstNode.updateClass(c, node);
then
node;
Expand Down Expand Up @@ -592,14 +596,14 @@ end expandBuiltinExtends;
function makeExternalObjectType
"Constructs a ComplexType for an external object, and also checks that the
external object declaration is valid."
input output ClassTree tree;
input ClassTree tree;
input InstNode node;
output ComplexType ty;
output ComplexType ty;
protected
Absyn.Path base_path;
InstNode constructor = InstNode.EMPTY_NODE(), destructor = InstNode.EMPTY_NODE();
algorithm
(tree, ty) := match tree
ty := match tree
case ClassTree.PARTIAL_TREE()
algorithm
// An external object may not contain components.
Expand Down Expand Up @@ -664,18 +668,8 @@ algorithm
{InstNode.name(node), "destructor"}, InstNode.info(node));
fail();
end if;

// We don't need the ExternalObject extends anymore, get rid of it so we
// don't have to handle it later.
tree.exts := arrayCreate(0, InstNode.EMPTY_NODE());
// The component array will only contain a reference node to the
// ExternalObject extends, so get rid of it too.
tree.components := arrayCreate(0, InstNode.EMPTY_NODE());

// Construct the ComplexType for the external object.
ty := ComplexType.EXTERNAL_OBJECT(constructor, destructor);
then
(tree, ty);
ComplexType.EXTERNAL_OBJECT(constructor, destructor);

end match;
end makeExternalObjectType;
Expand Down
72 changes: 48 additions & 24 deletions Compiler/NFFrontEnd/NFLookup.mo
Expand Up @@ -52,6 +52,7 @@ import NFInstNode.NodeTree;
import NFInstNode.CachedData;
import NFComponent.Component;
import Subscript = NFSubscript;
import ComplexType = NFComplexType;

public
type MatchType = enumeration(FOUND, NOT_FOUND, PARTIAL);
Expand Down Expand Up @@ -97,7 +98,8 @@ protected
LookupState state;
InstNode node;
algorithm
(foundCref, foundScope, state) := lookupCref(cref, scope, info);
(foundCref, foundScope, state) := lookupCref(cref, scope, info,
Error.LOOKUP_VARIABLE_ERROR);
node := ComponentRef.node(foundCref);
state := fixTypenameState(node, state);
LookupState.assertComponent(state, node, cref, info);
Expand Down Expand Up @@ -137,26 +139,6 @@ algorithm
LookupState.assertComponent(state, ComponentRef.node(foundCref), cref, info);
end lookupLocalComponent;

function lookupCallableName
input Absyn.ComponentRef cref;
input InstNode scope "The scope to look in.";
input SourceInfo info;
output ComponentRef foundCref;
output InstNode foundScope;
protected
LookupState state;
InstNode node;
algorithm
(foundCref, foundScope, state) := lookupCref(cref, scope, info);
node := ComponentRef.node(foundCref);

//try
LookupState.assertFunction(state, node, cref, info);
//else
//end try;

end lookupCallableName;

function lookupFunctionName
input Absyn.ComponentRef cref;
input InstNode scope "The scope to look in.";
Expand All @@ -167,11 +149,52 @@ protected
LookupState state;
InstNode node;
algorithm
(foundCref, foundScope, state) := lookupCref(cref, scope, info);
(foundCref, foundScope, state) := lookupCref(cref, scope, info,
Error.LOOKUP_FUNCTION_ERROR);
node := ComponentRef.node(foundCref);
(foundCref, state) := fixExternalObjectCall(node, foundCref, state);
LookupState.assertFunction(state, node, cref, info);
end lookupFunctionName;

function fixExternalObjectCall
"Changes calls to external objects so that the constructor is called instead,
i.e. a call such as
'ExtObj eo = ExtObj(...)'
is changed to
'ExtObj eo = ExtObj.constructor(...)'"
input InstNode node;
input output ComponentRef cref;
input output LookupState state;
protected
Class cls;
InstNode constructor;
algorithm
// If it's not a class it can't be an external object.
if not LookupState.isClass(state) then
return;
end if;

// External objects are identified by extending from ExternalObject, so the
// node needs to be expanded before we know whether it's an external object or
// not. Components are instantiated before their bindings, so in proper models
// we shouldn't get any non-expanded external objects here. But to avoid
// getting weird errors in erroneous models we make sure it's expanded anyway.
Inst.expand(node);
cls := InstNode.getClass(node);

() := match cls
case Class.PARTIAL_BUILTIN(ty = Type.COMPLEX(complexTy =
ComplexType.EXTERNAL_OBJECT(constructor = constructor)))
algorithm
cref := ComponentRef.prefixCref(constructor, Type.UNKNOWN(), {}, cref);
state := LookupState.FUNC();
then
();

else ();
end match;
end fixExternalObjectCall;

function lookupImport
input Absyn.Path name;
input InstNode scope;
Expand All @@ -188,6 +211,7 @@ function lookupCref
input Absyn.ComponentRef cref;
input InstNode scope "The scope to look in.";
input SourceInfo info;
input Error.Message errMsg;
output ComponentRef foundCref;
output InstNode foundScope "The scope where the first part of the cref was found.";
output LookupState state;
Expand Down Expand Up @@ -224,7 +248,7 @@ algorithm
(foundCref, foundScope, state);

case Absyn.ComponentRef.CREF_FULLYQUALIFIED()
then lookupCref(cref.componentRef, InstNode.topScope(scope), info);
then lookupCref(cref.componentRef, InstNode.topScope(scope), info, errMsg);

case Absyn.ComponentRef.WILD() then (ComponentRef.WILD(), scope, LookupState.PREDEF_COMP());
case Absyn.ComponentRef.ALLWILD() then (ComponentRef.WILD(), scope, LookupState.PREDEF_COMP());
Expand All @@ -242,7 +266,7 @@ algorithm
end if;

if match_ty <> MatchType.FOUND then
Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR,
Error.addSourceMessage(errMsg,
{Dump.printComponentRefStr(cref), InstNode.name(scope)}, info);
fail();
end if;
Expand Down
19 changes: 15 additions & 4 deletions Compiler/NFFrontEnd/NFLookupState.mo
Expand Up @@ -132,14 +132,25 @@ uniontype LookupState

function isCallable
input InstNode node;
output Boolean b = false;
output Boolean callable;
protected
SCode.Element def;
SCode.Element def = InstNode.definition(node);
algorithm
def := InstNode.definition(node);
b := SCode.isRecord(def) or SCode.isOperator(def);
callable := SCode.isRecord(def) or SCode.isOperator(def);
end isCallable;

function isClass
input LookupState state;
output Boolean isClass;
algorithm
isClass := match state
case COMP_CLASS() then true;
case CLASS() then true;
case PREDEF_CLASS() then true;
else false;
end match;
end isClass;

function assertState
input LookupState endState;
input LookupState expectedState;
Expand Down

0 comments on commit d71fe29

Please sign in to comment.