handle more parsing edgecases

This commit is contained in:
Ilya Rezvov
2021-04-07 10:35:51 -07:00
parent 93a79badbe
commit fa1d9a7bd1
3 changed files with 78 additions and 42 deletions
+76 -41
View File
@@ -69,6 +69,7 @@ import qualified Data.ByteString.Lazy.Char8 as LBSChar8
import Data.Maybe (fromMaybe, fromJust, isNothing) import Data.Maybe (fromMaybe, fromJust, isNothing)
import Data.List (foldl', findIndex, find) import Data.List (foldl', findIndex, find)
import Control.Monad (guard, foldM) import Control.Monad (guard, foldM)
import Control.Monad.Except (throwError)
import Numeric.Natural (Natural) import Numeric.Natural (Natural)
import Data.Word (Word32, Word64) import Data.Word (Word32, Word64)
@@ -642,27 +643,27 @@ memarg8 :: { MemArg }
instruction_list(terminator) instruction_list(terminator)
: terminator { ($1, []) } : terminator { ($1, []) }
| plaininstr mixed_instruction_list(terminator) { ([PlainInstr $1] ++) `fmap` $2 } | plaininstr mixed_instruction_list(terminator) { ([PlainInstr $1] ++) `fmap` $2 }
| 'call_indirect' typeuse(terminator) { | 'call_indirect' typeuse(terminator) {%
let (tu, instr, end) = $2 in let (tu, instr, end) = $2 in
(end, [PlainInstr $ CallIndirect tu] ++ instr) onlyAnonimParams tu >> (return (end, [PlainInstr $ CallIndirect tu] ++ instr))
} }
| 'block' opt(ident) typeuse('end') opt(ident) mixed_instruction_list(terminator) {% | 'block' opt(ident) typeuse('end') opt(ident) mixed_instruction_list(terminator) {% do
let (tu, instr, _) = $3 in let (tu, instr, _) = $3
if matchIdents $2 $4 matchIdents $2 $4
then Right $ ([BlockInstr $2 tu instr] ++) `fmap` $5 onlyAnonimParams tu
else Left "Block labels have to match" return $ ([BlockInstr $2 tu instr] ++) `fmap` $5
} }
| 'loop' opt(ident) typeuse('end') opt(ident) mixed_instruction_list(terminator) {% | 'loop' opt(ident) typeuse('end') opt(ident) mixed_instruction_list(terminator) {% do
let (tu, instr, _) = $3 in let (tu, instr, _) = $3
if matchIdents $2 $4 matchIdents $2 $4
then Right $ ([LoopInstr $2 tu instr] ++) `fmap` $5 onlyAnonimParams tu
else Left "Loop labels have to match" return $ ([LoopInstr $2 tu instr] ++) `fmap` $5
} }
| 'if' opt(ident) typeuse(if_else) mixed_instruction_list(terminator) {% | 'if' opt(ident) typeuse(if_else) mixed_instruction_list(terminator) {% do
let (tu, trueBranch, (falseBranch, identAfter)) = $3 in let (tu, trueBranch, (falseBranch, identAfter)) = $3
if matchIdents $2 identAfter matchIdents $2 identAfter
then Right $ ([IfInstr $2 tu trueBranch falseBranch] ++) `fmap` $4 onlyAnonimParams tu
else Left "If labels have to match" return $ ([IfInstr $2 tu trueBranch falseBranch] ++) `fmap` $4
} }
mixed_instruction_list(terminator) mixed_instruction_list(terminator)
@@ -672,9 +673,7 @@ mixed_instruction_list(terminator)
if_else :: { ([Instruction], Maybe Ident) } if_else :: { ([Instruction], Maybe Ident) }
: 'end' opt(ident) { ([], $2) } : 'end' opt(ident) { ([], $2) }
| 'else' opt(ident) mixed_instruction_list('end') opt(ident) {% | 'else' opt(ident) mixed_instruction_list('end') opt(ident) {%
if matchIdents $2 $4 matchIdents $2 $4 >> return (snd $3, if isNothing $2 then $4 else $2)
then Right (snd $3, if isNothing $2 then $4 else $2)
else Left "If labels have to match"
} }
folded_instr_list(terminator) : folded_instr1 mixed_instruction_list(terminator) { ($1 ++) `fmap` $2 } folded_instr_list(terminator) : folded_instr1 mixed_instruction_list(terminator) { ($1 ++) `fmap` $2 }
@@ -684,21 +683,21 @@ folded_instr :: { [Instruction] }
folded_instr1 :: { [Instruction] } folded_instr1 :: { [Instruction] }
: plaininstr mixed_instruction_list(')') { snd $2 ++ [PlainInstr $1] } : plaininstr mixed_instruction_list(')') { snd $2 ++ [PlainInstr $1] }
| 'call_indirect' typeuse(')') { | 'call_indirect' typeuse(')') {%
let (tu, instr, _) = $2 in let (tu, instr, _) = $2 in
instr ++ [PlainInstr $ CallIndirect tu] onlyAnonimParams tu >> (return $ instr ++ [PlainInstr $ CallIndirect tu])
} }
| 'block' opt(ident) typeuse(')') { | 'block' opt(ident) typeuse(')') {%
let (typeUse, instr, _) = $3 in let (typeUse, instr, _) = $3 in
[BlockInstr $2 typeUse instr] onlyAnonimParams typeUse >> (return [BlockInstr $2 typeUse instr])
} }
| 'loop' opt(ident) typeuse(')') { | 'loop' opt(ident) typeuse(')') {%
let (typeUse, instr, _) = $3 in let (typeUse, instr, _) = $3 in
[LoopInstr $2 typeUse instr] onlyAnonimParams typeUse >> (return [LoopInstr $2 typeUse instr])
} }
| 'if' opt(ident) '(' typeuse1(folded_then_else, never) { | 'if' opt(ident) '(' typeuse1(folded_then_else, never) {%
let (typeUse, Right (pred, (trueBranch, falseBranch))) = $4 in let (typeUse, Right (pred, (trueBranch, falseBranch))) = $4 in
pred ++ [IfInstr $2 typeUse trueBranch falseBranch] onlyAnonimParams typeUse >> (return $ pred ++ [IfInstr $2 typeUse trueBranch falseBranch])
} }
folded_then_else :: { ([Instruction], ([Instruction], [Instruction])) } folded_then_else :: { ([Instruction], ([Instruction], [Instruction])) }
@@ -997,10 +996,23 @@ prependFuncResults prep f@(Function { funcType = AnonimousTypeUse ft }) =
mergeFuncType :: FuncType -> FuncType -> FuncType mergeFuncType :: FuncType -> FuncType -> FuncType
mergeFuncType (FuncType lps lrs) (FuncType rps rrs) = FuncType (lps ++ rps) (lrs ++ rrs) mergeFuncType (FuncType lps lrs) (FuncType rps rrs) = FuncType (lps ++ rps) (lrs ++ rrs)
matchIdents :: Maybe Ident -> Maybe Ident -> Bool matchIdents :: Maybe Ident -> Maybe Ident -> Either String ()
matchIdents Nothing _ = True matchIdents Nothing Nothing = return ()
matchIdents _ Nothing = True matchIdents (Just a) (Just b) = if a == b then return () else throwError "mismatching label"
matchIdents a b = a == b matchIdents Nothing (Just _) = throwError "mismatching label"
matchIdents (Just _) Nothing = return ()
onlyAnonimParams :: TypeUse -> Either String ()
onlyAnonimParams (IndexedTypeUse _ (Just ft)) = onlyAnonimFT ft
onlyAnonimParams (AnonimousTypeUse ft) = onlyAnonimFT ft
onlyAnonimParams _ = return ()
onlyAnonimFT :: FuncType -> Either String ()
onlyAnonimFT (FuncType params _) = mapM_ isAnonim params
where
isAnonim ParamType{ ident = Just _ } =
throwError "only anonimous params allowed in block signatures"
isAnonim _ = return ()
asOffset :: LBS.ByteString -> Maybe Natural asOffset :: LBS.ByteString -> Maybe Natural
asOffset str = do asOffset str = do
@@ -1350,6 +1362,7 @@ desugarize fields = do
elements <- mapM (synElemToStruct mod) $ elems mod elements <- mapM (synElemToStruct mod) $ elems mod
segments <- mapM (synDataToStruct mod) $ datas mod segments <- mapM (synDataToStruct mod) $ datas mod
globs <- mapM (synGlobalToStruct mod) $ globals mod globs <- mapM (synGlobalToStruct mod) $ globals mod
checkTableIdentsUniqueness mod
checkMemoryIdentsUniqueness mod checkMemoryIdentsUniqueness mod
checkGlobalIdentsUniqueness mod checkGlobalIdentsUniqueness mod
return S.Module { return S.Module {
@@ -1666,6 +1679,23 @@ desugarize fields = do
synTableToStruct :: Table -> S.Table synTableToStruct :: Table -> S.Table
synTableToStruct (Table _ _ tableType) = S.Table tableType synTableToStruct (Table _ _ tableType) = S.Table tableType
checkTableIdentsUniqueness :: Module -> Either String ()
checkTableIdentsUniqueness m@Module { imports, tables } = do
mapM_ checkImportUniqueness $ filter isTableImport imports
mapM_ checkTableUniqueness tables
where
checkImportUniqueness Import { desc = ImportTable (Just id) _ } =
if length (getTableIndexes m id) > 1
then throwError "duplicate table"
else return ()
checkImportUniqueness _ = return ()
checkTableUniqueness (Table _ (Just id) _) =
if length (getTableIndexes m id) > 1
then throwError "duplicate table"
else return ()
checkTableUniqueness _ = return ()
extractTable :: [Table] -> ModuleField -> [Table] extractTable :: [Table] -> ModuleField -> [Table]
extractTable tables (MFTable table) = table : tables extractTable tables (MFTable table) = table : tables
extractTable tables _ = tables extractTable tables _ = tables
@@ -1674,15 +1704,20 @@ desugarize fields = do
isTableImport Import { desc = ImportTable _ _ } = True isTableImport Import { desc = ImportTable _ _ } = True
isTableImport _ = False isTableImport _ = False
getTableIndexes :: Module -> Ident -> [Natural]
getTableIndexes Module { imports, tables } id =
let tableImports = zip [0..] $ filter isTableImport imports in
let importIndexes = map fst $ filter (\(_, Import { desc = ImportTable ident _ }) -> ident == Just id) tableImports in
let isIdent (_, (Table _ (Just id) _)) = True in
let tableIndexes = map fst $ filter isIdent $ zip [length tableImports..] tables in
map fromIntegral $ importIndexes ++ tableIndexes
getTableIndex :: Module -> TableIndex -> Maybe Natural getTableIndex :: Module -> TableIndex -> Maybe Natural
getTableIndex Module { imports, tables } (Named id) = getTableIndex mod (Named id) =
let tableImports = filter isTableImport imports in case getTableIndexes mod id of
case findIndex (\(Import { desc = ImportTable ident _ }) -> ident == Just id) tableImports of [idx] -> return idx
Just idx -> return $ fromIntegral idx _ -> Nothing
Nothing -> getTableIndex _ (Index idx) = Just idx
let isIdent (Table _ (Just id) _) = True in
fromIntegral . (+ length tableImports) <$> findIndex isIdent tables
getTableIndex Module { imports, tables } (Index idx) = Just idx
-- memory -- memory
synMemoryToStruct :: Memory -> S.Memory synMemoryToStruct :: Memory -> S.Memory
@@ -1726,7 +1761,7 @@ desugarize fields = do
case getMemIndexes mod id of case getMemIndexes mod id of
[idx] -> return idx [idx] -> return idx
_ -> Nothing _ -> Nothing
getMemIndex Module { imports, mems } (Index idx) = Just idx getMemIndex _ (Index idx) = Just idx
-- global -- global
synGlobalToStruct :: Module -> Global -> Either String S.Global synGlobalToStruct :: Module -> Global -> Either String S.Global
+1
View File
@@ -187,6 +187,7 @@ runScript onAssertFail script = do
getFailureString Validate.InvalidResultArity = ["invalid result arity"] getFailureString Validate.InvalidResultArity = ["invalid result arity"]
getFailureString Validate.GlobalIsImmutable = ["global is immutable"] getFailureString Validate.GlobalIsImmutable = ["global is immutable"]
getFailureString Validate.InvalidStartFunctionType = ["start function"] getFailureString Validate.InvalidStartFunctionType = ["start function"]
getFailureString Validate.InvalidTableType = ["size minimum must not be greater than maximum"]
getFailureString r = [TL.concat ["not implemented ", (TL.pack $ show r)]] getFailureString r = [TL.concat ["not implemented ", (TL.pack $ show r)]]
printFailedAssert :: String -> Assertion -> AssertM () printFailedAssert :: String -> Assertion -> AssertM ()
+1 -1
View File
@@ -210,7 +210,7 @@ getInstrType Block { blockType, body } = do
getInstrType Loop { blockType, body } = do getInstrType Loop { blockType, body } = do
bt@(Arrow from _) <- getBlockType blockType bt@(Arrow from _) <- getBlockType blockType
resultType <- getResultType blockType resultType <- getResultType blockType
t <- withLabel [] $ getExpressionTypeWithInput from body t <- withLabel (map (\(Val v) -> v) from) $ getExpressionTypeWithInput from body
if isArrowMatch t bt if isArrowMatch t bt
then return bt then return bt
else throwError $ TypeMismatch t bt else throwError $ TypeMismatch t bt