Anton Myasnikov 3037be689b
[LIGO-27] Fix parameters for lambdas and restructure grammar
Problem: It happens that "go to definition" fails with lambda
parameters meaning that we do not create proper AST for it.
Also we need to restructure grammar so that we can support it in
the future.

Solution: Restructure grammar to use "param_decl" and ensure that
we use proper fields for parser resolution.
2020-08-23 22:05:27 +03:00

273 lines
11 KiB
Haskell

-- | Parser for a PascaLigo contract.
module AST.Pascaligo.Parser where
import Data.Maybe (isJust)
import AST.Skeleton
import Duplo.Error
import Duplo.Tree
import Duplo.Pretty
import Product
import Parser
import ParseTree
-- import Debug.Trace
-- example :: FilePath
-- example = "../../../src/test/contracts/arithmetic.ligo"
-- example = "../../../src/test/contracts/address.ligo"
-- example = "../../../src/test/contracts/annotation.ligo"
-- example = "../../../src/test/contracts/amount.ligo"
-- example = "../../../src/test/contracts/attributes.ligo"
-- example = "../../../src/test/contracts/application.ligo"
-- example = "../../../src/test/contracts/assign.ligo"
-- example = "../../../src/test/contracts/big_map.ligo"
-- example = "../../../src/test/contracts/blockless.ligo"
-- example = "../../../src/test/contracts/bad_timestamp.ligo"
-- example = "../../../src/test/contracts/boolean_operators.ligo"
-- example = "../../../src/test/contracts/bitwise_arithmetic.ligo"
-- example = "../../../src/test/contracts/bad_type_operator.ligo"
-- example = "../../../src/test/contracts/blocks.ligo"
-- example = "../../../src/test/contracts/bytes_unpack.ligo"
-- example = "../../../src/test/contracts/balance_constant.ligo"
-- example = "../../../src/test/contracts/blockless.ligo"
-- example = "../../../src/test/contracts/bytes_arithmetic.ligo"
-- example = "../../../src/test/contracts/chain_id.ligo"
-- example = "../../../src/test/contracts/closure-3.ligo"
-- sample' :: FilePath -> IO (LIGO Info)
-- sample' f
-- = toParseTree (Path f)
-- >>= runParserM . recognise
-- >>= return . fst
source' :: FilePath -> IO ()
source' f
= toParseTree (Path f)
>>= print . pp
-- sample :: IO ()
-- sample
-- = toParseTree (Path example)
-- >>= runParserM . recognise
-- >>= print . pp . fst
-- source :: IO ()
-- source
-- = toParseTree (Path example)
-- >>= print . pp
recognise :: RawTree -> ParserM (LIGO Info)
recognise = descent (\_ -> error . show . pp) $ map usingScope
[ -- Contract
Descent do
boilerplate \case
"Start" -> RawContract <$> fields "declaration"
_ -> fallthrough
-- Expr
, Descent do
boilerplate \case
"let_expr" -> Let <$> field "locals" <*> field "body"
"fun_call" -> Apply <$> field "f" <*> fields "arguments"
"par_call" -> Apply <$> field "f" <*> fields "arguments"
"projection_call" -> Apply <$> field "f" <*> fields "arguments"
"Some_call" -> Apply <$> field "constr" <*> fields "arguments"
"constr_call" -> Apply <$> field "constr" <*> fields "arguments"
"arguments" -> Tuple <$> fields "argument"
"unop" -> UnOp <$> field "negate" <*> field "arg"
"binop" -> BinOp <$> field "arg1" <*> field "op" <*> field "arg2"
"block" -> Seq <$> fields "statement"
"clause_block" -> Seq <$> fields "statement"
"list_expr" -> List <$> fields "element"
"annot_expr" -> Annot <$> field "subject" <*> field "type"
"conditional" -> If <$> field "selector" <*> field "then" <*> fieldOpt "else"
"cond_expr" -> If <$> field "selector" <*> field "then" <*> fieldOpt "else"
"assignment" -> Assign <$> field "LHS" <*> field "RHS"
"attr_decl" -> Attrs <$> fields "attribute"
"record_expr" -> Record <$> fields "assignment"
"big_map_injection" -> BigMap <$> fields "binding"
"map_remove" -> MapRemove <$> field "key" <*> field "container"
"tuple_expr" -> Tuple <$> fields "element"
"skip" -> return Skip
"case_expr" -> Case <$> field "subject" <*> fields "case"
"case_instr" -> Case <$> field "subject" <*> fields "case"
"fun_expr" -> Lambda <$> fields "parameters" <*> fieldOpt "type" <*> field "body"
"for_cycle" -> ForLoop <$> field "name" <*> field "begin" <*> field "end" <*> fieldOpt "step" <*> field "body"
"for_box" -> ForBox <$> field "key" <*> fieldOpt "value" <*> field "kind" <*> field "collection" <*> field "body"
"while_loop" -> WhileLoop <$> field "breaker" <*> field "body"
"map_injection" -> Map <$> fields "binding"
"list_injection" -> List <$> fields "element"
"set_expr" -> Set <$> fields "element"
"map_patch" -> MapPatch <$> field "container" <*> fields "binding"
"set_patch" -> SetPatch <$> field "container" <*> fields "key"
"set_remove" -> SetRemove <$> field "key" <*> field "container"
"update_record" -> RecordUpd <$> field "record" <*> fields "assignment"
_ -> fallthrough
-- Pattern
, Descent do
boilerplate \case
"user_constr_pattern" -> IsConstr <$> field "constr" <*> fieldOpt "arguments"
"tuple_pattern" -> IsTuple <$> fields "element"
"nil" -> return $ IsList []
"list_pattern" -> IsList <$> fields "element"
"cons_pattern" -> IsCons <$> field "head" <*> field "tail"
_ -> fallthrough
-- Alt
, Descent do
boilerplate \case
"case_clause_expr" -> Alt <$> field "pattern" <*> field "body"
"case_clause_instr" -> Alt <$> field "pattern" <*> field "body"
_ -> fallthrough
-- FieldAssignment
, Descent do
boilerplate \case
"field_assignment" -> FieldAssignment <$> field "name" <*> field "_rhs"
"field_path_assignment" -> FieldAssignment <$> field "lhs" <*> field "_rhs"
_ -> fallthrough
-- MapBinding
, Descent do
boilerplate \case
"binding" -> MapBinding <$> field "key" <*> field "value"
_ -> fallthrough
, Descent do
boilerplate' \case
("negate", op) -> return $ Op op
("adder", op) -> return $ Op op
("multiplier", op) -> return $ Op op
("comparison", op) -> return $ Op op
("^", _) -> return $ Op "^"
("#", _) -> return $ Op "#"
_ -> fallthrough
, Descent do
boilerplate \case
"data_projection" -> QualifiedName <$> field "struct" <*> fields "index"
"map_lookup" -> QualifiedName <$> field "container" <*> fields "index"
"module_field" -> QualifiedName <$> field "module" <*> fields "method"
_ -> fallthrough
-- Literal
, Descent do
boilerplate' \case
("Int", i) -> return $ Int i
("Nat", i) -> return $ Nat i
("Bytes", i) -> return $ Bytes i
("String", i) -> return $ String i
("Tez", i) -> return $ Tez i
_ -> fallthrough
-- Declaration
, Descent do
boilerplate \case
"fun_decl" -> Function <$> flag "recursive" <*> field "name" <*> fields "parameters" <*> fieldOpt "type" <*> field "body"
"const_decl" -> Const <$> field "name" <*> fieldOpt "type" <*> field "value"
"var_decl" -> Var <$> field "name" <*> fieldOpt "type" <*> field "value"
"type_decl" -> TypeDecl <$> field "typeName" <*> field "typeValue"
"include" -> Include <$> field "filename"
_ -> fallthrough
-- Parameters
, Descent do
boilerplate \case
"parameters" -> Parameters <$> fields "parameter"
_ -> fallthrough
-- VarDecl
, Descent do
boilerplate \case
"param_decl" -> Decl <$> field "access" <*> field "name" <*> fieldOpt "type"
_ -> fallthrough
-- Mutable
, Descent do
boilerplate \case
"const" -> return Immutable
"var" -> return Mutable
_ -> fallthrough
-- Name
, Descent do
boilerplate' \case
("Name", n) -> return $ Name n
("and", _) -> return $ Name "and"
("or", _) -> return $ Name "or"
_ -> fallthrough
-- Type
, Descent do
boilerplate \case
"fun_type" -> TArrow <$> field "domain" <*> field "codomain"
"cartesian" -> TProduct <$> fields "element"
"invokeBinary" -> TApply <$> field "typeConstr" <*> fields "arguments"
"invokeUnary" -> TApply <$> field "typeConstr" <*> fields "arguments"
"type_tuple" -> TTuple <$> fields "element"
"record_type" -> TRecord <$> fields "field"
"sum_type" -> TSum <$> fields "variant"
"michelsonTypeOr" -> TOr <$> field "left_type" <*> field "left_type_name" <*> field "right_type" <*> field "right_type_name"
"michelsonTypeAnd" -> TAnd <$> field "left_type" <*> field "left_type_name" <*> field "right_type" <*> field "right_type_name"
_ -> fallthrough
-- Variant
, Descent do
boilerplate \case
"variant" -> Variant <$> field "constructor" <*> fieldOpt "arguments"
_ -> fallthrough
-- TField
, Descent do
boilerplate \case
"field_decl" -> TField <$> field "fieldName" <*> field "fieldType"
_ -> fallthrough
-- TypeName
, Descent do
boilerplate' \case
("TypeName", name) -> return $ TypeName name
("list", _) -> return $ TypeName "list"
("big_map", _) -> return $ TypeName "big_map"
("map", _) -> return $ TypeName "map"
("set", _) -> return $ TypeName "set"
("option", _) -> return $ TypeName "option"
("contract", _) -> return $ TypeName "contract"
_ -> fallthrough
-- Ctor
, Descent do
boilerplate' \case
("Name_Capital", name) -> return $ Ctor name
("Some", _) -> return $ Ctor "Some"
("Some_pattern", _) -> return $ Ctor "Some"
("None", _) -> return $ Ctor "None"
("True", _) -> return $ Ctor "True"
("False", _) -> return $ Ctor "False"
("Unit", _) -> return $ Ctor "Unit"
("constr", n) -> return $ Ctor n
_ -> fallthrough
-- FieldName
, Descent do
boilerplate' \case
("FieldName", name) -> return $ FieldName name
_ -> fallthrough
-- Err
, Descent do
\(r :> _, ParseTree _ _ text') -> do
withComments do
return (r :> N :> Nil, Err text')
, Descent do
\case
(r :> _, ParseTree "ERROR" _ text') -> do
return ([] :> r :> Y :> Nil, Err text')
_ -> fallthrough
]