module Record.Syntax where import Record.Syntax.Prelude import Record.Syntax.Shared import qualified Record.Syntax.LevelReifier as LevelReifier import qualified Record.Syntax.Position as Position import qualified Record.Syntax.Parser as Parser import qualified Record.Syntax.Renderer as Renderer processModule :: Text -> Either Error TextBuilder processModule input = join $ runParser pass1Parser where runParser p = Parser.run p input pass1Parser = liftA2 mappend <$> fmap pure head <*> body where head = flip fmap Parser.moduleHead $ \(output, t) -> output <> "import qualified Record" <> ending t where ending = \case Parser.LineType_Space -> "" Parser.LineType_Comment -> " " Parser.LineType_Import -> "; " Parser.LineType_Other -> "\n" body = do offset <- Parser.position forest <- Parser.total $ Parser.extendableSyntaxForest Parser.unparsedExtensionLexeme return $ processExtensionForest Level_Decl forest process :: Level -> Text -> Either Error TextBuilder process level input = do forest <- Parser.run parser $ input processExtensionForest level forest where parser = Parser.extendableSyntaxForest Parser.unparsedExtensionLexeme processExtensionForest :: Level -> ExtendableSyntaxForest TextBuilder -> Either Error TextBuilder processExtensionForest level forest = do levels <- reifyLevels level forest forest' <- zipTraversableWithM (\a b -> processExtension b (convert a)) forest levels return $ Renderer.extendableSyntaxForest id forest' where reifyLevels level = LevelReifier.reify level . convert . Renderer.extendableSyntaxForest (const marker) processExtension :: Level -> Text -> Either Error TextBuilder processExtension level input = join $ Parser.run (parser level) input where parser = \case Level_Exp -> fmap processExtensionExp Parser.extensionExp Level_Type -> fmap processExtensionType Parser.extensionType processExtensionExp :: ExtensionExp (Position, TextBuilder) -> Either Error TextBuilder processExtensionExp = \case ExtensionExp_Record x -> processRecordExp x ExtensionExp_Label x -> pure $ Renderer.labelExp x processRecordExp :: RecordExp (Position, TextBuilder) -> Either Error TextBuilder processRecordExp = fmap (Renderer.recordExp id) . traverse (\(p, i) -> offsetResult p $ process Level_Exp $ convert i) processExtensionType :: ExtensionType -> Either Error TextBuilder processExtensionType = \case ExtensionType_Record x -> pure $ Renderer.recordType x offsetResult :: Position -> Either Error a -> Either Error a offsetResult p = either (Left . (\f (a, b) -> (f a, b)) (Position.add p)) Right