diff --git a/README.md b/README.md index aa89fb42b..e967b6bab 100644 --- a/README.md +++ b/README.md @@ -92,20 +92,22 @@ Nice, we know. But not very awesome, it only can tell you if you are using a _bi 1. `assigns`: **any paradigm** is the given variable or attribute assigned? 1. `declares`: **any paradigm** is the given element declared? -1. `declaresAttribute`: **objects paradigm** is a given attribute declared? -1. `declaresClass`: **objects paradigm** is a given class declared? +1. `declaresAttribute`: **object oriented paradigm** is a given attribute declared? +1. `declaresClass`: **object oriented paradigm** is a given class declared? 1. `declaresComputation`: **any paradigm** that is, does the given computation - method, predicate, function, etc - exist? 1. `declaresComputationWithArity`: **any paradigm** that is, does the given computation have the exact given arity? 1. `declaresEntryPoint`: **any paradigm** is there a program entry point, like a `main` procedure? +1. `declaresEnumeration`: **imperative paradigm** is a given enumeration declared? 1. `declaresFact`: **logic paradigm** is a given logic fact declared? 1. `declaresFunction`: **functional/imperative paradigm** is a given function declared? -1. `declaresMethod`: **objects paradigm** is a given method declared? -1. `declaresObject`: **objects paradigm** is a given named object declared? +1. `declaresInterface`: **object oriented paradigm** is a given interface declared? +1. `declaresMethod`: **object oriented paradigm** is a given method declared? +1. `declaresObject`: **object oriented paradigm** is a given named object declared? 1. `declaresPredicate`: **logic paradigm** is a given rule o fact declared? 1. `declaresProcedure`: **imperative paradigm** is a given procedure declared? 1. `declaresRecursively`: **any paradigm** is a given computation declared using recusion? 1. `declaresRule`: **logic paradigm** is a given logic rule declared? -1. `declaresSuperclass`: **objects paradigm** is a given class declared as superclass? +1. `declaresSuperclass`: **object oriented paradigm** is a given class declared as superclass? 1. `declaresTypeAlias`: **any paradigm** is a given type synonym declared? 1. `declaresTypeSignature`: **any paradigm** is a given computation type signature declared? 1. `declaresVariable`: **any paradigm** is a given local o global variable declared? @@ -123,6 +125,8 @@ Nice, we know. But not very awesome, it only can tell you if you are using a _bi 1. `hasRedundantReduction`: **logic paradigm** is a is-operator used to unify individuals that don't require a reduction, like `X is 4` 1. `hasTooShortBindings`: **any paradigm** whether a binding is too short and not part of domain language's jargon 1. `hasWrongCaseBindings`: **any paradigm** whether a binding does not match the domain language's case style +1. `implements`: **object oriented paradigm** is the given interface implemented? +1. `instantiates`: **object oriented paradigm** is the given class instantiated? 1. `isLongCode`: **any paradigm** has the code long sequences of statements? 1. `returnsNull` 1. `uses`: **any paradigm** is there any reference to the given element? @@ -136,14 +140,14 @@ Nice, we know. But not very awesome, it only can tell you if you are using a _bi 1. `usesForall`: **logic paradigm** is the logic `forall` consult used? 1. `usesGuards` 1. `usesIf`: **any paradigm** is an `if` control structure used? -1. `usesInheritance`: **objects paradigm** is a superclass explicitly declared? +1. `usesInheritance`: **object oriented paradigm** is a superclass explicitly declared? 1. `usesLambda` 1. `usesNot` 1. `usesPatternMatching` 1. `usesRepeat` 1. `usesSwitch` 1. `usesUnificationOperator`: **logic paradigm** is the logic unification operator `=` used? -1. `usesWhile` +1. `usesWhile`: **imperative paradigm** is a `while` control structure used? For example, let's go trickier: diff --git a/mulang.cabal b/mulang.cabal index f0908c87c..2ffce914c 100644 --- a/mulang.cabal +++ b/mulang.cabal @@ -52,6 +52,7 @@ library Language.Mulang.Parsers Language.Mulang.Parsers.Haskell Language.Mulang.Parsers.Prolog + Language.Mulang.Parsers.Java Language.Mulang.Parsers.JavaScript Language.Mulang.Analyzer Language.Mulang.Analyzer.Analysis @@ -72,6 +73,7 @@ library scientific , vector , haskell-src , + language-java , language-javascript , aeson , inflections , diff --git a/spec/ExpectationsCompilerSpec.hs b/spec/ExpectationsCompilerSpec.hs index 90e13bcb6..4c11e4b02 100644 --- a/spec/ExpectationsCompilerSpec.hs +++ b/spec/ExpectationsCompilerSpec.hs @@ -5,6 +5,7 @@ import Language.Mulang.Analyzer hiding (spec) import Language.Mulang.Analyzer.ExpectationsCompiler (compileExpectation) import Language.Mulang.Parsers.Haskell import Language.Mulang.Parsers.JavaScript +import Language.Mulang.Parsers.Java spec :: Spec spec = do @@ -166,3 +167,6 @@ spec = do it "works with UsesLambda" $ do run (hs "f 3 = 3") "f" "UsesLambda" `shouldBe` False + it "works with Implements" $ do + run (java "class Foo implements Bar {}") "Foo" "Implements:Bar" `shouldBe` True + run (java "class Foo implements Bar {}") "Foo" "Implements:Baz" `shouldBe` False diff --git a/spec/InspectorSpec.hs b/spec/InspectorSpec.hs index dc40c2b69..f0f97af93 100644 --- a/spec/InspectorSpec.hs +++ b/spec/InspectorSpec.hs @@ -4,6 +4,7 @@ import Test.Hspec import Language.Mulang import Language.Mulang.Parsers.Haskell import Language.Mulang.Parsers.JavaScript +import Language.Mulang.Parsers.Java (java) import Language.Mulang.Inspector.Generic.Smell import Data.Maybe (fromJust) @@ -199,7 +200,37 @@ spec = do it "is True when anyone present, scoped" $ do declaresObject anyone (js "var g = {}") `shouldBe` True - describe "usesInheritance" $ do + describe "declaresEnumeration" $ do + it "is True when present" $ do + declaresEnumeration (named "Direction") (Enumeration "Direction" ["SOUTH", "EAST", "WEST", "NORTH"]) `shouldBe` True + + it "is False when not present" $ do + declaresEnumeration (named "Bird") (Class "Bird" (Just "Animal") MuNull) `shouldBe` False + + describe "declaresInterface" $ do + it "is True when present" $ do + declaresInterface (named "Optional") (java "interface Optional { Object get(); }") `shouldBe` True + + it "is False when not present" $ do + declaresInterface (named "Bird") (java "class Bird extends Animal {}") `shouldBe` False + + describe "instantiates" $ do + it "is True when instantiates" $ do + instantiates (named "Bird") (java "class Main { void main(String[] args) { Animal a = new Bird(); } }") `shouldBe` True + + it "is False when not instantiates" $ do + instantiates (named "Bird") (java "class Main { void main(String[] args) { Animal a = new Mammal(); } }") `shouldBe` False + + describe "implements" $ do + it "is True when implements" $ do + implements (named "Bird") (java "class Eagle implements Bird {}") `shouldBe` True + + it "is False when implements declaration not present" $ do + implements (named "Bird") (java "class Cell {}") `shouldBe` False + + it "is False when a superinterface is declares" $ do + implements (named "Iterable") (java "interface Collection extends Iterable {}") `shouldBe` False + it "is True when present" $ do usesInheritance (Class "Bird" (Just "Animal") MuNull) `shouldBe` True @@ -219,6 +250,12 @@ spec = do it "is True when any present" $ do declaresMethod anyone (js "var f = {x: function(){}}") `shouldBe` True + it "is True when scoped in a class" $ do + scoped (declaresMethod (named "foo")) "A" (java "class A { void foo() {} }") `shouldBe` True + + it "is False when scoped in a class and not present" $ do + scoped (declaresMethod (named "foo")) "A" (java "class A { void foobar() {} }") `shouldBe` False + it "is False when not present" $ do declaresMethod (named "m") (js "var f = {x: function(){}}") `shouldBe` False diff --git a/spec/JavaSpec.hs b/spec/JavaSpec.hs new file mode 100644 index 000000000..5699089f1 --- /dev/null +++ b/spec/JavaSpec.hs @@ -0,0 +1,196 @@ +{-# LANGUAGE QuasiQuotes, OverloadedStrings #-} + +module JavaSpec (spec) where + +import Test.Hspec +import Language.Mulang +import Language.Mulang.Parsers.Java + +import Data.Text (Text, unpack) +import NeatInterpolation (text) + +run :: Text -> Expression +run = java . unpack + + +spec :: Spec +spec = do + describe "parse" $ do + it "parses Simple Class" $ do + run "public class Foo {}" `shouldBe` Class "Foo" Nothing MuNull + + it "parsers Class With Superclass" $ do + run "public class Foo extends Bar {}" `shouldBe` Class "Foo" (Just "Bar") MuNull + + it "parses Simple Interface" $ do + run "public interface Foo {}" `shouldBe` Interface "Foo" [] MuNull + + it "parses Simple Interface With Messages" $ do + run "public interface Foo { void foo(); }" `shouldBe` Interface "Foo" [] (TypeSignature "foo" [] "void") + + it "parses Simple Interface With Messages With Params" $ do + run "public interface Foo { void foo(String x, int y); }" `shouldBe` Interface "Foo" [] (TypeSignature "foo" ["String", "int"] "void") + + + it "parses Interface with superinterfaces" $ do + run "public interface Foo extends Bar, Baz {}" `shouldBe` Interface "Foo" ["Bar", "Baz"] MuNull + + it "parses Class With Methods" $ do + run [text| + class Foo { + public void hello() {} + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] MuNull) + + it "parses Empty Returns" $ do + run [text|class Foo { + public void hello() { return; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return MuNull)) + + it "parses Strings In Returns" $ do + run [text|class Foo { + public String hello() { return "hello"; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return (MuString "hello"))) + + it "parses Int In Returns" $ do + run [text|class Foo { + public int hello() { return 1; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return (MuNumber 1))) + + it "parses Double In Returns" $ do + run [text|class Foo { + public double hello() { return 453.2; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return (MuNumber 453.2))) + + it "parses Bools In Returns" $ do + run [text|class Foo { + public boolean hello() { return true; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return MuTrue)) + + it "parses Negation In Returns" $ do + run [text|class Foo { + public boolean hello() { return !true; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return (SimpleSend MuTrue "!" []))) + + it "parses Chars In Returns" $ do + run [text|class Foo { + public char hello() { return 'f'; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Return (MuString "f"))) + + it "parses Parameters" $ do + run "public class Foo extends Bar { int succ(int y) {} }" `shouldBe` Class "Foo" (Just "Bar") (SimpleMethod "succ" [VariablePattern "y"] MuNull) + + it "parses Enums" $ do + run "public enum Foo { A, B }" `shouldBe` Enumeration "Foo" ["A", "B"] + + it "parsesMain" $ do + run [text| + public class MyMain { + public static void main(String[] args) { } + }|] `shouldBe` Class "MyMain" Nothing (EntryPoint "main" MuNull) + + it "parses Variables And Ints" $ do + run [text| + class Foo { + public void hello() { int x = 1; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Variable "x" (MuNumber 1))) + + it "parses Variables And Ints" $ do + run [text| + class Foo { + public void hello() { Foo x = this; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Variable "x" Self)) + + it "parses Variables And ternaries" $ do + run [text| + class Foo { + public void hello() { Foo x = true ? this : this; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Variable "x" (If MuTrue Self Self))) + + it "parses Variables without initialization" $ do + run [text| + class Foo { + public void hello() { int x; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (Variable "x" MuNull)) + + it "parses self-send" $ do + run [text| + class Foo { + public void hello() { f(); } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (SimpleSend Self "f" [])) + + it "parses self-send" $ do + run [text| + class Foo { + public void hello() { f(2); } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (SimpleSend Self "f" [MuNumber 2])) + + it "parses explict self-send" $ do + run [text| + class Foo { + public void hello() { this.f(); } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (SimpleSend Self "f" [])) + + it "parses argument-send" $ do + run [text| + class Foo { + public void hello(String g) { g.toString(); } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [VariablePattern "g"] (SimpleSend (Reference "g") "toString" [])) + + it "parses expression-send" $ do + run [text| + class Foo { + public void hello(String g) { g.size().toString(); } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [VariablePattern "g"] (SimpleSend (SimpleSend (Reference "g") "size" []) "toString" [])) + + + it "parses Ifs with empty braces" $ do + run [text| + class Foo { + public void hello() { if (true) { } } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (If MuTrue MuNull MuNull)) + + it "parses Ifs with return in braces" $ do + run [text| + class Foo { + public void hello() { if (true) { return true; } else { return false; } } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] (If MuTrue (Return MuTrue) (Return MuFalse))) + + it "parses Ifs with equal comparisons on conditions" $ do + run [text| + class Foo { + public void hello(String x) { if (x == "foo") { } } + }|] `shouldBe` Class "Foo" Nothing ( + SimpleMethod "hello" [VariablePattern "x"] ( + If (Send (Reference "x") Equal [MuString "foo"]) + MuNull + MuNull)) + + it "parses Ifs with not-equal comparisons on conditions" $ do + run [text| + class Foo { + public void hello(String x) { if (x != "foo") { } } + }|] `shouldBe` Class "Foo" Nothing ( + SimpleMethod "hello" [VariablePattern "x"] ( + If (Send (Reference "x") NotEqual [MuString "foo"]) + MuNull + MuNull)) + + it "parsesAssignmentsAndDoubles" $ do + run [text|class Foo { + public void hello() { double m = 1.0; m = 3.4; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] ( + Sequence [ + Variable "m" (MuNumber 1.0), + Assignment "m" (MuNumber 3.4)])) + + it "parses Lambdas" $ do + run [text|class Foo { + public Object hello() { return (int x) -> x + 1; } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] ( + Return (Lambda [VariablePattern "x"] (SimpleSend (Reference "x") "+" [MuNumber 1])))) + + it "parses News" $ do + run [text|class Foo { + public Foo hello() { return new Bar(3); } + }|] `shouldBe` Class "Foo" Nothing (SimpleMethod "hello" [] ( + Return (New "Bar" [MuNumber 3]))) diff --git a/spec/SignatureSpec.hs b/spec/SignatureSpec.hs index d8c8468b9..c063360de 100644 --- a/spec/SignatureSpec.hs +++ b/spec/SignatureSpec.hs @@ -45,13 +45,13 @@ spec = do describe "TypedSignature" $ do it "simple variable type declaration" $ do - signaturesOf (hs "foo :: Int") `shouldBe` [TypedSignature "foo" ["Int"]] + signaturesOf (hs "foo :: Int") `shouldBe` [TypedSignature "foo" [] "Int"] it "simple function type declaration" $ do - signaturesOf (hs "foo :: Int -> Int") `shouldBe` [TypedSignature "foo" ["Int", "Int"]] + signaturesOf (hs "foo :: Int -> Int") `shouldBe` [TypedSignature "foo" ["Int"] "Int"] it "simple function tuple declaration" $ do - signaturesOf (hs "foo :: b -> (Int, [a])") `shouldBe` [TypedSignature "foo" ["b", "(Int, [a])"]] + signaturesOf (hs "foo :: b -> (Int, [a])") `shouldBe` [TypedSignature "foo" ["b"] "(Int, [a])"] describe "NamedSignature" $ do it "empty expression" $ do diff --git a/spec/SignaturesAnalyzerSpec.hs b/spec/SignaturesAnalyzerSpec.hs index fc40f43b8..05ae33e94 100644 --- a/spec/SignaturesAnalyzerSpec.hs +++ b/spec/SignaturesAnalyzerSpec.hs @@ -10,6 +10,7 @@ run language content style = analyse (signaturesAnalysis (CodeSample language co spec = describe "SignturesAnalyzer" $ do it "handles MulangStyle" $ do (run Haskell "f x = x + 1" MulangStyle ) `shouldReturn` (result ["-- f(x)"]) + (run Haskell "f :: Int -> String" MulangStyle ) `shouldReturn` (result ["-- f(Int): String"]) it "handles HaskellStyle" $ do (run Haskell "f x = x + 1" HaskellStyle ) `shouldReturn` (result ["-- f x"]) diff --git a/src/Language/Mulang/Analyzer/Analysis.hs b/src/Language/Mulang/Analyzer/Analysis.hs index ace850c02..d710f7b8a 100644 --- a/src/Language/Mulang/Analyzer/Analysis.hs +++ b/src/Language/Mulang/Analyzer/Analysis.hs @@ -100,6 +100,7 @@ data Sample data Language = Json + | Java | JavaScript | Prolog | Haskell deriving (Show, Eq, Generic) diff --git a/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs b/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs index b9e6d8894..06f31326c 100644 --- a/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs +++ b/src/Language/Mulang/Analyzer/ExpectationsCompiler.hs @@ -64,8 +64,10 @@ compileInspectionPrimitive = f f "DeclaresComputationWithArity4" = binded (declaresComputationWithArity 4) f "DeclaresComputationWithArity5" = binded (declaresComputationWithArity 5) f "DeclaresEntryPoint" = binded declaresEntryPoint + f "DeclaresEnumeration" = binded declaresEnumeration f "DeclaresFact" = binded declaresFact f "DeclaresFunction" = binded declaresFunction + f "DeclaresInterface" = binded declaresInterface f "DeclaresMethod" = binded declaresMethod f "DeclaresObject" = binded declaresObject f "DeclaresPredicate" = binded declaresPredicate @@ -76,6 +78,8 @@ compileInspectionPrimitive = f f "DeclaresTypeAlias" = binded declaresTypeAlias f "DeclaresTypeSignature" = binded declaresTypeSignature f "DeclaresVariable" = binded declaresVariable + f "Implements" = binded implements + f "Instantiates" = binded instantiates f "Uses" = binded uses f "UsesAnonymousVariable" = simple usesAnonymousVariable f "UsesComposition" = simple usesComposition diff --git a/src/Language/Mulang/Analyzer/SampleParser.hs b/src/Language/Mulang/Analyzer/SampleParser.hs index c78cd0c87..b4c220635 100644 --- a/src/Language/Mulang/Analyzer/SampleParser.hs +++ b/src/Language/Mulang/Analyzer/SampleParser.hs @@ -6,6 +6,7 @@ import Language.Mulang.Parsers (MaybeParser) import Language.Mulang.Parsers.Haskell import Language.Mulang.Parsers.JavaScript (parseJavaScript) import Language.Mulang.Parsers.Prolog (parseProlog) +import Language.Mulang.Parsers.Java (parseJava) import Language.Mulang.Analyzer.Analysis (Sample(..), Language(..)) parseSample :: Sample -> Maybe Expression @@ -14,5 +15,6 @@ parseSample (MulangSample ast) = Just ast parserFor :: Language -> MaybeParser parserFor Haskell = parseHaskell +parserFor Java = parseJava parserFor JavaScript = parseJavaScript parserFor Prolog = parseProlog diff --git a/src/Language/Mulang/Ast.hs b/src/Language/Mulang/Ast.hs index e93a2648b..077193702 100644 --- a/src/Language/Mulang/Ast.hs +++ b/src/Language/Mulang/Ast.hs @@ -24,6 +24,7 @@ module Language.Mulang.Ast ( pattern SimpleFunction, pattern SimpleProcedure, pattern SimpleMethod, + pattern SimpleSend, pattern MuTrue, pattern MuFalse, pattern Subroutine, @@ -61,9 +62,9 @@ data Expression | Record Identifier -- ^ Imperative / Functional programming struct declaration. -- Only the record name is parsed - | TypeSignature Identifier [Identifier] - -- ^ Generic type signature for a computation. - -- Only the target name of the computation is parsed + | TypeSignature Identifier [Identifier] Identifier + -- ^ Generic type signature for a computation, + -- composed by a name, parameter types and return type | EntryPoint Identifier Expression -- ^ Entry point with its body | Function Identifier [Equation] @@ -81,7 +82,12 @@ data Expression -- composed by a name and a body | Class Identifier (Maybe Identifier) Expression -- ^ Object oriented programming global, class declaration, - -- composed by a name, superclass and a body + -- composed by a name, an optional superclass, implemented interfaces and a body + | Enumeration Identifier [Identifier] + -- ^ Imperative named enumeration of values + | Interface Identifier [Identifier] Expression + -- ^ Object oriented programming global interface or contract declaration, + -- composed by a name, superinterfaces and a body | Rule Identifier [Pattern] [Expression] -- ^ Logic programming declaration of a fact, composed by the rue name, rule arguments, and rule body | Fact Identifier [Pattern] @@ -100,6 +106,12 @@ data Expression -- ^ Generic, non-curried application of a function or procedure, composed by the applied element itself, and the application arguments | Send Expression Expression [Expression] -- ^ Object oriented programming message send, composed by the reciever, selector and arguments + | New Identifier [Expression] + -- ^ Object oriented instantiation, composed by the class reference and instantiation arguments + | Implement Identifier + -- ^ Object oriented instantiation, interface implementation + | Include Identifier + -- ^ Object oriented instantiation, mixin inclusion | Lambda [Pattern] Expression | If Expression Expression Expression | Return Expression @@ -167,6 +179,8 @@ data ComprehensionStatement pattern SimpleEquation params body = Equation params (UnguardedBody body) +pattern SimpleSend receptor selector args = Send receptor (Reference selector) args + pattern SimpleFunction name params body = Function name [SimpleEquation params body] pattern SimpleProcedure name params body = Procedure name [SimpleEquation params body] pattern SimpleMethod name params body = Method name [SimpleEquation params body] diff --git a/src/Language/Mulang/Builder.hs b/src/Language/Mulang/Builder.hs index 2a5d78293..cb637eb23 100644 --- a/src/Language/Mulang/Builder.hs +++ b/src/Language/Mulang/Builder.hs @@ -1,7 +1,13 @@ -module Language.Mulang.Builder (compact, normalize) where +module Language.Mulang.Builder (compact, compactMap, compactConcatMap, normalize) where import Language.Mulang.Ast +compactConcatMap :: (a -> [Expression]) -> [a] -> Expression +compactConcatMap f = compact . concat . map f + +compactMap :: (a -> Expression) -> [a] -> Expression +compactMap f = compact . map f + compact :: [Expression] -> Expression compact [] = MuNull compact [e] = e @@ -35,8 +41,6 @@ normalize (MuTuple es) = MuTuple (map normalize es) normalize (MuList es) = MuList (map normalize es) normalize e = e - - normalizeInObject (Function n eqs) = Method n (map normalizeEquation eqs) normalizeInObject (Variable n (Lambda vars e)) = SimpleMethod n vars (normalize e) normalizeInObject (Variable n e) = Attribute n (normalize e) diff --git a/src/Language/Mulang/Explorer.hs b/src/Language/Mulang/Explorer.hs index 9305e0aae..e4315f5b6 100644 --- a/src/Language/Mulang/Explorer.hs +++ b/src/Language/Mulang/Explorer.hs @@ -72,13 +72,13 @@ nameOf :: Expression -> Maybe Binding nameOf = fmap fst . extractDeclaration extractReference :: Expression -> Maybe (Binding, Expression) -extractReference e@(Reference n) = Just (n, e) -extractReference e@(Exist n _) = Just (n, e) -extractReference _ = Nothing +extractReference e@(Reference n) = Just (n, e) +extractReference e@(Exist n _) = Just (n, e) +extractReference _ = Nothing extractDeclaration :: Expression -> Maybe (Binding, Expression) -extractDeclaration e@(TypeSignature n _) = Just (n, e) +extractDeclaration e@(TypeSignature n _ _)= Just (n, e) extractDeclaration e@(TypeAlias n ) = Just (n, e) extractDeclaration e@(Variable n _) = Just (n, e) extractDeclaration e@(Subroutine n _) = Just (n, e) @@ -86,6 +86,8 @@ extractDeclaration e@(Record n) = Just (n, e) extractDeclaration e@(Clause n _ _) = Just (n, e) extractDeclaration e@(Object n _) = Just (n, e) extractDeclaration e@(Class n _ _) = Just (n, e) +extractDeclaration e@(Interface n _ _) = Just (n, e) +extractDeclaration e@(Enumeration n _) = Just (n, e) extractDeclaration e@(Attribute n _) = Just (n, e) extractDeclaration e@(EntryPoint n _) = Just (n, e) extractDeclaration _ = Nothing diff --git a/src/Language/Mulang/Inspector/Generic.hs b/src/Language/Mulang/Inspector/Generic.hs index 9d1b0e38b..70fa9076d 100644 --- a/src/Language/Mulang/Inspector/Generic.hs +++ b/src/Language/Mulang/Inspector/Generic.hs @@ -55,8 +55,8 @@ usesIf = containsExpression f -- | Inspection that tells whether a top level binding exists declares :: BindedInspection declares = containsDeclaration f - where f (TypeSignature _ _) = False - f _ = True + where f (TypeSignature _ _ _) = False + f _ = True -- | Inspection that tells whether an expression is direct recursive declaresRecursively :: BindedInspection @@ -104,8 +104,8 @@ declaresTypeAlias = containsDeclaration f declaresTypeSignature :: BindedInspection declaresTypeSignature = containsDeclaration f - where f (TypeSignature _ _) = True - f _ = False + where f (TypeSignature _ _ _) = True + f _ = False usesAnonymousVariable :: Inspection diff --git a/src/Language/Mulang/Inspector/ObjectOriented.hs b/src/Language/Mulang/Inspector/ObjectOriented.hs index 9203e0a4d..38ac97905 100644 --- a/src/Language/Mulang/Inspector/ObjectOriented.hs +++ b/src/Language/Mulang/Inspector/ObjectOriented.hs @@ -1,8 +1,12 @@ module Language.Mulang.Inspector.ObjectOriented ( + implements, + instantiates, usesInheritance, declaresObject, declaresSuperclass, declaresClass, + declaresInterface, + declaresEnumeration, declaresAttribute, declaresMethod) where @@ -10,30 +14,51 @@ import Language.Mulang.Ast import Language.Mulang.Binding import Language.Mulang.Inspector.Generic +implements :: BindedInspection +implements predicate = containsExpression f + where f (Implement name) = predicate name + f _ = False + +instantiates :: BindedInspection +instantiates predicate = containsExpression f + where f (New name _) = predicate name + f _ = False + + usesInheritance :: Inspection usesInheritance = declaresSuperclass anyone -declaresObject :: BindingPredicate -> Inspection +declaresObject :: BindedInspection declaresObject = containsDeclaration f where f (Object _ _) = True f _ = False -declaresSuperclass :: BindingPredicate -> Inspection +declaresSuperclass :: BindedInspection declaresSuperclass predicate = containsExpression f where f (Class _ (Just name) _) = predicate name f _ = False -declaresClass :: BindingPredicate -> Inspection +declaresClass :: BindedInspection declaresClass = containsDeclaration f where f (Class _ _ _) = True f _ = False -declaresAttribute :: BindingPredicate -> Inspection +declaresEnumeration :: BindedInspection +declaresEnumeration = containsDeclaration f + where f (Enumeration _ _) = True + f _ = False + +declaresInterface :: BindedInspection +declaresInterface = containsDeclaration f + where f (Interface _ _ _) = True + f _ = False + +declaresAttribute :: BindedInspection declaresAttribute = containsDeclaration f where f (Attribute _ _) = True f _ = False -declaresMethod :: BindingPredicate -> Inspection +declaresMethod :: BindedInspection declaresMethod = containsDeclaration f where f (Method _ _) = True f _ = False diff --git a/src/Language/Mulang/Parsers/Haskell.hs b/src/Language/Mulang/Parsers/Haskell.hs index 8e4da45ca..b5a750dfa 100644 --- a/src/Language/Mulang/Parsers/Haskell.hs +++ b/src/Language/Mulang/Parsers/Haskell.hs @@ -31,7 +31,7 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls) muDecls (HsTypeDecl _ name _ _) = [TypeAlias (muName name)] muDecls (HsDataDecl _ _ name _ _ _ ) = [Record (muName name)] - muDecls (HsTypeSig _ names (HsQualType _ t)) = map (\name -> TypeSignature (muName name) (muTopType t)) names + muDecls (HsTypeSig _ names (HsQualType _ t)) = map (muTypeSignature t) names muDecls (HsFunBind equations) | (HsMatch _ name _ _ _) <- head equations = [Function (muName name) (map muEquation equations)] muDecls (HsPatBind _ (HsPVar name) (HsUnGuardedRhs exp) _) = [Variable (muName name) (muExp exp)] @@ -118,9 +118,11 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls) muStmt (HsGenerator _ pat exp) = MuGenerator (muPat pat) (muExp exp) muStmt (HsQualifier exp) = MuQualifier (muExp exp) + muTypeSignature t name = TypeSignature (muName name) (init topTypes) (last topTypes) + where topTypes = muTopTypes t - muTopType (HsTyFun i o) = muType i : muTopType o - muTopType t = [muType t] + muTopTypes (HsTyFun i o) = muType i : muTopTypes o + muTopTypes t = [muType t] muType (HsTyFun i o) = muType i ++ " -> " ++ muType o muType (HsTyCon name) = muQName name @@ -128,3 +130,4 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls) muType (HsTyTuple ts) = "(" ++ (intercalate ", " . map muType $ ts) ++ ")" muType (HsTyApp (HsTyCon (Special HsListCon)) t2) = "[" ++ muType t2 ++ "]" muType (HsTyApp t1 t2) = muType t1 ++ " " ++ muType t2 + diff --git a/src/Language/Mulang/Parsers/Java.hs b/src/Language/Mulang/Parsers/Java.hs new file mode 100644 index 000000000..ce068d0ef --- /dev/null +++ b/src/Language/Mulang/Parsers/Java.hs @@ -0,0 +1,167 @@ +{-# LANGUAGE ViewPatterns #-} + + +module Language.Mulang.Parsers.Java (java, parseJava) where + +import Language.Mulang.Ast hiding (While, Return, Equal, Lambda) +import qualified Language.Mulang.Ast as M (Expression(While, Return, Equal, Lambda)) +import Language.Mulang.Parsers +import Language.Mulang.Builder (compact, compactMap, compactConcatMap) + +import Language.Java.Parser +import Language.Java.Syntax + +import Control.Fallible + +import Data.Maybe (fromMaybe) +import Data.List (intercalate) +import Data.Char (toLower) + +java :: Parser +java = orFail . parseJava' + +parseJava :: MaybeParser +parseJava = orNothing . parseJava' + +parseJava' = fmap m . j + +m (CompilationUnit _ _ typeDecls) = compactMap muTypeDecl $ typeDecls + +muTypeDecl (ClassTypeDecl decl) = muClassTypeDecl decl +muTypeDecl (InterfaceTypeDecl decl) = muInterfaceTypeDecl decl + +muClassTypeDecl (ClassDecl _ name _ superclass interfaces (ClassBody body)) = + Class (i name) (fmap muRefType superclass) (compact (map muImplements interfaces ++ map muDecl body)) +muClassTypeDecl (EnumDecl _ name _ (EnumBody constants _)) = + Enumeration (i name) (map muEnumConstant constants) + +muImplements interface = Implement $ muRefType interface + +muInterfaceTypeDecl (InterfaceDecl _ name _ interfaces (InterfaceBody body)) = + Interface (i name) (map muRefType interfaces) (compactMap muMemberDecl body ) + +muDecl (MemberDecl memberDecl) = muMemberDecl memberDecl +muDecl (InitDecl _ _) = Other + +muMemberDecl (FieldDecl _ _type _varDecls) = Other +muMemberDecl (MethodDecl _ _ _ name params _ (MethodBody Nothing)) = TypeSignature (i name) (map muFormalParamType params) "void" +muMemberDecl (MethodDecl (elem Static -> True) _ _ (Ident "main") [_] _ body) = EntryPoint "main" (muMethodBody body) +muMemberDecl (MethodDecl _ _ _ name params _ body) = SimpleMethod (i name) (map muFormalParam params) (muMethodBody body) +muMemberDecl (ConstructorDecl _ _ _ _params _ _constructorBody) = Other +muMemberDecl (MemberClassDecl decl) = muClassTypeDecl decl +muMemberDecl (MemberInterfaceDecl decl) = muInterfaceTypeDecl decl + +muEnumConstant (EnumConstant name _ _) = i name + +muFormalParam (FormalParam _ _ _ id) = VariablePattern (v id) +muFormalParamType (FormalParam _ typ _ _) = (muType typ) + +muBlock (Block statements) = compactConcatMap muBlockStmt statements + +muBlockStmt (BlockStmt stmt) = [muStmt stmt] +muBlockStmt (LocalClass decl) = [muClassTypeDecl decl] +muBlockStmt (LocalVars _ _type vars) = map muVarDecl vars + +muType (PrimType t) = muPrimType t +muType (RefType t) = muRefType t + +muStmt (StmtBlock block) = muBlock block +muStmt (IfThen exp ifTrue) = If (muExp exp) (muStmt ifTrue) MuNull +muStmt (IfThenElse exp ifTrue ifFalse) = If (muExp exp) (muStmt ifTrue) (muStmt ifFalse) +muStmt (While cond body) = M.While (muExp cond) (muStmt body) +muStmt (Return exp) = M.Return $ fmapOrNull muExp exp +muStmt (ExpStmt exp) = muExp exp +muStmt Empty = MuNull +muStmt (Assert exp _) = SimpleSend Self "assert" [muExp exp] +muStmt (Synchronized _ block) = muBlock block +muStmt (Labeled _ stmt) = muStmt stmt +--muStmt (EnhancedFor _ _ name gen body) = Other +--Throw Exp +--Try Block [Catch] (Maybe Block) +--Switch Exp [SwitchBlock] +muStmt _ = Other + +muExp (Lit lit) = muLit lit +muExp (MethodInv invoke) = muMethodInvocation invoke +muExp This = Self +muExp (BinOp arg1 op arg2) = Send (muExp arg1) (muOp op) [muExp arg2] +muExp (Cond cond ifTrue ifFalse) = If (muExp cond) (muExp ifTrue) (muExp ifFalse) +muExp (ExpName name) = muName name +muExp (Assign lhs EqualA exp) = Assignment (muLhs lhs) (muExp exp) +muExp (InstanceCreation _ clazz args _) = New (r clazz) (map muExp args) +muExp (PreNot exp) = SimpleSend (muExp exp) "!" [] +muExp (Lambda params exp) = M.Lambda (muLambdaParams params) (muLambdaExp exp) +muExp (MethodRef _ message) = M.Lambda [VariablePattern "it"] (SimpleSend (Reference "it") (i message) []) +muExp _ = Other + +muLambdaExp (LambdaExpression exp) = muExp exp +muLambdaExp (LambdaBlock block) = muBlock block + +muLambdaParams (LambdaSingleParam name) = [VariablePattern (i name)] +muLambdaParams (LambdaInferredParams names) = map (VariablePattern . i) names +muLambdaParams (LambdaFormalParams params) = map muFormalParam params + +muLhs (NameLhs (Name names)) = ns names + +muName (Name names) = Reference . ns $ names + +muLit (String s) = MuString s +muLit (Char c) = MuString [c] +muLit (Int i) = MuNumber (fromIntegral i) +muLit (Float d) = MuNumber d +muLit (Double d) = MuNumber d +muLit (Boolean b) = MuBool b +muLit Null = MuNull +muLit _ = Other + +muOp Mult = Reference "*" +muOp Div = Reference "/" +muOp Rem = Reference "rem" +muOp Add = Reference "+" +muOp Sub = Reference "-" +muOp LThan = Reference "<" +muOp LThanE = Reference "<=" +muOp GThan = Reference ">" +muOp GThanE = Reference ">=" +muOp And = Reference "&&" +muOp Or = Reference "||" +muOp Equal = M.Equal +muOp NotEq = NotEqual +muOp _ = Other + +muVarDecl (VarDecl id init) = Variable (v id) (fmapOrNull muVarInit init) + +muMethodBody (MethodBody (Just block)) = muBlock block + +muVarInit (InitExp exp) = muExp exp +muVarInit (InitArray _ArrayInit) = Other + +muMethodInvocation (MethodCall (Name [message]) args) = SimpleSend Self (i message) (map muExp args) +muMethodInvocation (MethodCall (Name (receptor:message)) args) = SimpleSend (Reference (i receptor)) (ns message) (map muExp args) +muMethodInvocation (PrimaryMethodCall receptor _ selector args) = SimpleSend (muExp receptor) (i selector) (map muExp args) +muMethodInvocation _ = Other + +muRefType (ClassRefType clazz) = r clazz +muRefType (ArrayType t) = (muType t) ++ "[]" + +muPrimType = map toLower . dropLast 1 . show + +-- Combinators + +fmapOrNull f = fromMaybe MuNull . fmap f + +-- Helpers + +v (VarId name) = i name +v (VarDeclArray id) = (v id) ++ "[]" + +i (Ident name) = name +r (ClassType [(name, _)]) = i name + +j = parser compilationUnit + +ns = intercalate "." . map i + +-- list helpers + +dropLast n xs = take (length xs - n) xs diff --git a/src/Language/Mulang/Signature.hs b/src/Language/Mulang/Signature.hs index ca1ed9678..c5ce37fc3 100644 --- a/src/Language/Mulang/Signature.hs +++ b/src/Language/Mulang/Signature.hs @@ -27,37 +27,37 @@ import Data.Function (on) type SignatureStyle = [Signature] -> [String] data Signature = AritySignature Binding Int - | TypedSignature Binding [Binding] + | TypedSignature Binding [Binding] Binding | NamedSignature Binding [Maybe Binding] deriving (Show, Eq) arity :: Signature -> Int -arity (AritySignature _ a) = a -arity (TypedSignature _ ps) = length ps -arity (NamedSignature _ ps) = length ps +arity (AritySignature _ a) = a +arity (TypedSignature _ ps _) = length ps +arity (NamedSignature _ ps) = length ps name :: Signature -> Binding -name (AritySignature n _) = n -name (TypedSignature n _) = n -name (NamedSignature n _) = n +name (AritySignature n _) = n +name (TypedSignature n _ _) = n +name (NamedSignature n _) = n nameAndArity :: Signature -> (Binding, Int) nameAndArity signature = (name signature, arity signature) parameterNames :: Signature -> [Maybe Binding] -parameterNames (AritySignature _ arity) = replicate arity Nothing -parameterNames (TypedSignature _ types) = map (const Nothing) types -parameterNames (NamedSignature _ names) = names +parameterNames (AritySignature _ arity) = replicate arity Nothing +parameterNames (TypedSignature _ types _) = map (const Nothing) types +parameterNames (NamedSignature _ names) = names signaturesOf :: Expression -> [Signature] signaturesOf = nub . mapMaybe (signatureOf.snd) . declarationsOf mainExpressions signatureOf :: Expression -> Maybe Signature -signatureOf (Subroutine name es) = Just $ NamedSignature name (parameterNamesOf es) -signatureOf (Clause name args _) = Just $ AritySignature name (length args) -signatureOf (TypeSignature name args) = Just $ TypedSignature name args -signatureOf (Variable name _) = Just $ AritySignature name 0 -signatureOf _ = Nothing +signatureOf (Subroutine name es) = Just $ NamedSignature name (parameterNamesOf es) +signatureOf (Clause name args _) = Just $ AritySignature name (length args) +signatureOf (TypeSignature name args ret) = Just $ TypedSignature name args ret +signatureOf (Variable name _) = Just $ AritySignature name 0 +signatureOf _ = Nothing parameterNamesOf :: [Equation] -> [Maybe Binding] parameterNamesOf = map msum . transpose . map (map parameterNameOf . equationParams) @@ -77,9 +77,9 @@ styledCodeSignaturesOf style = style . signaturesOf mulangStyle :: SignatureStyle mulangStyle = makeLines "--" (return.s) where s :: Signature -> String - s (AritySignature name arity) = name ++ "/" ++ show arity - s (NamedSignature name names) = name ++ "(" ++ (intercalate ", " . makeParamNames $ names) ++ ")" - s (TypedSignature name types) = name ++ " :: " ++ (intercalate " -> " types) + s (AritySignature name arity) = name ++ "/" ++ show arity + s (NamedSignature name names) = name ++ "(" ++ (intercalate ", " . makeParamNames $ names) ++ ")" + s (TypedSignature name types ret) = name ++ "(" ++ (intercalate ", " types) ++ "): " ++ ret untypedCStyle :: SignatureStyle untypedCStyle = makeLines "//" s @@ -89,10 +89,10 @@ untypedCStyle = makeLines "//" s haskellStyle :: SignatureStyle haskellStyle = groupAndMakeLinesOn "--" name s - where s (NamedSignature name names) = Just $ name ++ " " ++ (intercalate " " . makeParamNames $ names) - s (TypedSignature name types) = Just $ name ++ " :: " ++ (intercalate " -> " types) - s (AritySignature name 0) = Just name - s _ = Nothing + where s (NamedSignature name names) = Just $ name ++ " " ++ (intercalate " " . makeParamNames $ names) + s (TypedSignature name types ret) = Just $ name ++ " :: " ++ (intercalate " -> " (types ++ [ret])) + s (AritySignature name 0) = Just name + s _ = Nothing prologStyle :: SignatureStyle prologStyle = groupAndMakeLinesOn "%%" nameAndArity s diff --git a/src/Language/Mulang/Unfold.hs b/src/Language/Mulang/Unfold.hs index fedd94b34..ec53ac238 100644 --- a/src/Language/Mulang/Unfold.hs +++ b/src/Language/Mulang/Unfold.hs @@ -19,6 +19,7 @@ allExpressions expr = expr : concatMap allExpressions (subExpressions expr) subExpressions (Attribute _ v) = [v] subExpressions (Object _ v) = [v] subExpressions (Class _ _ v) = [v] + subExpressions (Interface _ _ v) = [v] subExpressions (EntryPoint _ e) = [e] subExpressions (Call op args) = op:args subExpressions (Lambda _ a) = [a] @@ -44,8 +45,9 @@ allExpressions expr = expr : concatMap allExpressions (subExpressions expr) mainExpressions :: Unfold mainExpressions o@(Object _ b) = o : mainExpressions b mainExpressions c@(Class _ _ b) = c : mainExpressions b +mainExpressions c@(Interface _ _ b) = c : mainExpressions b mainExpressions e@(EntryPoint _ b) = e : mainExpressions b -mainExpressions t@(TypeSignature _ _) = [t] +mainExpressions t@(TypeSignature _ _ _)= [t] mainExpressions t@(TypeAlias _ ) = [t] mainExpressions r@(Record _) = [r] mainExpressions v@(Variable _ _) = [v]