Skip to content

Commit

Permalink
Merge pull request #52 from exercism/jie-tracks-on-tracks-on-tracks
Browse files Browse the repository at this point in the history
Add analysis for `tracks-on-tracks-on-tracks`
  • Loading branch information
jiegillet authored Nov 14, 2022
2 parents 128fb78 + 68a0b70 commit 5750bea
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 18 deletions.
48 changes: 30 additions & 18 deletions src/Analyzer.elm
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ Note that for searching for function that are automatically imported, like `roun
`CaseBlock` means looking for a `case` expression.
`Operator "::"` means we are looking for the operator either applied `head :: tail` or standalone `List.map2 (::)`.
-}



-- TODO: also search for operators, if, or any expression?
-- TODO: also search for if, or any expression?


type CalledFunction
Expand All @@ -54,6 +56,7 @@ type CalledFunction
| FromSameModule FunctionName
| LetBlock
| CaseBlock
| Operator FunctionName


{-| Type of search.
Expand Down Expand Up @@ -177,40 +180,43 @@ annotateFunctionDeclaration calledFrom node (Context context) =
{-| Gather all expressions we care about from the code in a tree
-}
expressionCallsFunction : Node Expression -> Context -> ( List nothing, Context )
expressionCallsFunction (Node range expression) (Context ({ lookupTable, functionDeclaration, callTree } as context)) =
expressionCallsFunction ((Node range expression) as node) (Context ({ lookupTable, functionDeclaration, callTree } as context)) =
let
updateFunction treeExpressions =
add expr tree =
Just (expr :: Maybe.withDefault [] tree)

updateTree nodeTree =
case expression of
FunctionOrValue _ name ->
case LookupTable.moduleNameFor lookupTable (Node range expression) of
case LookupTable.moduleNameFor lookupTable node of
Nothing ->
treeExpressions
nodeTree

Just originalModuleName ->
Node range (FunctionOrValue originalModuleName name)
:: Maybe.withDefault [] treeExpressions
|> Just
add (Node range (FunctionOrValue originalModuleName name)) nodeTree

LetExpression _ ->
add node nodeTree

LetExpression block ->
Node range (LetExpression block)
:: Maybe.withDefault [] treeExpressions
|> Just
CaseExpression _ ->
add node nodeTree

CaseExpression block ->
Node range (CaseExpression block)
:: Maybe.withDefault [] treeExpressions
|> Just
OperatorApplication _ _ _ _ ->
add node nodeTree

PrefixOperator _ ->
add node nodeTree

_ ->
treeExpressions
nodeTree
in
( []
, Context
{ context
| callTree =
case functionDeclaration of
Just function ->
Dict.update function updateFunction callTree
Dict.update function updateTree callTree

Nothing ->
callTree
Expand Down Expand Up @@ -296,6 +302,12 @@ matchFunction (Node range expression) foundFunction =
( CaseExpression _, NotFound CaseBlock ) ->
FoundAt range

( OperatorApplication exprOperator _ _ _, NotFound (Operator operator) ) ->
match exprOperator operator

( PrefixOperator exprOperator, NotFound (Operator operator) ) ->
match exprOperator operator

-- already found function, or expression that doesn't match
_ ->
foundFunction
Expand Down
60 changes: 60 additions & 0 deletions src/Exercise/TracksOnTracksOnTracks.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module Exercise.TracksOnTracksOnTracks exposing (addLanguageUsesCons, countLanguagesUsesLength, excitingListUsesCase, reverseListUsesReverse, ruleConfig)

import Analyzer exposing (CalledFrom(..), CalledFunction(..), Find(..))
import Comment exposing (Comment, CommentType(..))
import Dict
import Review.Rule exposing (Rule)
import RuleConfig exposing (AnalyzerRule(..), RuleConfig)


ruleConfig : RuleConfig
ruleConfig =
{ slug = Just "tracks-on-tracks-on-tracks"
, restrictToFiles = Just [ "src/TracksOnTracksOnTracks.elm" ]
, rules =
[ CustomRule addLanguageUsesCons
(Comment "addLanguage doesn't use (::)" "elm.tracks-on-tracks-on-tracks.use_cons" Essential Dict.empty)
, CustomRule countLanguagesUsesLength
(Comment "countLanguages doesn't use List.length" "elm.tracks-on-tracks-on-tracks.use_length" Essential Dict.empty)
, CustomRule reverseListUsesReverse
(Comment "reverseList doesn't use List.reverse" "elm.tracks-on-tracks-on-tracks.use_reverse" Essential Dict.empty)
, CustomRule excitingListUsesCase
(Comment "excitingList doesn't use a case expression" "elm.tracks-on-tracks-on-tracks.use_case" Essential Dict.empty)
]
}


addLanguageUsesCons : Comment -> Rule
addLanguageUsesCons =
Analyzer.functionCalls
{ calledFrom = TopFunction "addLanguage"
, findFunctions = [ Operator "::" ]
, find = Some
}


countLanguagesUsesLength : Comment -> Rule
countLanguagesUsesLength =
Analyzer.functionCalls
{ calledFrom = TopFunction "countLanguages"
, findFunctions = [ FromExternalModule [ "List" ] "length" ]
, find = Some
}


reverseListUsesReverse : Comment -> Rule
reverseListUsesReverse =
Analyzer.functionCalls
{ calledFrom = TopFunction "reverseList"
, findFunctions = [ FromExternalModule [ "List" ] "reverse" ]
, find = Some
}


excitingListUsesCase : Comment -> Rule
excitingListUsesCase =
Analyzer.functionCalls
{ calledFrom = TopFunction "excitingList"
, findFunctions = [ CaseBlock ]
, find = Some
}
2 changes: 2 additions & 0 deletions src/ReviewConfig.elm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Exercise.BlorkemonCards
import Exercise.MariosMarvellousLasagna
import Exercise.Strain
import Exercise.TopScorers
import Exercise.TracksOnTracksOnTracks
import Review.Rule as Rule exposing (Rule)
import RuleConfig exposing (RuleConfig)

Expand All @@ -22,6 +23,7 @@ ruleConfigs =
, Exercise.TopScorers.ruleConfig
, Exercise.MariosMarvellousLasagna.ruleConfig
, Exercise.BlorkemonCards.ruleConfig
, Exercise.TracksOnTracksOnTracks.ruleConfig

-- Practice Exercises
, Exercise.Strain.ruleConfig
Expand Down
46 changes: 46 additions & 0 deletions tests/AnalyzerTest.elm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Test exposing (Test, describe, test)
import TestHelper


tests : Test
tests =
describe "AnalyzerTest tests"
[ calledFromTest, findFunctionsTest, findTest, indirectCallTest ]
Expand All @@ -26,6 +27,7 @@ allRules =
, ( "internal", [ FromSameModule "internal" ] )
, ( "let", [ LetBlock ] )
, ( "case", [ CaseBlock ] )
, ( "pipe", [ Operator "|>" ] )
, ( "Ext._ + Ext.ext", [ AnyFromExternalModule [ "Ext" ], FromExternalModule [ "Ext" ] "ext" ] )
, ( "Ext._ + internal", [ AnyFromExternalModule [ "Ext" ], FromSameModule "internal" ] )
, ( "Ext.ext + internal", [ FromExternalModule [ "Ext" ] "ext", FromSameModule "internal" ] )
Expand Down Expand Up @@ -297,6 +299,9 @@ findFunctionsTest =
caseRule =
"calling function, case, all"

pipeRule =
"calling function, pipe, all"

extExtExtRule =
"calling function, Ext._ + Ext.ext, all"

Expand Down Expand Up @@ -472,6 +477,47 @@ callingFunction param =
|> Review.Test.run (getRule caseRule)
|> Review.Test.expectErrors
[ TestHelper.createExpectedErrorUnder (quickComment caseRule) "callingFunction" ]
, test "calling pipe operator, no error" <|
\() ->
"""
module A exposing (..)
import Ext
callingFunction param =
param
|> Ext.ext
|> Ext.other
|> internal
"""
|> Review.Test.run (getRule pipeRule)
|> Review.Test.expectNoErrors
, test "calling pipe operator as prefix, no error" <|
\() ->
"""
module A exposing (..)
import Ext
callingFunction param =
(|>) param (internal >> Ext.other >> Ext.ext)
"""
|> Review.Test.run (getRule pipeRule)
|> Review.Test.expectNoErrors
, test "calling pipe operator, missing pipe" <|
\() ->
"""
module A exposing (..)
import Ext
callingFunction param =
internal (Ext.other (Ext.ext param))
-- |> foo
"""
|> Review.Test.run (getRule pipeRule)
|> Review.Test.expectErrors
[ TestHelper.createExpectedErrorUnder (quickComment pipeRule) "callingFunction" ]
, test "any function from Ext and Ext, no error" <|
\() ->
"""
Expand Down
1 change: 1 addition & 0 deletions tests/Exercise/BlorkemonCardsTest.elm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Test exposing (Test, describe, test)
import TestHelper


tests : Test
tests =
describe "BlorkemonCardsTest"
[ exemplar
Expand Down
Loading

0 comments on commit 5750bea

Please sign in to comment.