Skip to content

Commit

Permalink
ENH Add to_string() method to int/double
Browse files Browse the repository at this point in the history
Addresses #78 in one direction (int/double -> str)

Make the method machinery more general, allowing different types to
have methods with the same name (closes #81)
  • Loading branch information
luispedro committed Dec 4, 2020
1 parent 549c775 commit e29a218
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 24 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Expand Up @@ -2,6 +2,7 @@ Version 1.2.0+
* Add early check that block assignments are always to block variables
* Use ZStd compression for temporary files from preprocess()
* Correctly handle subpaths in samples for collect (fixes #141)
* Add to_string() to int and double types (partially fixes #78 & fixes #81)

Version 1.2.0 2020-07-12 by luispedro
* Add load_fastq_directory to builtin functions
Expand Down
8 changes: 7 additions & 1 deletion NGLess/BuiltinFunctions.hs
@@ -1,4 +1,4 @@
{- Copyright 2013-2018 NGLess Authors
{- Copyright 2013-2020 NGLess Authors
- License: MIT
-}
module BuiltinFunctions
Expand Down Expand Up @@ -159,6 +159,12 @@ builtinMethods =
,MethodInfo (MethodName "avg_quality") NGLRead Nothing NGLDouble [] True []
,MethodInfo (MethodName "fraction_at_least") NGLRead (Just NGLInteger) NGLDouble [] True []
,MethodInfo (MethodName "n_to_zero_quality") NGLRead Nothing NGLRead [] True [FunctionCheckMinNGLessVersion (0,8)]

-- NGLDouble
,MethodInfo (MethodName "to_string") NGLDouble Nothing NGLString [] True []

-- NGLInteger
,MethodInfo (MethodName "to_string") NGLInteger Nothing NGLString [] True []
]

filterArgs =
Expand Down
2 changes: 2 additions & 0 deletions NGLess/Interpret.hs
Expand Up @@ -516,6 +516,8 @@ executePreprocess v _ _ = unreachable ("executePreprocess: Cannot handle this in
executeMethod :: MethodName -> NGLessObject -> Maybe NGLessObject -> [(T.Text, NGLessObject)] -> InterpretationROEnv NGLessObject
executeMethod method (NGOMappedRead samline) arg kwargs = runNGLess (executeMappedReadMethod method samline arg kwargs)
executeMethod method (NGOShortRead sr) arg kwargs = runNGLess (executeShortReadsMethod method sr arg kwargs)
executeMethod (MethodName "to_string") (NGODouble val) _ _ = return . NGOString . T.pack . show $ val
executeMethod (MethodName "to_string") (NGOInteger val) _ _ = return . NGOString . T.pack . show $ val
executeMethod m self arg kwargs = throwShouldNotOccur ("Method " ++ show m ++ " with self="++show self ++ " arg="++ show arg ++ " kwargs="++show kwargs ++ " is not implemented")


Expand Down
53 changes: 30 additions & 23 deletions NGLess/Types.hs
Expand Up @@ -140,7 +140,7 @@ check_assignment a b = when (a /= b)

nglTypeOf :: Expression -> TypeMSt (Maybe NGLType)
nglTypeOf (FunctionCall f arg args b) = inferBlock f b *> checkFuncKwArgs f args *> checkFuncUnnamed f arg
nglTypeOf (MethodCall m self arg args) = checkmethodargs m args *> checkmethodcall m self arg
nglTypeOf (MethodCall m self arg args) = checkmethodcall m self arg args
nglTypeOf (Lookup mt (Variable v)) = envLookup mt v
nglTypeOf (BuiltinConstant (Variable v)) = return (typeOfConstant v)
nglTypeOf (ConstStr _) = return (Just NGLString)
Expand Down Expand Up @@ -286,15 +286,24 @@ funcInfo fn = do
errorInLineC ["Too many matches for function '", show fn, "'"]
cannotContinue

findMethodInfo :: MethodName -> TypeMSt MethodInfo
findMethodInfo m = case filter ((==m) . methodName) builtinMethods of
[mi] -> return mi
_ -> do
errorInLineC
["Cannot find method `", T.unpack (unwrapMethodName m), "`. "
,T.unpack $ suggestionMessage (unwrapMethodName m) ((unwrapMethodName . methodName) <$> builtinMethods)
]
cannotContinue
findMethodInfo :: MethodName -> Expression -> TypeMSt MethodInfo
findMethodInfo m self = case filter ((==m) . methodName) builtinMethods of
[mi] -> return mi
ms@(_:_) -> nglTypeOf self >>= \case
Nothing -> do
errorInLineC ["Cannot disambiguate method `", T.unpack (unwrapMethodName m), "` as it is called on an expression of unknown type (", show self, ")."]
cannotContinue
Just selfType -> case filter (\mi -> methodSelfType mi == selfType) ms of
[mi] -> return mi
_ -> do
errorInLineC ["Cannot disambiguate method `", T.unpack (unwrapMethodName m), "` as it was called on an unsupported type"]
cannotContinue
_ -> do
errorInLineC
["Cannot find method `", T.unpack (unwrapMethodName m), "`. "
,T.unpack $ suggestionMessage (unwrapMethodName m) ((unwrapMethodName . methodName) <$> builtinMethods)
]
cannotContinue

checkFuncUnnamed :: FuncName -> Expression -> TypeMSt (Maybe NGLType)
checkFuncUnnamed f arg = do
Expand Down Expand Up @@ -349,9 +358,9 @@ requireType def_t e = nglTypeOf e >>= \case
return def_t
Just t -> return t

checkmethodcall :: MethodName -> Expression -> Maybe Expression -> TypeMSt (Maybe NGLType)
checkmethodcall m self arg = do
minfo <- findMethodInfo m
checkmethodcall :: MethodName -> Expression -> Maybe Expression -> [(Variable, Expression)] -> TypeMSt (Maybe NGLType)
checkmethodcall m self arg args = do
minfo <- findMethodInfo m self
let reqSelfType = methodSelfType minfo
reqArgType = methodArgType minfo
stype <- requireType reqSelfType self
Expand All @@ -364,17 +373,15 @@ checkmethodcall m self arg = do
(Just _, Nothing) -> errorInLineC ["Method ", show m, " does not take any unnamed argument (saw ", show arg, ")"]
(Just t, Just t') -> when (t /= t') (errorInLineC
["Method ", show m, " expects type ", show t', " got ", show t])
return . Just . methodReturnType $ minfo

checkmethodargs :: MethodName -> [(Variable, Expression)] -> TypeMSt ()
checkmethodargs m args = do
ainfo <- methodKwargsInfo <$> findMethodInfo m
forM_ args (check1arg (concat ["method '", show m, "'"]) ainfo)
forM_ (filter argRequired ainfo) $ \ai ->
case filter (\(Variable v,_) -> v == argName ai) args of
[_] -> return ()
[] -> errorInLineC ["Required argument ", T.unpack (argName ai), " is missing in method call ", show m, "."]
_ -> error "This should never happen: multiple arguments with the same name should have been caught before"
let ainfo = methodKwargsInfo minfo
forM_ args (check1arg (concat ["method '", show m, "'"]) ainfo)
forM_ (filter argRequired ainfo) $ \ai ->
case filter (\(Variable v,_) -> v == argName ai) args of
[_] -> return ()
[] -> errorInLineC ["Required argument ", T.unpack (argName ai), " is missing in method call ", show m, "."]
_ -> error "This should never happen: multiple arguments with the same name should have been caught before"
return . Just . methodReturnType $ minfo

addTypes :: TypeMap -> [(Int, Expression)] -> NGLess [(Int,Expression)]
addTypes tmap exprs = mapM (secondM (runNGLess . recursiveTransform addTypes')) exprs
Expand Down

0 comments on commit e29a218

Please sign in to comment.