morley-0.3.0: src/Michelson/Parser/Instr.hs
-- | Parsing of Michelson instructions.
module Michelson.Parser.Instr
( primInstr
, ops'
-- * These are handled separately to have better error messages
, mapOp
, pairOp
, cmpOp
) where
import Prelude hiding (EQ, GT, LT, many, note, some, try)
import Text.Megaparsec (choice, sepEndBy, try)
import Michelson.Let (LetValue(..))
import Michelson.Macro (ParsedInstr, ParsedOp(..))
import Michelson.Parser.Annotations
import Michelson.Parser.Lexer
import Michelson.Parser.Type
import Michelson.Parser.Types (Parser, letValues)
import Michelson.Parser.Value
import Michelson.Untyped
-- | Parser for primitive Michelson instruction (no macros and extensions).
primInstr :: Parser (Contract' ParsedOp) -> Parser ParsedOp -> Parser ParsedInstr
primInstr contractParser opParser = choice
[ dropOp, dupOp, swapOp, pushOp opParser, someOp, noneOp, unitOp
, ifNoneOp opParser, carOp, cdrOp, leftOp, rightOp, ifLeftOp opParser, nilOp
, consOp, ifConsOp opParser, sizeOp, emptySetOp, emptyMapOp, iterOp opParser
, memOp, getOp, updateOp, loopLOp opParser, loopOp opParser
, lambdaOp opParser, execOp, dipOp opParser, failWithOp, castOp, renameOp
, concatOp, packOp, unpackOp, sliceOp, isNatOp, addressOp, addOp, subOp
, mulOp, edivOp, absOp, negOp, lslOp, lsrOp, orOp, andOp, xorOp, notOp
, compareOp, eqOp, neqOp, ltOp, leOp, gtOp, geOp, intOp, selfOp, contractOp
, transferTokensOp, setDelegateOp, createAccountOp
, createContractOp contractParser, implicitAccountOp, nowOp, amountOp
, balanceOp, checkSigOp, sha256Op, sha512Op, blake2BOp, hashKeyOp
, stepsToQuotaOp, sourceOp, senderOp
]
-- | Parse a sequence of instructions.
ops' :: Parser ParsedOp -> Parser [ParsedOp]
ops' opParser = braces $ sepEndBy opParser semicolon
-- Control Structures
failWithOp :: Parser ParsedInstr
failWithOp = do symbol' "FAILWITH"; return FAILWITH
loopOp :: Parser ParsedOp -> Parser ParsedInstr
loopOp opParser = do void $ symbol' "LOOP"; LOOP <$> ops' opParser
loopLOp :: Parser ParsedOp -> Parser ParsedInstr
loopLOp opParser = do void $ symbol' "LOOP_LEFT"; LOOP_LEFT <$> ops' opParser
execOp :: Parser ParsedInstr
execOp = do void $ symbol' "EXEC"; EXEC <$> noteVDef
dipOp :: Parser ParsedOp -> Parser ParsedInstr
dipOp opParser = do void $ symbol' "DIP"; DIP <$> ops' opParser
-- Stack Operations
dropOp :: Parser ParsedInstr
dropOp = do symbol' "DROP"; return DROP;
dupOp :: Parser ParsedInstr
dupOp = do void $ symbol' "DUP"; DUP <$> noteVDef
swapOp :: Parser ParsedInstr
swapOp = do symbol' "SWAP"; return SWAP;
pushOp :: Parser ParsedOp -> Parser ParsedInstr
pushOp opParser = do
symbol' "PUSH"
v <- noteVDef
(try $ pushLet v) <|> (push' v)
where
pushLet v = do
lvs <- asks letValues
lv <- mkLetVal lvs
return $ PUSH v (lvSig lv) (lvVal lv)
push' v = PUSH v <$> type_ <*> value' opParser
unitOp :: Parser ParsedInstr
unitOp = do symbol' "UNIT"; (t, v) <- notesTV; return $ UNIT t v
lambdaOp :: Parser ParsedOp -> Parser ParsedInstr
lambdaOp opParser =
symbol' "LAMBDA" *>
(LAMBDA <$> noteVDef <*> type_ <*> type_ <*> ops' opParser)
-- Generic comparison
cmpOp :: Parser ParsedInstr
cmpOp = eqOp <|> neqOp <|> ltOp <|> gtOp <|> leOp <|> gtOp <|> geOp
eqOp :: Parser ParsedInstr
eqOp = do void $ symbol' "EQ"; EQ <$> noteVDef
neqOp :: Parser ParsedInstr
neqOp = do void $ symbol' "NEQ"; NEQ <$> noteVDef
ltOp :: Parser ParsedInstr
ltOp = do void $ symbol' "LT"; LT <$> noteVDef
gtOp :: Parser ParsedInstr
gtOp = do void $ symbol' "GT"; GT <$> noteVDef
leOp :: Parser ParsedInstr
leOp = do void $ symbol' "LE"; LE <$> noteVDef
geOp :: Parser ParsedInstr
geOp = do void $ symbol' "GE"; GE <$> noteVDef
-- ad-hoc comparison
compareOp :: Parser ParsedInstr
compareOp = do void $ symbol' "COMPARE"; COMPARE <$> noteVDef
-- Operations on booleans
orOp :: Parser ParsedInstr
orOp = do void $ symbol' "OR"; OR <$> noteVDef
andOp :: Parser ParsedInstr
andOp = do void $ symbol' "AND"; AND <$> noteVDef
xorOp :: Parser ParsedInstr
xorOp = do void $ symbol' "XOR"; XOR <$> noteVDef
notOp :: Parser ParsedInstr
notOp = do void $ symbol' "NOT"; NOT <$> noteVDef
-- Operations on integers and natural numbers
addOp :: Parser ParsedInstr
addOp = do void $ symbol' "ADD"; ADD <$> noteVDef
subOp :: Parser ParsedInstr
subOp = do void $ symbol' "SUB"; SUB <$> noteVDef
mulOp :: Parser ParsedInstr
mulOp = do void $ symbol' "MUL"; MUL <$> noteVDef
edivOp :: Parser ParsedInstr
edivOp = do void $ symbol' "EDIV";EDIV <$> noteVDef
absOp :: Parser ParsedInstr
absOp = do void $ symbol' "ABS"; ABS <$> noteVDef
negOp :: Parser ParsedInstr
negOp = do symbol' "NEG"; return NEG;
-- Bitwise logical operators
lslOp :: Parser ParsedInstr
lslOp = do void $ symbol' "LSL"; LSL <$> noteVDef
lsrOp :: Parser ParsedInstr
lsrOp = do void $ symbol' "LSR"; LSR <$> noteVDef
-- Operations on string's
concatOp :: Parser ParsedInstr
concatOp = do void $ symbol' "CONCAT"; CONCAT <$> noteVDef
sliceOp :: Parser ParsedInstr
sliceOp = do void $ symbol' "SLICE"; SLICE <$> noteVDef
-- Operations on pairs
pairOp :: Parser ParsedInstr
pairOp = do symbol' "PAIR"; (t, v, (p, q)) <- notesTVF2; return $ PAIR t v p q
carOp :: Parser ParsedInstr
carOp = do symbol' "CAR"; (v, f) <- notesVF; return $ CAR v f
cdrOp :: Parser ParsedInstr
cdrOp = do symbol' "CDR"; (v, f) <- notesVF; return $ CDR v f
-- Operations on collections (sets, maps, lists)
emptySetOp :: Parser ParsedInstr
emptySetOp = do symbol' "EMPTY_SET"; (t, v) <- notesTV;
EMPTY_SET t v <$> comparable
emptyMapOp :: Parser ParsedInstr
emptyMapOp = do symbol' "EMPTY_MAP"; (t, v) <- notesTV; a <- comparable;
EMPTY_MAP t v a <$> type_
memOp :: Parser ParsedInstr
memOp = do void $ symbol' "MEM"; MEM <$> noteVDef
updateOp :: Parser ParsedInstr
updateOp = do symbol' "UPDATE"; return UPDATE
iterOp :: Parser ParsedOp -> Parser ParsedInstr
iterOp opParser = do void $ symbol' "ITER"; ITER <$> ops' opParser
sizeOp :: Parser ParsedInstr
sizeOp = do void $ symbol' "SIZE"; SIZE <$> noteVDef
mapOp :: Parser ParsedOp -> Parser ParsedInstr
mapOp opParser = do symbol' "MAP"; v <- noteVDef; MAP v <$> ops' opParser
getOp :: Parser ParsedInstr
getOp = do void $ symbol' "GET"; GET <$> noteVDef
nilOp :: Parser ParsedInstr
nilOp = do symbol' "NIL"; (t, v) <- notesTV; NIL t v <$> type_
consOp :: Parser ParsedInstr
consOp = do void $ symbol' "CONS"; CONS <$> noteVDef
ifConsOp :: Parser ParsedOp -> Parser ParsedInstr
ifConsOp opParser =
symbol' "IF_CONS" *>
(IF_CONS <$> ops' opParser <*> ops' opParser)
-- Operations on options
someOp :: Parser ParsedInstr
someOp = do symbol' "SOME"; (t, v, f) <- notesTVF; return $ SOME t v f
noneOp :: Parser ParsedInstr
noneOp = do symbol' "NONE"; (t, v, f) <- notesTVF; NONE t v f <$> type_
ifNoneOp :: Parser ParsedOp -> Parser ParsedInstr
ifNoneOp opParser =
symbol' "IF_NONE" *>
(IF_NONE <$> ops' opParser <*> ops' opParser)
-- Operations on unions
leftOp :: Parser ParsedInstr
leftOp = do symbol' "LEFT"; (t, v, (f, f')) <- notesTVF2;
LEFT t v f f' <$> type_
rightOp :: Parser ParsedInstr
rightOp = do symbol' "RIGHT"; (t, v, (f, f')) <- notesTVF2;
RIGHT t v f f' <$> type_
ifLeftOp :: Parser ParsedOp -> Parser ParsedInstr
ifLeftOp opParser = do
symbol' "IF_LEFT"
a <- ops' opParser
IF_LEFT a <$> ops' opParser
-- Operations on contracts
createContractOp :: Parser (Contract' ParsedOp) -> Parser ParsedInstr
createContractOp contractParser =
symbol' "CREATE_CONTRACT" *>
(CREATE_CONTRACT <$> noteVDef <*> noteVDef <*> braces contractParser)
createAccountOp :: Parser ParsedInstr
createAccountOp = do symbol' "CREATE_ACCOUNT"; v <- noteVDef; v' <- noteVDef;
return $ CREATE_ACCOUNT v v'
transferTokensOp :: Parser ParsedInstr
transferTokensOp = do void $ symbol' "TRANSFER_TOKENS"; TRANSFER_TOKENS <$> noteVDef
setDelegateOp :: Parser ParsedInstr
setDelegateOp = do void $ symbol' "SET_DELEGATE"; SET_DELEGATE <$> noteVDef
balanceOp :: Parser ParsedInstr
balanceOp = do void $ symbol' "BALANCE"; BALANCE <$> noteVDef
contractOp :: Parser ParsedInstr
contractOp = do void $ symbol' "CONTRACT"; CONTRACT <$> noteVDef <*> type_
sourceOp :: Parser ParsedInstr
sourceOp = do void $ symbol' "SOURCE"; SOURCE <$> noteVDef
senderOp :: Parser ParsedInstr
senderOp = do void $ symbol' "SENDER"; SENDER <$> noteVDef
amountOp :: Parser ParsedInstr
amountOp = do void $ symbol' "AMOUNT"; AMOUNT <$> noteVDef
implicitAccountOp :: Parser ParsedInstr
implicitAccountOp = do void $ symbol' "IMPLICIT_ACCOUNT"; IMPLICIT_ACCOUNT <$> noteVDef
selfOp :: Parser ParsedInstr
selfOp = do void $ symbol' "SELF"; SELF <$> noteVDef
addressOp :: Parser ParsedInstr
addressOp = do void $ symbol' "ADDRESS"; ADDRESS <$> noteVDef
-- Special Operations
nowOp :: Parser ParsedInstr
nowOp = do void $ symbol' "NOW"; NOW <$> noteVDef
stepsToQuotaOp :: Parser ParsedInstr
stepsToQuotaOp = do void $ symbol' "STEPS_TO_QUOTA"; STEPS_TO_QUOTA <$> noteVDef
-- Operations on bytes
packOp :: Parser ParsedInstr
packOp = do void $ symbol' "PACK"; PACK <$> noteVDef
unpackOp :: Parser ParsedInstr
unpackOp = do symbol' "UNPACK"; v <- noteVDef; UNPACK v <$> type_
-- Cryptographic Primitives
checkSigOp :: Parser ParsedInstr
checkSigOp = do void $ symbol' "CHECK_SIGNATURE"; CHECK_SIGNATURE <$> noteVDef
blake2BOp :: Parser ParsedInstr
blake2BOp = do void $ symbol' "BLAKE2B"; BLAKE2B <$> noteVDef
sha256Op :: Parser ParsedInstr
sha256Op = do void $ symbol' "SHA256"; SHA256 <$> noteVDef
sha512Op :: Parser ParsedInstr
sha512Op = do void $ symbol' "SHA512"; SHA512 <$> noteVDef
hashKeyOp :: Parser ParsedInstr
hashKeyOp = do void $ symbol' "HASH_KEY"; HASH_KEY <$> noteVDef
-- Type operations
castOp :: Parser ParsedInstr
castOp = do void $ symbol' "CAST"; CAST <$> noteVDef <*> type_;
renameOp :: Parser ParsedInstr
renameOp = do void $ symbol' "RENAME"; RENAME <$> noteVDef
isNatOp :: Parser ParsedInstr
isNatOp = do void $ symbol' "ISNAT"; ISNAT <$> noteVDef
intOp :: Parser ParsedInstr
intOp = do void $ symbol' "INT"; INT <$> noteVDef