diff --git a/preludes/ruby.rb b/preludes/ruby.rb index af3f8721d..37c7e6000 100644 --- a/preludes/ruby.rb +++ b/preludes/ruby.rb @@ -1,3 +1,7 @@ +def require_dependency(path) + require_relative(path) +end + class Object def new self diff --git a/src/Data/Abstract/Environment.hs b/src/Data/Abstract/Environment.hs index 84e915a25..74abee172 100644 --- a/src/Data/Abstract/Environment.hs +++ b/src/Data/Abstract/Environment.hs @@ -1,6 +1,6 @@ {-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, TypeFamilies #-} module Data.Abstract.Environment - ( Environment + ( Environment(..) , addresses , bind , delete @@ -25,6 +25,7 @@ import qualified Data.Map as Map import Data.Semigroup.Reducer import GHC.Exts (IsList (..)) import Prologue +import qualified Data.List.NonEmpty as NonEmpty -- $setup -- >>> let bright = push (insert (name "foo") (Address (Precise 0)) mempty) @@ -74,13 +75,15 @@ pop (Environment (_ :| a : as)) = Environment (a :| as) head :: Environment l a -> Environment l a head (Environment (a :| _)) = Environment (a :| []) - -- | Take the union of two environments. When duplicate keys are found in the -- name to address map, the second definition wins. mergeNewer :: Environment l a -> Environment l a -> Environment l a -mergeNewer (Environment (a :| as)) (Environment (b :| bs)) = - Environment (combine a b :| alignWith (mergeThese combine) as bs) - where combine = Map.unionWith (flip const) +mergeNewer (Environment a) (Environment b) = + Environment (NonEmpty.fromList . reverse $ alignWith (mergeThese combine) (reverse as) (reverse bs)) + where + combine = Map.unionWith (flip const) + as = NonEmpty.toList a + bs = NonEmpty.toList b -- | Extract an association list of bindings from an 'Environment'. -- diff --git a/src/Language/Ruby/Syntax.hs b/src/Language/Ruby/Syntax.hs index d9a994db2..53b822f57 100644 --- a/src/Language/Ruby/Syntax.hs +++ b/src/Language/Ruby/Syntax.hs @@ -11,6 +11,8 @@ import Diffing.Algorithm import Prelude hiding (fail) import Prologue import System.FilePath.Posix +import qualified Data.List.NonEmpty as NonEmpty +import Data.Abstract.Environment -- TODO: Fully sort out ruby require/load mechanics @@ -48,7 +50,7 @@ instance Evaluatable Require where name <- subtermValue x >>= asString path <- resolveRubyName name (importedEnv, v) <- isolate (doRequire path) - modifyEnv (mappend importedEnv) + modifyEnv (`mergeNewer` importedEnv) pure v -- Returns True if the file was loaded, False if it was already loaded. http://ruby-doc.org/core-2.5.0/Kernel.html#method-i-require doRequire :: MonadEvaluatable location term value m diff --git a/test/fixtures/ruby/analysis/main.rb b/test/fixtures/ruby/analysis/main.rb index fcc0cc22a..b1d878428 100644 --- a/test/fixtures/ruby/analysis/main.rb +++ b/test/fixtures/ruby/analysis/main.rb @@ -1,3 +1,3 @@ -require_relative "foo" +require_dependency "foo" foo(1)