Fixing relative imports for extopenscad.

When exteopnscad is called with a source filepath outside of the current
directory, relative filepaths such as "../config.scad" would fail to
read if no such file relative to the _programs_ directory, not the
source file, existed.

This change uses the directory of the initial source file as the
location for relative file lookups.
This commit is contained in:
Owen Harvey 2024-04-18 17:54:42 +10:00
parent b44e9597ff
commit dc113faac5
10 changed files with 24 additions and 10 deletions

View File

@ -14,6 +14,7 @@
* Making `torus` and `ellipsoid` primitive objects, rather than being defined implicitly. [#450](https://github.com/Haskell-Things/ImplicitCAD/issues/450)
* Improved formatting of ExtOpenSCAD code [#472](https://github.com/Haskell-Things/ImplicitCAD/pull/472)
* Fixing an issue where ImplicitCAD extended primitive objects were being exported to OpenSCAD where they aren't supported.
* Fixing relative imports to use the directory of the initial source file rather than the directory where `extopenscad` was called.
# Version [0.4.1.0](https://github.com/Haskell-Things/ImplicitCAD/compare/v0.4.0.0...v0.4.1.0) (2023-12-18)

View File

@ -5,7 +5,7 @@
-- An executor, which parses openscad code, and executes it.
module Graphics.Implicit.ExtOpenScad (runOpenscad) where
import Prelude(String, IO, ($), (<$>), pure, either, (.), Applicative, Bool(True))
import Prelude(String, IO, ($), (<$>), pure, either, (.), Applicative, Bool(True), Maybe, maybe)
import Graphics.Implicit.Definitions (SymbolicObj2, SymbolicObj3)
@ -28,10 +28,11 @@ import System.Directory (getCurrentDirectory)
import Data.Foldable (traverse_)
import Data.Text.Lazy (pack)
import System.FilePath (FilePath, takeDirectory)
-- | Small wrapper of our parser to handle parse errors, etc.
runOpenscad :: ScadOpts -> [String] -> String -> IO (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message])
runOpenscad scadOpts constants source = do
runOpenscad :: ScadOpts -> [String] -> Maybe FilePath -> String -> IO (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message])
runOpenscad scadOpts constants filepath source = do
(initialObjects, initialMessages) <- addConstants constants True
let
err :: Applicative f => ParseError -> f (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message])
@ -39,11 +40,12 @@ runOpenscad scadOpts constants source = do
run :: [StatementI] -> IO (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message])
run sts = rearrange <$> do
let sts' = traverse_ runStatementI sts
path <- getCurrentDirectory
-- If we are given a filepath, use its directory, relative or absolute.
-- If there is no filepath given, then use the current directory of the process.
path <- maybe getCurrentDirectory (pure . takeDirectory) filepath
let initState = CompState initialObjects [] path
(_, w, s') <- runImplicitCadM scadOpts initState sts'
pure (w, s')
either err run $ parseProgram "" source
where
rearrange :: ([Message], CompState) -> (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message])

View File

@ -10,7 +10,7 @@
-- Let's be explicit about what we're getting from where :)
import Prelude (Maybe(Just, Nothing), IO, Bool(True, False), FilePath, String, (<>), ($), readFile, fst, putStrLn, show, (>>=), return, unlines, filter, not, null, (||), (&&), (.), print)
import Prelude (Maybe(Just, Nothing), IO, Bool(True, False), FilePath, String, (<>), ($), readFile, fst, putStrLn, show, (>>=), return, unlines, filter, not, null, (||), (&&), (.), print, pure)
-- Our Extended OpenScad interpreter
import Graphics.Implicit (union, runOpenscad)
@ -173,7 +173,7 @@ run rawargs = do
_ | Just file <- outputFile args -> Just $ guessOutputFormat file
_ -> Nothing
scadOpts = generateScadOpts args
openscadProgram = runOpenscad scadOpts (rawDefines args) content
openscadProgram = runOpenscad scadOpts (rawDefines args) (pure $ inputFile args) content
if quiet args
then return ()

View File

@ -10,7 +10,7 @@ module MessageSpec.Util
) where
-- be explicit about where we get things from.
import Prelude (String, Bool(False), IO, return)
import Prelude (String, Bool(False), IO, return, Maybe (Nothing))
-- Expressions, symbols, and values in the OpenScad language.
import Graphics.Implicit.ExtOpenScad.Definitions (ScadOpts(ScadOpts), MessageType, Message(Message), SourcePosition)
@ -39,7 +39,7 @@ infixr 1 -->
-- | An even smaller wrapper which runs a program, and only returns the generated messages. for the test suite.
getOpenscadMessages :: ScadOpts -> [String] -> String -> IO [Message]
getOpenscadMessages scadOpts constants source = do
(_, _, _, messages) <- runOpenscad scadOpts constants source
(_, _, _, messages) <- runOpenscad scadOpts constants Nothing source
return messages
oneMessage :: MessageType -> SourcePosition -> Text -> [Message]

View File

@ -122,4 +122,4 @@ statementSpec = do
"module foo\n(\nbar\n)\n{}" --> single (NewModule (Symbol "foo") [(Symbol "bar", Nothing)] [])
describe "identifiers" $ do
it "accepts unicode" $
"module 💩 () { }" --> single (NewModule (Symbol "💩") [] [])
"module 💩 () { }" --> single (NewModule (Symbol "💩") [] [])

1
tests/imports/child.scad Normal file
View File

@ -0,0 +1 @@
include <relative/parent.scad>;

View File

@ -0,0 +1,3 @@
foo=1;
bar=2;
baz=3;

View File

@ -0,0 +1,3 @@
include <./config.scad>;
cube(foo,bar,baz);

View File

@ -0,0 +1 @@
include <../parent.scad>;

View File

@ -0,0 +1,3 @@
include <../config.scad>;
cube(foo,bar,baz);