1165 lines
50 KiB
Standard ML
1165 lines
50 KiB
Standard ML
(*****************************************************************************
|
|
* su4sml --- an SML repository for managing (Secure)UML/OCL models
|
|
* http://projects.brucker.ch/su4sml/
|
|
*
|
|
* xmi_parser.sml --- an xmi-parser for the import interface for su4sml
|
|
* This file is part of su4sml.
|
|
*
|
|
* Copyright (c) 2005-2007 ETH Zurich, Switzerland
|
|
* 2008-2009 Achim D. Brucker, Germany
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
*
|
|
* * Neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
******************************************************************************)
|
|
(* $Id$ *)
|
|
|
|
structure XmiParser : sig
|
|
val readFile: string -> XMI.XmiContent
|
|
end =
|
|
struct
|
|
open Rep_Helper
|
|
open XmlTree
|
|
open XmlTreeHelper
|
|
|
|
(* some syntax sugar *)
|
|
infix 1 |>
|
|
infix 2 is
|
|
val map_optional = Option.map
|
|
fun get_optional_or_default x y = Option.getOpt(y,x)
|
|
|
|
fun bool_value_of string atts =
|
|
let val att = value_of string atts
|
|
in
|
|
(valOf o Bool.fromString) att
|
|
handle Option => Logger.error ("boolean attribute \""^string^
|
|
"\" has non-boolean value \""^att^
|
|
"\" (xmi.id = "^(value_of "xmi.id" atts)^")")
|
|
end
|
|
|
|
|
|
fun int_value_of string atts =
|
|
let val att = value_of string atts
|
|
in
|
|
(valOf o Int.fromString) att
|
|
handle Option => Logger.error ("integer attribute \""^string^
|
|
"\" has non-integer value \""^att^
|
|
"\" (xmi.id = "^(value_of "xmi.id" atts)^")")
|
|
end
|
|
|
|
val language = value_of "language"
|
|
val body = value_of "body"
|
|
val xmiid = value_of "xmi.id"
|
|
val name = value_of "name"
|
|
fun xmiidref t = t |> attributes |> value_of "xmi.idref"
|
|
|
|
fun optional_name_or_empty atts = atts |> optional_value_of "name"
|
|
|> get_optional_or_default ""
|
|
|
|
fun unknown_attribute_value atts att s = Logger.error ("attribute \""^att^
|
|
"\" has unknown value \""^s^
|
|
"\" (xmi.id = "^(atts |> xmiid)^")")
|
|
|
|
fun visibility atts =
|
|
let val att = optional_value_of "visibility" atts
|
|
in
|
|
case att of SOME "public" => XMI.public
|
|
| SOME "private" => XMI.private
|
|
| SOME "protected" => XMI.protected
|
|
| SOME "package" => XMI.package
|
|
| NONE => XMI.public
|
|
| SOME string => unknown_attribute_value atts "visibility" string
|
|
end
|
|
|
|
|
|
fun target_scope atts =
|
|
let val att = optional_value_of "targetScope" atts
|
|
in
|
|
case att of SOME "instance" => XMI.InstanceScope
|
|
| SOME "classifier" => XMI.ClassifierScope
|
|
| NONE => XMI.InstanceScope
|
|
| SOME s => unknown_attribute_value atts "targetScope" s
|
|
end
|
|
|
|
fun owner_scope atts =
|
|
let val att = optional_value_of "ownerScope" atts
|
|
in
|
|
case att of SOME "instance" => XMI.InstanceScope
|
|
| SOME "classifier" => XMI.ClassifierScope
|
|
| NONE => XMI.InstanceScope
|
|
| SOME s => unknown_attribute_value atts "ownerScope" s
|
|
end
|
|
|
|
fun ordering default atts =
|
|
let val att = optional_value_of "ordering" atts
|
|
in
|
|
case att of SOME "unordered" => XMI.Unordered
|
|
| SOME "ordered" => XMI.Ordered
|
|
| NONE => default (* XMI.Unordered *)
|
|
| SOME s => unknown_attribute_value atts "ordering" s
|
|
end
|
|
|
|
fun aggregation atts =
|
|
let val att = optional_value_of "aggregation" atts
|
|
in
|
|
(case att of SOME "none" => XMI.NoAggregation
|
|
| SOME "aggregate" => XMI.Aggregate
|
|
| SOME "composite" => XMI.Composite
|
|
| NONE => XMI.NoAggregation
|
|
| SOME x => unknown_attribute_value atts "aggregation" x)
|
|
end
|
|
|
|
fun changeability atts =
|
|
let val att = optional_value_of "changeability" atts in
|
|
case att of
|
|
SOME "changeable" => XMI.Changeable
|
|
| SOME "frozen" => XMI.Frozen
|
|
| SOME "addonly" => XMI.AddOnly
|
|
| NONE => XMI.Changeable
|
|
| SOME x => unknown_attribute_value atts "changeability" x
|
|
end
|
|
|
|
fun kind atts =
|
|
let val att = atts |> optional_value_of "kind"
|
|
|> get_optional_or_default "inout"
|
|
in
|
|
case att of
|
|
"in" => XMI.In
|
|
| "out" => XMI.Out
|
|
| "inout" => XMI.Inout
|
|
| "return" => XMI.Return
|
|
| x => unknown_attribute_value atts "kind" x
|
|
end
|
|
|
|
fun pseudo_state_kind atts =
|
|
let val att = value_of "kind" atts
|
|
in case att of "initial" => XMI.initial
|
|
| "deep" => XMI.deep
|
|
| "shallow" => XMI.shallow
|
|
| "join" => XMI.join
|
|
| "fork" => XMI.fork
|
|
| "junction" => XMI.junction
|
|
| "choice" => XMI.choice
|
|
| x => unknown_attribute_value atts "kind (PseudoStateKind)" x
|
|
end
|
|
|
|
fun mkRange tree =
|
|
let val atts = tree |> assert "UML:MultiplicityRange" |> attributes
|
|
in
|
|
(int_value_of "lower" atts, int_value_of "upper" atts)
|
|
end
|
|
|
|
fun mkMultiplicity tree =
|
|
assert "UML:Multiplicity" tree
|
|
|> get "UML:Multiplicity.range"
|
|
|> map mkRange
|
|
|
|
(* find the xmi.idref attribute of an element pointed to by name *)
|
|
fun xmiidref_to name tree = tree |> get_one name
|
|
|> xmiidref
|
|
|
|
(* find the type of an OCl sub-expression *)
|
|
fun expression_type tree = tree |> xmiidref_to "OCL.Expressions.OclExpression.type"
|
|
handle _ => "DummyT"
|
|
(* hack: return a reference to a dummy*)
|
|
(* type if the real type is not found *)
|
|
|
|
(* this is a hack. This will still throw an exception in xmi2mdr, because the *)
|
|
(* expression_type should be the xmiid of oclLib.Boolean, which we do not know *)
|
|
val triv_expr = XMI.LiteralExp {symbol = "true",
|
|
expression_type = "bool" }
|
|
|
|
(* FIX: this is only a dummy implementation *)
|
|
fun mkCollectionLiteralPart x = (xmiidref x)
|
|
|
|
fun mkLiteralExp string tree =
|
|
XMI.LiteralExp
|
|
{ symbol = tree |> attributes |> value_of string,
|
|
expression_type = tree |> expression_type
|
|
}
|
|
|
|
fun mkOCLExpression (tree as Node(("UML15OCL.Expressions.BooleanLiteralExp",
|
|
atts),_)) =
|
|
mkLiteralExp "booleanSymbol" tree
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.IntegerLiteralExp",
|
|
atts),_)) =
|
|
mkLiteralExp "integerSymbol" tree
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.StringLiteralExp",
|
|
atts),_)) =
|
|
mkLiteralExp "stringSymbol" tree
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.RealLiteralExp",
|
|
atts),_)) =
|
|
mkLiteralExp "realSymbol" tree
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.CollectionLiteralExp",
|
|
atts),_))
|
|
= XMI.CollectionLiteralExp
|
|
{ parts = nil,
|
|
(* map mkCollectionLiteralPart (follow "OCL.Expressions.\
|
|
\CollectionLiteralExp.parts" trees),*)
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.OperationCallExp",
|
|
atts),_))
|
|
= XMI.OperationCallExp
|
|
{ source = (tree |> get_one "OCL.Expressions.\
|
|
\PropertyCallExp.source"
|
|
|> mkOCLExpression)
|
|
(* This hack is necessary to support TYPE::allInstances() as parsed *)
|
|
(* by dresden-ocl. *)
|
|
handle ex =>
|
|
XMI.LiteralExp
|
|
{ symbol = "",
|
|
expression_type = tree |> get_one "OCL.Expressions.\
|
|
\FeatureCallExp.\
|
|
\srcType"
|
|
|> xmiidref
|
|
},
|
|
arguments = tree |> get "OCL.Expressions.OperationCallExp.arguments"
|
|
|> map mkOCLExpression,
|
|
referredOperation = tree |> xmiidref_to "OCL.Expressions.\
|
|
\OperationCallExp.\
|
|
\referredOperation",
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.OclOperationWith\
|
|
\TypeArgExp",atts),_))
|
|
= XMI.OperationWithTypeArgExp
|
|
{ source = tree |> get_one "OCL.Expressions.PropertyCallExp.\
|
|
\source"
|
|
|> mkOCLExpression,
|
|
name = atts |> name,
|
|
typeArgument = tree |> xmiidref_to "OCL.Expressions.OclOperation\
|
|
\WithTypeArgExp.typeArgument",
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.AttributeCallExp",
|
|
atts),_))
|
|
= XMI.AttributeCallExp
|
|
{ source = tree |> get_one "OCL.Expressions.PropertyCall\
|
|
\Exp.source"
|
|
|> mkOCLExpression,
|
|
referredAttribute = tree |> xmiidref_to "OCL.Expressions.Attribute\
|
|
\CallExp.referred\
|
|
\Attribute",
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.AssociationEndCall\
|
|
\Exp",atts),_))
|
|
= XMI.AssociationEndCallExp
|
|
{ source = tree |> get_one "OCL.Expressions.PropertyCallExp.source"
|
|
|> mkOCLExpression,
|
|
referredAssociationEnd = tree |> xmiidref_to
|
|
"OCL.Expressions.AssociationEndCall\
|
|
\Exp.referredAssociationEnd",
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.AssociationClassCall\
|
|
\Exp",atts),_))
|
|
= Logger.error ("AssociationClassCallExp is not yet implemented"^some_id tree)
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.VariableExp",atts),_))
|
|
= XMI.VariableExp
|
|
{ referredVariable = tree |> xmiidref_to
|
|
"OCL.Expressions.VariableExp.referred\
|
|
\Variable",
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.IfExp",atts),_))
|
|
= XMI.IfExp
|
|
{ condition = tree |> get_one "OCL.Expressions.IfExp.condition"
|
|
|> mkOCLExpression,
|
|
thenExpression = tree |> get_one "OCL.Expressions.IfExp.then\
|
|
\Expression"
|
|
|> mkOCLExpression,
|
|
elseExpression = tree |> get_one "OCL.Expressions.IfExp.else\
|
|
\Expression"
|
|
|> mkOCLExpression,
|
|
expression_type = tree |> expression_type }
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.LetExp",atts),_))
|
|
= XMI.LetExp
|
|
{ variable = let val vard = tree |> get_one "OCL.Expressions.Let\
|
|
\Exp.variable"
|
|
val atts = vard |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
declaration_type = vard |> xmiidref_to
|
|
"OCL.Expressions.Variable\
|
|
\Declaration.type",
|
|
init = vard |> get_one
|
|
"OCL.Expressions.VariableDeclaration.\
|
|
\initExpression"
|
|
|> mkOCLExpression
|
|
|> SOME
|
|
}
|
|
end,
|
|
inExpression = tree |> get_one "OCL.Expressions.LetExp.in"
|
|
|> mkOCLExpression,
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.IterateExp",atts),_))
|
|
= XMI.IterateExp
|
|
{ result = tree |> get_one "OCL.Expressions.IterateExp.result"
|
|
|> mkVariableDec,
|
|
iterators = tree |> get_many "OCL.Expressions.LoopExp.iterators"
|
|
|> map mkVariableDec,
|
|
body = tree |> get_one "OCL.Expressions.LoopExp.body"
|
|
|> mkOCLExpression,
|
|
source = tree |> get_one "OCL.Expressions.PropertyCallExp.\
|
|
\source"
|
|
|> mkOCLExpression,
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression (tree as Node(("UML15OCL.Expressions.IteratorExp",atts),_))
|
|
= XMI.IteratorExp
|
|
{ name = atts |> name,
|
|
iterators = tree |> get_many "OCL.Expressions.LoopExp.iterators"
|
|
|> map mkVariableDec,
|
|
body = tree |> get_one "OCL.Expressions.LoopExp.body"
|
|
|> mkOCLExpression,
|
|
source = tree |> get_one "OCL.Expressions.PropertyCallExp.source"
|
|
|> mkOCLExpression,
|
|
expression_type = tree |> expression_type
|
|
}
|
|
| mkOCLExpression tree =
|
|
Logger.error ("unknown OCLExpression type \""^(tagname tree)^"\""^some_id tree^
|
|
".")
|
|
and mkVariableDec vtree =
|
|
let val atts = vtree |> assert "UML15OCL.Expressions.VariableDeclaration"
|
|
|> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
init = vtree |> get_optional "OCL.Expressions.VariableDeclaration.\
|
|
\initExpression"
|
|
|> map_optional mkOCLExpression,
|
|
declaration_type = vtree |> get_one "OCL.Expressions.Variable\
|
|
\Declaration.type"
|
|
|> xmiidref
|
|
}
|
|
end
|
|
(* handle IllFormed msg => Logger.error ("in mkVariableDec: "^msg)*)
|
|
|
|
fun mkTaggedValue tree =
|
|
let val atts = tree |> assert "UML:TaggedValue" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
dataValue= tree |> find_child "UML:TaggedValue.dataValue"
|
|
|> children
|
|
|> map text
|
|
|> String.concat,
|
|
tag_type = tree |> get_one "UML:TaggedValue.type"
|
|
|> assert "UML:TagDefinition"
|
|
|> xmiidref
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkTaggedValue: "^msg)*)
|
|
|
|
fun mkAttribute tree =
|
|
let val atts = tree |> assert "UML:Attribute" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
visibility = atts |> visibility,
|
|
changeability = atts |> changeability,
|
|
ordering = atts |> ordering XMI.Ordered,
|
|
initialValue = tree |> get_optional "UML:Attribute.initialValue"
|
|
|> map_optional (get_optional
|
|
"OCL.Expressions.\
|
|
\ExpressionInOcl.bodyExpression")
|
|
|> Option.join
|
|
|> map_optional mkOCLExpression,
|
|
type_id = tree |> get_optional "UML:StructuralFeature.type"
|
|
|> map_optional xmiidref
|
|
|> get_optional_or_default "",
|
|
multiplicity = tree |> get_optional "UML:StructuralFeature.multiplicity"
|
|
|> map_optional mkMultiplicity
|
|
|> get_optional_or_default [(1,1)],
|
|
targetScope = atts |> target_scope,
|
|
ownerScope = atts |> owner_scope,
|
|
stereotype = tree |> get "UML:ModelElement.stereotype"
|
|
|> map xmiidref ,
|
|
taggedValue = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkAttribute: "^msg)*)
|
|
|
|
fun mkQualifier tree =
|
|
get_maybe "UML:Attribute" tree
|
|
|> map mkAttribute
|
|
|
|
fun mkAssociationEnd association tree:XMI_Core.AssociationEnd =
|
|
let val atts = tree |> assert "UML:AssociationEnd" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> optional_value_of "name",
|
|
association = association,
|
|
isNavigable = atts |> bool_value_of "isNavigable" ,
|
|
ordering = atts |> ordering XMI.Unordered,
|
|
aggregation = atts |> aggregation,
|
|
targetScope = atts |> target_scope,
|
|
multiplicity = tree |> get_optional "UML:AssociationEnd.\
|
|
\multiplicity"
|
|
|> map_optional mkMultiplicity
|
|
|> get_optional_or_default [(0,~1)],
|
|
changeability = atts |> changeability,
|
|
qualifier = tree |> get_optional "UML.AssociationEnd.qualifier"
|
|
|> map_optional mkQualifier
|
|
|> get_optional_or_default [],
|
|
visibility = atts |> visibility,
|
|
participant_id = tree |> get_one "UML:AssociationEnd.participant"
|
|
|> xmiidref
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkAssociationEnd: "^msg)*)
|
|
|
|
(* This is a hack to handle the implicit association end to *)
|
|
(* the AssociationClass itself. *)
|
|
(* update: no longer needed *)
|
|
fun mkAssociationEndFromAssociationClass association tree :XMI.AssociationEnd =
|
|
let val atts = tree |> assert "UML:AssociationClass" |> attributes
|
|
in
|
|
{(* xmiids are used as keys in a lookup table. *)
|
|
(* to avoid name-clashes with the xmiid for the *)
|
|
(* class itsel, we simply add a suffix *)
|
|
xmiid = (atts |> xmiid)^"_aend",
|
|
(* rep_parser already takes care of naming the association end *)
|
|
name = NONE,
|
|
association = association,
|
|
isNavigable = true,
|
|
ordering = XMI_DataTypes.Unordered,
|
|
aggregation = XMI_DataTypes.Aggregate,
|
|
targetScope = XMI_DataTypes.InstanceScope,
|
|
multiplicity = [(0,~1)] (* FIX: is this always the correct multiplicity? *),
|
|
qualifier = [],
|
|
changeability = XMI_DataTypes.Changeable,
|
|
visibility = XMI_DataTypes.public,
|
|
participant_id = atts |> xmiid
|
|
}
|
|
end
|
|
|
|
(* FIX: this is a hack to handle AssociationClasses. *)
|
|
(* From an AssociationClass, we build the corresponding association *)
|
|
(* that will later be handles just like any other association. *)
|
|
fun mkAssociationFromAssociationClass tree =
|
|
let
|
|
val atts = tree |> assert "UML:AssociationClass" |> attributes
|
|
val id = atts |> xmiid
|
|
in
|
|
{ xmiid = id,
|
|
name = atts |> optional_value_of "name" ,
|
|
connection = tree |> get_many "UML:Association.connection"
|
|
|> map (mkAssociationEnd id)
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkAssociation: "^msg)*)
|
|
|
|
|
|
fun mkAssociation tree =
|
|
let
|
|
val _ = Logger.debug2 ("XmiParser.mkAssociation\n")
|
|
val atts = tree |> assert "UML:Association" |> attributes
|
|
val id = atts |> xmiid
|
|
(* FIXME: empty string is returned as (SOME "") instead of NONE *)
|
|
val name_tmp = atts |> optional_value_of "name"
|
|
val name = if (isSome name_tmp) andalso ((valOf name_tmp) = "")
|
|
then NONE
|
|
else name_tmp
|
|
val res = { xmiid = id,
|
|
name = name,
|
|
connection = tree |> get_many "UML:Association.connection"
|
|
|> map (mkAssociationEnd id)
|
|
}
|
|
val _ = Logger.debug2 ("end XmiParser.mkAssociation")
|
|
in
|
|
res
|
|
end
|
|
(* handle IllFormed msg => Logger.error ("in mkAssociation: "^msg)*)
|
|
|
|
val filterAssociations = filter "UML:Association"
|
|
val filterAssociationClasses = filter "UML:AssociationClass"
|
|
|
|
fun filterConstraints trees = List.filter (fn x => (tagname o (get_one "UML:Constraint.body")) x
|
|
= "UML15OCL.Expressions.ExpressionInOcl")
|
|
(filter "UML:Constraint" trees)
|
|
|
|
val filterStereotypes = filter "UML:Stereotype"
|
|
val filterVariableDecs = filter "UML15OCL.Expressions.VariableDeclaration"
|
|
val filterPackages = fn trees => append (filter "UML:Package" trees)
|
|
(filter "UML:Model" trees)
|
|
val filterStateMachines = filter "UML:StateMachine"
|
|
val filterActivityGraphs= filter "UML:ActivityGraph"
|
|
val filterEvents = fn x => append (filter "UML:CallEvent" x)
|
|
(filter "UML:SignalEvent" x)(* add SignalEvents? *)
|
|
|
|
(* there may be other kinds of dependencies, but we do not parse them atm *)
|
|
val filterDependencies = filter "UML:Abstraction"
|
|
|
|
val filterTagDefinitions = filter "UML:TagDefinition"
|
|
|
|
(* FIX: other classifiers *)
|
|
fun filterClassifiers trees =
|
|
List.filter (fn x => let val elem = tagname x in
|
|
elem = "UML:Class" orelse
|
|
elem = "UML:Primitive" orelse
|
|
elem = "UML:DataType" orelse
|
|
elem = "UML:Interface" orelse
|
|
elem = "UML:Enumeration" orelse
|
|
elem = "UML15OCL.Types.SequenceType" orelse
|
|
elem = "UML15OCL.Types.BagType" orelse
|
|
elem = "UML15OCL.Types.SetType" orelse
|
|
elem = "UML15OCL.Types.CollectionType" orelse
|
|
elem = "UML15OCL.Types.VoidType" orelse
|
|
elem = "UML:AssociationClass"
|
|
end) trees
|
|
|
|
fun mkDependency tree =
|
|
let val atts = tree |> assert "UML:Abstraction" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
client = tree |> get_one "UML:Dependency.client"
|
|
|> xmiidref,
|
|
supplier = tree |> get_one "UML:Dependency.supplier"
|
|
|> xmiidref,
|
|
stereotype = tree |> get_one "UML:ModelElement.stereotype"
|
|
|> xmiidref
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkDependency: "^msg) *)
|
|
|
|
fun mkConstraint tree =
|
|
let val atts = tree |> assert "UML:Constraint" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> optional_value_of "name",
|
|
constraint_type = tree |> get_one "UML:ModelElement.stereotype"
|
|
|> xmiidref,
|
|
body = tree |> get_one "UML:Constraint.body"
|
|
|> assert "UML15OCL.Expressions.ExpressionInOcl"
|
|
|> get_one "OCL.Expressions.ExpressionInOcl.bodyExpression"
|
|
|> mkOCLExpression
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkConstraint: "^msg)*)
|
|
|
|
|
|
fun mkParameter tree =
|
|
let val atts = tree |> assert "UML:Parameter" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
kind = atts |> kind,
|
|
type_id = tree |> get_optional "UML:Parameter.type"
|
|
|> map_optional xmiidref
|
|
|> get_optional_or_default ""
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkParameter: "^msg)*)
|
|
|
|
fun mkOperation tree =
|
|
let val atts = tree |> assert "UML:Operation" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
visibility = atts |> visibility,
|
|
isQuery = atts |> bool_value_of "isQuery",
|
|
ownerScope = atts |> owner_scope,
|
|
parameter = tree |> get "UML:BehavioralFeature.parameter"
|
|
|> map mkParameter,
|
|
constraints = tree |> get_maybe "UML:ModelElement.constraint"
|
|
|> map xmiidref
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkOperation: "^msg)*)
|
|
|
|
fun mkTagDefinition tree =
|
|
let val atts = tree |> assert "UML:TagDefinition" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
multiplicity = tree |> get_one "UML:TagDefinition.multiplicity"
|
|
|> mkMultiplicity
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkTagDefinition: "^msg)*)
|
|
|
|
fun mkStereotypeR tree =
|
|
let val atts = tree |> assert "UML:Stereotype" |> attributes
|
|
in
|
|
tree |> xmiidref
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkStereotype: "^msg)*)
|
|
|
|
fun mkAction tree =
|
|
let val atts = tree |> attributes
|
|
val expr = tree |> get_one "UML:Action.script"
|
|
val expr_atts = expr |> attributes
|
|
in
|
|
XMI.mk_Procedure
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> optional_name_or_empty,
|
|
isSpecification = atts |> bool_value_of "isSpecification" ,
|
|
isAsynchronous = atts |> bool_value_of "isAsynchronous" ,
|
|
language = expr_atts |> language,
|
|
body = expr_atts |> body ,
|
|
expression = "" (* FIXME: is this even useful? *)}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkAction: "^msg)*)
|
|
|
|
(* This works for ArgoUML, i.e. 1.4 metamodels... *)
|
|
fun mkProcedure tree =
|
|
let val elem = tagname tree
|
|
in
|
|
if elem = "UML:CallAction" orelse
|
|
elem = "UML:CreateAction" orelse
|
|
elem = "UML:DestroyAction" orelse
|
|
elem = "UML:ReturnAction" orelse
|
|
elem = "UML:SendAction" orelse
|
|
elem = "UML:TerminateAction" orelse
|
|
elem = "UML:UninterpretedAction"
|
|
then mkAction tree
|
|
else Logger.error ("unknown Action type \""^elem^"\""^(some_id tree)^".")
|
|
end
|
|
|
|
fun mkGuard tree =
|
|
let val atts = tree |> assert "UML:Guard"
|
|
|> attributes
|
|
val expr = tree |> get_one "UML:Guard.expression"
|
|
val expr_atts = expr |> attributes
|
|
in
|
|
XMI.mk_Guard
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> optional_name_or_empty,
|
|
isSpecification = atts |> bool_value_of "isSpecification",
|
|
visibility = atts |> visibility,
|
|
language = if expr is "UML15OCL:Expressions.ExpressionInOcl" orelse
|
|
expr is "UML:BooleanExpression"
|
|
then expr_atts |> language
|
|
else
|
|
Logger.error ("unknown expression type \""^(tagname expr)^
|
|
"\""^some_id expr^"."),
|
|
body = if expr is "UML:BooleanExpression" then
|
|
SOME (expr_atts |> body)
|
|
else NONE,
|
|
expression = if expr is "UML15OCL:Expressions.ExpressionInOcl"
|
|
then SOME (mkOCLExpression expr)
|
|
else NONE}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkGuard: "^msg)*)
|
|
|
|
|
|
fun mkTransition tree =
|
|
let val atts = tree |> assert "UML:Transition" |> attributes
|
|
in
|
|
XMI.mk_Transition
|
|
{ xmiid = atts |> xmiid,
|
|
isSpecification = atts |> bool_value_of "isSpecification",
|
|
source = tree |> get_one "UML:Transition.source"
|
|
|> xmiidref,
|
|
target = tree |> get_one "UML:Transition.target"
|
|
|> xmiidref,
|
|
guard = tree |> get_optional "UML:Transition.guard"
|
|
|> map_optional mkGuard,
|
|
trigger = tree |> get_optional "UML:Transition.trigger"
|
|
|> map_optional xmiidref,
|
|
effect = tree |> get_optional "UML:Transition.effect"
|
|
|> map_optional mkProcedure,
|
|
taggedValue = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkTransition: "^msg)*)
|
|
|
|
|
|
|
|
fun mkState tree =
|
|
let val elem = tagname tree
|
|
val atts = attributes tree
|
|
val xmiid = atts |> xmiid
|
|
val name = atts |> optional_name_or_empty
|
|
val isSpecification = atts |> bool_value_of "isSpecification"
|
|
fun idref tree = tree |> xmiidref
|
|
val stereotypes = tree |> get "UML:ModelElement.stereotype"
|
|
|> map mkStereotypeR
|
|
val incoming = tree |> get "UML:StateVertex.incoming"
|
|
|> map xmiidref
|
|
val outgoing = tree |> get "UML:StateVertex.outgoing"
|
|
|> map xmiidref
|
|
fun getSubvertex tree = tree |> get_many "UML:CompositeState.subvertex"
|
|
|> map mkState
|
|
val entry = tree |> get_optional "UML:State.entry"
|
|
|> map_optional mkProcedure
|
|
val exit = tree |> get_optional "UML:State.exit"
|
|
|> map_optional mkProcedure
|
|
val do_act = tree |> get_optional "UML:State.doActivity"
|
|
|> map_optional mkProcedure
|
|
val tagval = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue
|
|
fun getType tree = tree |> get_one "UML:ObjectFlowState.type"
|
|
|> xmiidref
|
|
in case elem of
|
|
"UML:CompositeState" =>
|
|
XMI.CompositeState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
isConcurrent = atts |> bool_value_of "isConcurrent",
|
|
outgoing = outgoing, incoming = incoming,
|
|
subvertex = getSubvertex tree,
|
|
entry = entry,
|
|
exit = exit,
|
|
doActivity = do_act,
|
|
taggedValue = tagval
|
|
}
|
|
|"UML:SubactivityState" =>
|
|
XMI.SubactivityState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
isConcurrent = atts |> bool_value_of "isConcurrent",
|
|
isDynamic = atts |> bool_value_of "isDynamic",
|
|
outgoing = outgoing, incoming = incoming,
|
|
subvertex = getSubvertex tree,
|
|
entry = entry,
|
|
exit = exit,
|
|
doActivity = do_act,
|
|
submachine = mkStateMachine tree,
|
|
(* HACK ! So far, no UML tool supports this. *)
|
|
(* Parser has to be adapted when we find a first example ... *)
|
|
taggedValue = tagval}
|
|
|"UML:ActionState" =>
|
|
XMI.ActionState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
outgoing = outgoing, incoming = incoming,
|
|
isDynamic = atts |> bool_value_of "isDynamic",
|
|
entry = entry,
|
|
taggedValue = tagval}
|
|
|"UML:Pseudostate" =>
|
|
XMI.PseudoState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
kind = atts |> pseudo_state_kind,
|
|
outgoing = outgoing,incoming = incoming,
|
|
taggedValue = tagval}
|
|
|"UML:SimpleState" =>
|
|
XMI.SimpleState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
entry = entry,
|
|
exit = exit,
|
|
doActivity = do_act,
|
|
outgoing = outgoing, incoming = incoming,
|
|
taggedValue = tagval}
|
|
|"UML:ObjectFlowState" =>
|
|
XMI.ObjectFlowState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
entry = entry,
|
|
exit = exit,
|
|
doActivity = do_act,
|
|
outgoing = outgoing, incoming = incoming,
|
|
isSynch = atts |> bool_value_of "isSynch",
|
|
parameter = nil,
|
|
type_ = tree |> getType,
|
|
taggedValue = tagval}
|
|
|"UML:FinalState" =>
|
|
XMI.FinalState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
entry = entry,
|
|
exit = exit,
|
|
doActivity = do_act,
|
|
incoming = incoming,
|
|
taggedValue = tagval}
|
|
|"UML:SyncState" =>
|
|
XMI.SyncState
|
|
{ xmiid=xmiid,name=name,isSpecification=isSpecification,
|
|
stereotype = stereotypes,
|
|
bound = 0,
|
|
outgoing = outgoing,incoming = incoming,
|
|
taggedValue = tagval}
|
|
|
|
| s => Logger.error ("unknown StateVertex type \""^s^"\""^some_id tree^".")
|
|
end
|
|
and mkStateMachine tree =
|
|
let val atts = tree |> assert "UML:StateMachine" |> attributes
|
|
in
|
|
XMI.mk_StateMachine
|
|
{ isSpecification = atts |> bool_value_of "isSpecification",
|
|
xmiid = atts |> xmiid,
|
|
contextxmiid = tree |> get_one "UML:StateMachine.context"
|
|
|> xmiidref,
|
|
top = tree |> get_one "UML:StateMachine.top"
|
|
|> mkState,
|
|
transitions = tree |> get "UML:StateMachine.transitions"
|
|
|> map mkTransition
|
|
}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkStateMachine: "^msg)*)
|
|
|
|
|
|
fun mkActivityGraph tree =
|
|
let val atts = tree |> assert "UML:ActivityGraph" |> attributes
|
|
in
|
|
XMI.mk_ActivityGraph
|
|
{ isSpecification = atts |> bool_value_of "isSpecification",
|
|
xmiid = atts |> xmiid,
|
|
contextxmiid = tree |> get_one "UML:StateMachine.context"
|
|
|> xmiidref,
|
|
top = tree |> get_one "UML:StateMachine.top"
|
|
|> mkState,
|
|
transitions = tree |> get "UML:StateMachine.transitions"
|
|
|> map mkTransition,
|
|
partition = nil}
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("in mkActivityGraph: "^msg)*)
|
|
|
|
fun mkClass atts tree =
|
|
let
|
|
val _ = Logger.debug2 ("XmiParser.mkClass \n")
|
|
val res = XMI.Class
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
isActive = atts |> bool_value_of "isActive",
|
|
visibility = atts |> visibility,
|
|
isLeaf = atts |> bool_value_of "isLeaf",
|
|
generalizations = tree |> get "UML:GeneralizableElement.generalization"
|
|
|> map xmiidref,
|
|
attributes = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Attribute"
|
|
|> map mkAttribute,
|
|
operations = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Operation"
|
|
|> map mkOperation,
|
|
invariant = tree |> get "UML:ModelElement.constraint"
|
|
|> map xmiidref,
|
|
stereotype = tree |> get "UML:ModelElement.stereotype"
|
|
|> map xmiidref,
|
|
taggedValue = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue,
|
|
clientDependency = tree |> get "UML:ModelElement.clientDependency"
|
|
|> map xmiidref,
|
|
supplierDependency = tree |> get "UML:ModelElement.supplierDependency"
|
|
|> map xmiidref,
|
|
classifierInState = tree |> get "UML:Namespace.ownedElement"
|
|
|> filter "UML:ClassifierInState"
|
|
|> map (xmiid o attributes),
|
|
state_machines = tree |> get "UML:Namespace.ownedElement"
|
|
|> filter "UML:StateMachine"
|
|
|> map mkStateMachine,
|
|
activity_graphs = tree |> get "UML:Namespace.ownedElement"
|
|
|> filter "UML:ActivityGraph"
|
|
|> map mkActivityGraph
|
|
}
|
|
val _ = Logger.debug2 ("end XmiParser.mkClass \n")
|
|
in
|
|
res
|
|
end
|
|
(*handle IllFormed msg => Logger.error ("Error in mkClass "^(name atts)^
|
|
": "^msg)*)
|
|
|
|
(* extended to match Rep.AssociationClass *)
|
|
fun mkAssociationClass atts tree =
|
|
let
|
|
val _ = Logger.debug2 ("XmiParser.mkAssociationClass\n")
|
|
val id = atts |> xmiid
|
|
val res = XMI.AssociationClass
|
|
{ xmiid = id,
|
|
name = atts |> name,
|
|
isActive = atts |> bool_value_of "isActive",
|
|
visibility = atts |> visibility,
|
|
isLeaf = atts |> bool_value_of "isLeaf",
|
|
generalizations = tree |> get "UML:GeneralizableElement.\
|
|
\generalization"
|
|
|> map xmiidref,
|
|
attributes = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Attribute"
|
|
|> map mkAttribute,
|
|
operations = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Operation"
|
|
|> map mkOperation,
|
|
invariant = tree |> get "UML:ModelElement.constraint"
|
|
|> map xmiidref,
|
|
stereotype = tree |> get "UML:ModelElement.stereotype"
|
|
|> map xmiidref,
|
|
taggedValue = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue,
|
|
clientDependency = tree |> get "UML:ModelElement.client\
|
|
\Dependency"
|
|
|> map xmiidref,
|
|
supplierDependency = tree |> get "UML:ModelElement.supplier\
|
|
\Dependency"
|
|
|> map xmiidref,
|
|
(*classifierInState = tree |> get "UML:Namespace.ownedElement"
|
|
|> filter "UML:ClassifierInState"
|
|
|> map (xmiid o attributes),
|
|
state_machines = tree |> get "UML:Namespace.ownedElement"
|
|
|> filter "UML:StateMachine"
|
|
|> map mkStateMachine, activity_graphs = tree |> get "UML:Namespace.ownedElement"
|
|
|> filter "UML:ActivityGraph"
|
|
|> map mkActivityGraph,
|
|
*)connection = tree |> get_many "UML:Association.connection"
|
|
|> map (mkAssociationEnd id)
|
|
}
|
|
val _ = Logger.debug2 ("end XmiParser.mkAssociation Class\n")
|
|
in
|
|
res
|
|
end
|
|
|
|
(*handle IllFormed msg => Logger.error ("in mkAssociationClass: "^msg)*)
|
|
|
|
|
|
fun mkPrimitive atts tree
|
|
= XMI.Primitive
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
operations = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Operation"
|
|
|> map mkOperation,
|
|
generalizations = tree |> get "UML:GeneralizableElement.generalization"
|
|
|> map xmiidref,
|
|
invariant = tree |> get "UML:ModelElement.constraint"
|
|
|> map xmiidref,
|
|
taggedValue = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue
|
|
}
|
|
(* handle IllFormed msg => Logger.error ("in mkPrimitive: "^msg)*)
|
|
|
|
fun mkInterface atts tree
|
|
= XMI.Interface
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
operations = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Operation"
|
|
|> map mkOperation,
|
|
generalizations = tree |> get "UML:GeneralizableElement.generalization"
|
|
|> map xmiidref,
|
|
invariant = tree |> get "UML:ModelElement.constraint"
|
|
|> map xmiidref,
|
|
clientDependency = tree |> get "UML:ModelElement.clientDependency"
|
|
|> map xmiidref,
|
|
supplierDependency = tree |> get "UML:ModelElement.supplierDependency"
|
|
|> map xmiidref
|
|
}
|
|
(*handle IllFormed msg => Logger.error ("in mkInterface: "^msg)*)
|
|
|
|
fun mkEnumerationLiteral tree =
|
|
tree |> assert "UML:EnumerationLiteral"
|
|
|> attributes |> name
|
|
(*handle IllFormed msg => Logger.error ("in mkOperation: "^msg)*)
|
|
|
|
|
|
fun mkEnumeration atts tree
|
|
= XMI.Enumeration
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
operations = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Operation"
|
|
|> map mkOperation,
|
|
generalizations = tree |> get "UML:GeneralizableElement.generalization"
|
|
|> map xmiidref,
|
|
invariant = tree |> get "UML:ModelElement.constraint"
|
|
|> map xmiidref,
|
|
literals = tree |> get "UML:Enumeration.literal"
|
|
|> map mkEnumerationLiteral
|
|
}
|
|
(* handle IllFormed msg => Logger.error ("in mkEnumeration: "^msg)*)
|
|
|
|
fun mkVoid atts tree = XMI.Void { xmiid = atts |> xmiid,
|
|
name = atts |> name
|
|
}
|
|
(* handle IllFormed msg => Logger.error ("in mkVoid: "^msg)*)
|
|
|
|
|
|
fun mkGenericCollection atts tree =
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
operations = tree |> get "UML:Classifier.feature"
|
|
|> filter "UML:Operation"
|
|
|> map mkOperation,
|
|
generalizations = tree |> get "UML:GeneralizableElement.generalization"
|
|
|> map xmiidref,
|
|
elementtype = tree |> get_one "OCL.Types.CollectionType.elementType"
|
|
|> xmiidref
|
|
}
|
|
(* handle IllFormed msg => Logger.error ("in mkGenericCollection: "^msg) *)
|
|
|
|
|
|
fun mkCollection atts tree = XMI.Collection (mkGenericCollection atts tree)
|
|
fun mkSequence atts tree = XMI.Sequence (mkGenericCollection atts tree)
|
|
fun mkSet atts tree = XMI.Set (mkGenericCollection atts tree)
|
|
fun mkBag atts tree = XMI.Bag (mkGenericCollection atts tree)
|
|
fun mkOrderedSet atts tree = XMI.OrderedSet (mkGenericCollection atts tree)
|
|
|
|
fun mkStereotype tree =
|
|
let val atts = tree |> assert "UML:Stereotype" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
baseClass = Option.map (text o hd o text_children)
|
|
(find_some "UML:Stereotype.baseClass"
|
|
(node_children tree)),
|
|
stereotypeConstraint = NONE (* FIXME, not supported by ArgoUML 0.22 *)
|
|
}
|
|
end
|
|
(* handle IllFormed msg => Logger.error ("in mkStereotype: "^msg)*)
|
|
|
|
|
|
fun mkClassifier tree =
|
|
let val elem = tagname tree
|
|
val atts = attributes tree
|
|
val trees = node_children tree
|
|
in
|
|
case elem of "UML:Class" => mkClass atts tree
|
|
| "UML:AssociationClass" => mkAssociationClass atts tree
|
|
| "UML:Interface" => mkInterface atts tree
|
|
| "UML:DataType" => mkPrimitive atts tree
|
|
| "UML:Primitive" => mkPrimitive atts tree
|
|
| "UML:Enumeration" => mkEnumeration atts tree
|
|
| "UML15OCL.Types.VoidType" => mkVoid atts tree
|
|
| "UML15OCL.Types.CollectionType" => mkCollection atts tree
|
|
| "UML15OCL.Types.SequenceType" => mkSequence atts tree
|
|
| "UML15OCL.Types.SetType" => mkSet atts tree
|
|
| "UML15OCL.Types.BagType" => mkBag atts tree
|
|
| "UML15OCL.Types.OrderedSetType" => mkOrderedSet atts tree
|
|
| _ => Logger.error ("unknown Classifier type \""^elem^
|
|
"\""^some_id tree^".")
|
|
end
|
|
|
|
|
|
|
|
fun mkGeneralization tree =
|
|
let val atts = tree |> assert "UML:Generalization" |> attributes
|
|
in
|
|
{ xmiid = atts |> xmiid,
|
|
child_id = tree |> get_one "UML:Generalization.child"
|
|
|> xmiidref,
|
|
parent_id = tree |> get_one "UML:Generalization.parent"
|
|
|> xmiidref
|
|
}
|
|
end
|
|
|
|
|
|
fun mkCallEvent atts tree =
|
|
XMI.CallEvent
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> optional_name_or_empty,
|
|
operation = tree |> get_one "UML:CallEvent.operation"
|
|
|> xmiidref,
|
|
parameter = tree |> get "UML:Event.parameter"
|
|
|> map mkParameter
|
|
}
|
|
|
|
fun mkSignalEvent atts tree = XMI.SignalEvent { xmiid = atts |> xmiid,
|
|
name = atts |> optional_name_or_empty,
|
|
parameter = tree |> get "UML:Event.parameter"
|
|
|> map mkParameter
|
|
}
|
|
|
|
(* FIXME: other events ? *)
|
|
fun mkEvent tree =
|
|
let val elem = tagname tree
|
|
val atts = attributes tree
|
|
in
|
|
case elem of "UML:CallEvent" => mkCallEvent atts tree
|
|
| "UML:SignalEvent" => mkSignalEvent atts tree
|
|
| _ => Logger.error ("unknown Event type \""^elem^"\""^some_id tree^".")
|
|
end
|
|
|
|
|
|
|
|
|
|
fun mkPackage tree =
|
|
if tree is "UML:Model" orelse tree is "UML:Package"
|
|
then let val trees = tree |> get "UML:Namespace.ownedElement"
|
|
val atts = attributes tree
|
|
val package_name = atts |> name
|
|
val _ = if tree is "UML:Model" then Logger.info ("parsing model "^package_name)
|
|
else Logger.info ("parsing package "^package_name)
|
|
in
|
|
XMI.Package
|
|
{ xmiid = atts |> xmiid,
|
|
name = atts |> name,
|
|
visibility = atts |> visibility,
|
|
packages = trees |> filterPackages |> map mkPackage,
|
|
classifiers = trees |> filterClassifiers |> map mkClassifier,
|
|
(*associations = trees |> getAssociations,*)
|
|
associations = trees |> filterAssociations |> map mkAssociation,
|
|
generalizations = trees |> filter "UML:Generalization"
|
|
|> map mkGeneralization,
|
|
constraints = trees |> filterConstraints |> map mkConstraint,
|
|
stereotypes = trees |> filterStereotypes |> map mkStereotype,
|
|
tag_definitions = trees |> filterTagDefinitions
|
|
|> map mkTagDefinition,
|
|
state_machines = nil,
|
|
activity_graphs = trees |> filterActivityGraphs
|
|
|> map mkActivityGraph,
|
|
dependencies = trees |> filterDependencies
|
|
|> map mkDependency,
|
|
stereotype = tree |> get "UML:ModelElement.stereotype"
|
|
|> map xmiidref,
|
|
taggedValue = tree |> get "UML:ModelElement.taggedValue"
|
|
|> map mkTaggedValue,
|
|
events = trees |> filterEvents |> map mkEvent
|
|
}
|
|
end
|
|
else Logger.error "no UML:Model or UML:Package found"
|
|
|
|
|
|
fun mkXmiContent tree =
|
|
let val trees = node_children (assert "XMI.content" tree)
|
|
in
|
|
{ packages = trees |> filterPackages |> map mkPackage,
|
|
constraints = trees |> filterConstraints |> map mkConstraint ,
|
|
classifiers = trees |> filterClassifiers |> map mkClassifier ,
|
|
stereotypes = trees |> filterStereotypes |> map mkStereotype ,
|
|
variable_declarations = trees |> filterVariableDecs |> map mkVariableDec ,
|
|
activity_graphs = trees |> filterActivityGraphs
|
|
|> map mkActivityGraph ,
|
|
state_machines = trees |> filterStateMachines
|
|
|> map mkStateMachine }
|
|
end
|
|
|
|
val emptyXmiContent = { packages = nil,
|
|
constraints = nil,
|
|
classifiers = nil,
|
|
stereotypes = nil,
|
|
variable_declarations = nil,
|
|
activity_graphs = nil,
|
|
state_machines = nil}
|
|
|
|
fun findXmiContent tree = valOf (dfs "XMI.content" tree)
|
|
handle Option => Logger.error "no XMI.content found"
|
|
|
|
fun readFile f = (mkXmiContent o findXmiContent o XmlTreeParser.readFile) f
|
|
handle ex => (Logger.warn ("Error during parsing of "^f^": \n\t"^General.exnMessage ex);
|
|
raise ex)
|
|
end
|
|
|
|
|