parsley-core-2.1.0.1: src/ghc-8.10+/Parsley/Internal/Backend/Machine/PosOps.hs
{-# LANGUAGE CPP, MagicHash, UnboxedTuples, NumericUnderscores #-}
{-# OPTIONS_GHC -Wno-overflowed-literals #-}
{-|
Module : Parsley.Internal.Backend.Machine.PosOps
Description : Collection of platform dependent position operations
License : BSD-3-Clause
Maintainer : Jamie Willis
Stability : experimental
This module contains the implementations of updates on positions: these depend on the number of
bits in a word, or if the @full-width-positions@ flag was set on the @parsley-core@ library.
@since 1.8.0.0
-}
module Parsley.Internal.Backend.Machine.PosOps (
initPos, tabWidth,
extractLine, extractCol,
liftPos,
updatePos, updatePosQ,
updatePosNewlineOnly, updatePosNewlineOnlyQ,
shiftLineAndSetCol, shiftCol, shiftAlignAndShiftCol,
shiftLineAndSetColQ, shiftColQ, shiftAlignAndShiftColQ,
toNextTab
) where
#include "MachDeps.h"
#if WORD_SIZE_IN_BITS < 64
#define FULL_WIDTH_POSITIONS
#endif
import Data.Bits ( (.&.), (.|.)
#ifndef FULL_WIDTH_POSITIONS
, unsafeShiftL
#endif
)
import Parsley.Internal.Backend.Machine.Types.Base (Pos)
import Parsley.Internal.Common (Code)
import GHC.Exts (Int(..), Word(W#))
import GHC.Prim ( plusWord#, and#, or#, word2Int#
#ifdef FULL_WIDTH_POSITIONS
, minusWord#
#else
, uncheckedShiftRL#
#endif
)
{-|
Advances a column to the next tab column.
@since 2.1.0.0
-}
toNextTab :: Word -> Word
toNextTab x = (x + tabWidth - 1) .&. negate tabWidth .|. 1
{-|
Given a dynamic character and a static position, produces a new dynamic position.
@since 2.1.0.0
-}
updatePos :: Code Char -> Word -> Word -> Code Pos
updatePos c line col = [||updatePos# $$(liftPos line col) $$c||]
{-|
Given a dynamic character and a static position, produces a new dynamic position.
For this variant, newlines are the only character than can affect the update.
@since 2.1.0.0
-}
updatePosNewlineOnly :: Code Char -> Word -> Code Pos
updatePosNewlineOnly c line = [||updatePos0ColNewlineOnly# $$(liftPos line 0) $$c||]
{-|
Given a dynamic character and a dynamic position, returns the representation of the updated position.
@since 2.1.0.0
-}
updatePosQ :: Code Char -> Code Pos -> Code Pos
updatePosQ c pos = [||updatePos# $$pos $$c||]
{-|
Given a dynamic character and a dynamic position, returns the representation of the updated position.
For this variant, newlines are the only character than can affect the update.
@since 2.1.0.0
-}
updatePosNewlineOnlyQ :: Code Char -> Code Pos -> Code Pos
updatePosNewlineOnlyQ c pos = [||updatePosNewlineOnly# $$pos $$c||]
{-|
Shift a static postion's column by a given amount
@since 2.1.0.0
-}
shiftCol :: Word -- ^ The amount to shift the column by
-> Word -- ^ The line
-> Word -- ^ The column
-> (Word, Word)
shiftCol n line col = (line, col + n)
{-|
Shift a static line by a given amount and then set the column
@since 2.1.0.0
-}
shiftLineAndSetCol :: Word -- ^ The amount to shift the line by
-> Word -- ^ The new column
-> Word -- ^ The line
-> (Word, Word)
shiftLineAndSetCol n col line = (line + n, col)
{-|
Shift a static position by first adjusting the column, then aligning to a tab, then shifting further
@since 2.1.0.0
-}
shiftAlignAndShiftCol :: Word -- ^ Amount to shift column by before the tab shift
-> Word -- ^ Amount to shift column by after the tab shift
-> Word -- ^ The line
-> Word -- ^ The new column
-> (Word, Word)
shiftAlignAndShiftCol firstBy thenBy line col = (line, toNextTab (col + firstBy) + thenBy)
{-|
The initial position used by the parser. This is some representation of (1, 1).
@since 1.8.0.0
-}
initPos :: (Word, Word)
initPos = (1, 1)
{-|
The size of a tab.
@since 2.1.0.0
-}
tabWidth :: Num a => a
tabWidth = 4
{-# INLINEABLE updatePos# #-}
updatePos# :: Pos -> Char -> Pos
{-# INLINE updatePosNewlineOnly# #-}
updatePosNewlineOnly# :: Pos -> Char -> Pos
{-# INLINEABLE updatePos0ColNewlineOnly# #-}
updatePos0ColNewlineOnly# :: Pos -> Char -> Pos
{-|
Shift a dynamic postion's column by a given amount
@since 2.1.0.0
-}
shiftColQ :: Word -- ^ The amount to shift the column by
-> Code Pos
-> Code Pos
{-|
Shift a dynamic line by a given amount and then set the column
@since 2.1.0.0
-}
shiftLineAndSetColQ :: Word -- ^ The amount to shift the line by
-> Word -- ^ The new column
-> Code Pos
-> Code Pos
{-|
Shift a dynamic position by first adjusting the column, then aligning to a tab, then shifting further
@since 2.1.0.0
-}
shiftAlignAndShiftColQ :: Word -- ^ Amount to shift column by before the tab shift
-> Word -- ^ Amount to shift column by after the tab shift
-> Code Pos
-> Code Pos
{-|
Given the opaque representation of a position, extracts the line number out of it.
@since 1.8.0.0
-}
extractLine :: Code Pos -> Code Int
{-|
Given the opaque representation of a position, extracts the column number out of it.
@since 1.8.0.0
-}
extractCol :: Code Pos -> Code Int
{-|
Converts a static position into a dynamic one.
@since 2.1.0.0
-}
liftPos :: Word -> Word -> Code Pos
#ifndef FULL_WIDTH_POSITIONS
-- This is referred to directly in generated code, leave optimised primitives
updatePos# pos '\n' = (pos `and#` 0xffffffff_00000000##) `plusWord#` 0x00000001_00000001##
updatePos# pos '\t' = ((pos `plusWord#` 0x00000000_00000003##) `and#` 0xffffffff_fffffffc##) `or#` 0x00000000_00000001##
updatePos# pos _ = pos `plusWord#` 0x00000000_00000001##
-- This is referred to directly in generated code, leave optimised primitives
updatePosNewlineOnly# pos = updatePos0ColNewlineOnly# (pos `and#` 0xffffffff_00000000##)
-- This is referred to directly in generated code, leave optimised primitives
updatePos0ColNewlineOnly# pos0Col '\n' = pos0Col `plusWord#` 0x00000001_00000000##
updatePos0ColNewlineOnly# pos0Col _ = pos0Col
shiftLineAndSetColQ n col qpos = [|| ($$qpos `and#` 0xffffffff_00000000##) `plusWord#` $$(liftPos n col) ||]
shiftColQ (W# n) qpos = [|| $$qpos `plusWord#` n ||]
shiftAlignAndShiftColQ firstBy thenBy qpos =
let !(W# pre) = firstBy + 3 -- offset first, then add 3 to overshoot
!(W# mask) = -4 -- constant fold this into raw literal
!(W# post) = thenBy + 1 -- add the offset of tab boundary from power of two, then remaining positions
in if thenBy == 0 then [|| (($$qpos `plusWord#` pre) `and#` mask) `or#` 0x00000000_00000001## ||] -- because tab widths are multiples of two
else [|| (($$qpos `plusWord#` pre) `and#` mask) `plusWord#` post ||]
extractLine qpos = [||I# (word2Int# ($$qpos `uncheckedShiftRL#` 32#))||]
extractCol qpos = [||I# (word2Int# ($$qpos `and#` 0x00000000_ffffffff##))||]
liftPos line col = let !(W# p) = (line `unsafeShiftL` 32) .|. col in [||p||]
#else
-- This is referred to directly in generated code, leave optimised primitives
updatePos# (# line, _ #) '\n' = (# line `plusWord#` 1##, 1## #)
updatePos# (# line, col #) '\t' = (# line, ((col `plusWord#` 3##) `and#` (0## `minusWord#` 4##)) `or#` 1## #) -- nearest tab boundary `c + (4 - (c - 1) % 4)`
updatePos# (# line, col #) _ = (# line, col `plusWord#` 1## #)
-- This is referred to directly in generated code, leave optimised primitives
updatePosNewlineOnly# = updatePos0ColNewlineOnly#
-- This is referred to directly in generated code, leave optimised primitives
updatePos0ColNewlineOnly# (# line, _ #) '\n' = (# line `plusWord#` 1##, 0## #)
updatePos0ColNewlineOnly# pos _ = pos
shiftLineAndSetColQ (W# n) (W# col) qpos = [|| case $$qpos of (# line, _ #) -> (# line `plusWord#` n, col #) ||]
shiftColQ (W# n) qpos = [|| case $$qpos of (# line, col #) -> (# line, col `plusWord#` n #) ||]
shiftAlignAndShiftColQ firstBy thenBy qpos =
let !(W# pre) = firstBy + 3 -- offset first, then add 3 to overshoot
!(W# mask) = -4 -- constant fold this into raw literal
!(W# post) = thenBy + 1 -- add the offset of tab boundary from power of two, then remaining positions
in [|| case $$qpos of
(# line, col #) -> (# line,
$$(if thenBy == 0 then [|| ((col `plusWord#` pre) `and#` mask) `or#` 1## ||] -- because tab widths are multiples of two
else [|| ((col `plusWord#` pre) `and#` mask) `plusWord#` post ||]) #) ||]
extractLine qpos = [|| case $$qpos of (# line, _ #) -> I# (word2Int# line) ||]
extractCol qpos = [|| case $$qpos of (# _, col #) -> I# (word2Int# col) ||]
liftPos (W# line) (W# col) = [||(# line, col #)||]
#endif