Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ast_generic.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901(* Yoann Padioleau
*
* Copyright (C) 2019 r2c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
* license.txt for more details.
*)(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* A generic AST, to factorize similar analysis in different programming
* languages (e.g., scheck, sgrep, checked_return).
*
* Right now this is mostly the factorized union of:
* - Python
* - Javascript
* - Java
* - C
* - TOFINISH OCaml
* - TODO PHP
*
* rational: In the end, programming languages have a lot in common.
* Even though most interesting analysis are probably better done on a
* per-language basis, many useful analysis are trivial and require just an
* AST and a visitor. One could duplicate those analysis for each language
* or design an AST (this file) generic enough to factorize all those
* analysis (e.g., unused entity). We also want to remain
* as precise as possible and not lose too much information while going
* from the specific language AST to the generic AST. We do not want
* to be generic as in ast_fuzzy.ml, where we have a very general
* tree of nodes, but all the structure of the original AST is lost.
*
* TODO:
* - later: add Go (easy)
* - later: add Ruby, Rust, Scala (difficult)
* - later: add C++ (argh)
* - see ast_fuzzy.ml TODOs for ideas to use ast_generic for sgrep.
*
* related work:
* - ast_fuzzy.ml (in this directory)
* - github semantic
* https://github.com/github/semantic
* - Coverity common program representation?
* - Semmle internal common representation?
* - Infer SIL (for C++, Java, Objective-C)
* - Dawson Engler and Fraser Brown micro-checkers for multiple languages
* - Lightweight Multi-language syntax transformation paper, but does not
* really operate on an AST
* - https://tabnine.com/ which supports multiple languages, but probably
* again does not operate on an AST
* - srcML https://www.srcml.org/doc/srcMLGrammar.html
* but just for C/C++/C#/Java and seems pretty heavy
*
* design choices to have a generic data structure:
* - add some 'a, 'b, 'c around expr/stmt/...
* - functorize and add some type hole (type tstmt; type texpr; ...)
* - data-type a la carte like in github-semantic but Seems too high-level
* with astronaut-style architecture (too abstract, too advanced features).
* - the OtherXxx strategy used in this file (simple)
*
* history:
* - started with crossproduct of Javascript, Python, PHP, Java, and C
* (and a bit of OCaml)
*
* invariants:
* - all the other_xxx types should contain only simple constructors (enums)
* without any parameter. I rely on that to simplify the code
* of the generic mapper and matcher.
* - each language should add the VarDefs that defines the locals
* used in a function (instead of having the first Assign play the role
* of a VarDef, as done in Python for example).
* - to correctly compute a CFG (Control Flow Graph), the stmt type
* should list all constructs that contains other statements and
* try to avoid to use the very generic OtherXxx of any
* - to correctly compute a DFG (Data Flow Graph), each constructs that
* introduce a new variable should have a relevant comment 'newvar:'
* - to correctly resolve names, each constructs that introduce a new scope
* should have a relevant comment 'newscope:'
*
* See also pfff/lang_GENERIC/
*)(*****************************************************************************)(* Names *)(*****************************************************************************)(* ------------------------------------------------------------------------- *)(* Token/info *)(* ------------------------------------------------------------------------- *)(* Contains among other things the position of the token through
* the Parse_info.token_location embedded inside it, as well as the
* transformation field that makes possible spatch on the code.
*)typetok=Parse_info.t(* with tarzan *)(* a shortcut to annotate some information with position information *)type'awrap='a*tok(* with tarzan *)(* ------------------------------------------------------------------------- *)(* Names *)(* ------------------------------------------------------------------------- *)typeident=stringwrap(* with tarzan *)typedotted_ident=identlist(* at least 1 element *)(* with tarzan *)(* todo: not enough in OCaml with functor and type arguments or C++ templates*)typequalifier=dotted_ident(* with tarzan *)(* 'module' can also be used for a 'package', or a 'namespace' *)typemodule_name=|FileNameofstringwrap(* ex: Javascript import, C #include *)|DottedNameofdotted_ident(* ex: Python *)(* with tarzan *)(* see also scope_code.ml *)typeresolved_name=|Localofgensym|Paramofgensym(* could merge with Local *)(* for closures; can refer to a Local or Param *)|EnclosedVarofgensym(* TODO? and depth? *)(* both dotted_ident must at least contain one element *)|Globalofdotted_ident(* or just name? *)(* can also use 0 for gensym *)|ImportedModuleofdotted_ident|Macro|EnumConstant(* this simplifies further analysis which need less to care about
* maintaining scoping information to deal with variable shadowing,
* functions using the same parameter names, etc.
*)andgensym=int(* a unique gensym'ed number *)(* with tarzan *)(* big mutually recursive types because of the use of 'any' in OtherXxx *)typename=ident*name_infoandname_info={name_qualifier:qualifieroption;name_typeargs:type_argumentsoption;(* Java *)}(*****************************************************************************)(* Naming/typing *)(*****************************************************************************)andid_info={id_resolved:resolved_nameoptionref;(* variable tagger (naming) *)id_type:type_optionref;(* type checker (typing) *)}(*****************************************************************************)(* Expression *)(*****************************************************************************)andexpr=(* basic (atomic) values *)|Lofliteral(* composite values *)|Containerofcontainer_operator*exprlist|Tupleofexprlist(* special case of Container *)(* And-type (field.vinit should be a Some) *)|Recordoffieldlist(* Or-type (could be used instead of Container, Cons, Nil, etc.) *)|Constructorofname*exprlist(* very special value *)|Lambdaoffunction_definition(* usually an argument of a New (used in Java, Javascript) *)|AnonClassofclass_definition|Nop(* less: could be merged with L Unit *)(* todo: newvar: sometimes abused to also introduce a newvar (as in Python)
* but ultimately those cases should be rewritten to first introduce a
* VarDef
*)|Nameofname*id_info|IdSpecialofspecialwrap(* operators and function application *)|Callofexpr*arguments(* (XHP, JSX, TSX), could transpile also *)|Xmlofxml(* IntepolatedString of expr list is simulated with a
* Call(IdSpecial (Concat ...)) *)(* The left part should be an lvalue (id, ObjAccess, ArrayAccess, Deref)
* but it can also be a pattern (Tuple, Container), but
* you should really use LetPattern for that.
* Assign can also be abused to declare new variables, but you should use
* variable_definition for that.
* less: should be in stmt, but many languages allow this at expr level
*)|Assignofexpr*expr(* less: should desugar in Assign, should be only binary_operator *)|AssignOpofexpr*arithmetic_operatorwrap*expr(* newvar:! newscope:? in OCaml yes but we miss the 'in' part here *)|LetPatternofpattern*expr(* can also be used for Record, Class, or Module access depending on expr *)|ObjAccessofexpr*ident|ArrayAccessofexpr*expr(* less: slice *)|Conditionalofexpr*expr*expr|MatchPatternofexpr*actionlist(* less: TryFunctional *)|Yieldofexpr|Awaitofexpr|Castoftype_*expr(* less: should be in statement *)|Seqofexprlist(* less: could be in Special *)|Refofexpr(* &, address of *)|DeRefofexpr(* '*' *)|Ellipsesoftok(* for sgrep, and also types in Python *)|OtherExprofother_expr_operator*anylistandliteral=|Boolofboolwrap|Intofstringwrap|Floatofstringwrap|Charofstringwrap|Stringofstringwrap|Regexpofstringwrap|Unitoftok(* a.k.a Void *)|Nulloftok|Undefinedoftok(* JS *)andcontainer_operator=(* Tuple was lifted up *)|Array(* todo? designator? *)|List|Set|Dict(* a.k.a Hash or Map (combine with Tuple to get Key/value pair) *)andspecial=(* special vars *)|This|Super|Self|Parent(* different from This/Super? *)(* special apply *)|Eval|Typeof|Instanceof|Sizeof(* note that certain languages do not have a 'new' keyword (e.g., Python),
* instead certain 'Call' are really 'New' *)|New(* usually associated with Call(New, [ArgType _;...]) *)|Concat(* used for interpolated strings constructs *)|Spread(* inline list var, in Container or call context *)|ArithOpofarithmetic_operator(* should be lift up and transformed in Assign at stmt level *)|IncrDecrof(incr_decr*prefix_postfix)(* mostly binary operator
* less: could be divided in really Arith vs Logical (bool) operators,
* but see is_boolean_operator() helper below.
* Note that Mod can be used for %style string formatting in Python.
* todo? use a Special operator intead for that? but need type info?
*)andarithmetic_operator=|Plus(* unary too *)|Minus(* unary too *)|Mult|Div|Mod|Pow|FloorDiv(* Python *)|LSL|LSR|ASR(* L = logic, A = Arithmetic, SL = shift left *)|BitOr|BitXor|BitAnd|BitNot(* unary *)(* todo? rewrite in CondExpr? have special behavior *)|And|Or(* also shortcut operator *)|Xor(* PHP*)|Not(* unary *)|Eq|NotEq(* less: could be desugared to Not Eq *)|PhysEq|NotPhysEq(* less: could be desugared to Not PhysEq *)|Lt|LtE|Gt|GtE(* less: could be desugared to Or (Eq Lt) *)andincr_decr=Incr|Decrandprefix_postfix=Prefix|Postfix(* newscope: newvar: *)andaction=pattern*expr(* TODO *)andxml=anylistandarguments=argumentlistandargument=(* regular argument *)|Argofexpr(* can be Call (IdSpecial Spread, Id foo) *)(* keyword argument *)|ArgKwdofident*expr(* type argument for New, instanceof/sizeof/typeof, C macros *)|ArgTypeoftype_|ArgOtherofother_argument_operator*anylistandother_argument_operator=(* Python *)|OA_ArgPow(* a kind of Spread, but for Dict instead of List *)|OA_ArgComp(* comprehension *)(* OCaml *)|OA_ArgQuestionandother_expr_operator=(* Javascript *)|OE_Exports|OE_Module|OE_Define|OE_Arguments|OE_NewTarget|OE_Delete|OE_YieldStar|OE_Encaps(* less: convert to regular funcall? *)|OE_Require(* todo: lift to Import? *)|OE_UseStrict(* less: lift up to program attribute/directive? *)|OE_ObjAccess_PN_Computed(* less: convert to ArrayAccess *)(* Python *)|OE_Imag|OE_Is|OE_IsNot(* less: could be part of a set_operator? or PhysEq? *)|OE_In|OE_NotIn(* less: could be part of a obj_operator? *)|OE_Invert|OE_Slice|OE_SliceIndex|OE_SliceRange(* TODO: newvar: *)|OE_CompForIf|OE_CompFor|OE_CompIf|OE_CmpOps|OE_Repr(* Java *)|OE_NameOrClassType|OE_ClassLiteral|OE_NewQualifiedClass(* C *)|OE_GetRefLabel|OE_ArrayInitDesignator|OE_GccConstructor(* transform in New? *)(* PHP *)|OE_Unpack(* OCaml *)|OE_FieldAccessQualified|OE_RecordWith|OE_StmtExpr(* OCaml has just expressions, no statements *)(*****************************************************************************)(* Statement *)(*****************************************************************************)andstmt=(* later: lift Call/Assign/Seq here *)|ExprStmtofexpr|DefStmtofdefinition|DirectiveStmtofdirective(* newscope: in C++/Java *)|Blockofstmtlist|Ifofexpr*stmt*stmt|Whileofexpr*stmt|DoWhileofstmt*expr(* newscope: *)|Foroffor_header*stmt(* less: could be merged with ExprStmt (MatchPattern ...) *)|Switchofexpr*case_and_bodylist|Returnofexpr|Continueofexproption|Breakofexproption(* todo? switch to label? *)|Labeloflabel*stmt|Gotooflabel|Throwofexpr(* a.k.a raise *)|Tryofstmt*catchlist*finallyoption|Assertofexpr*exproption(* message *)(* this is important to correctly compute a CFG *)|OtherStmtWithStmtofother_stmt_with_stmt_operator*expr*stmt(* any here should not contain any statement! otherwise the CFG will be
* incorrect and some analysis (e.g., liveness) will be incorrect.
*)|OtherStmtofother_stmt_operator*anylist(* newscope: *)andcase_and_body=caselist*stmt(* less: could be merged with pattern *)andcase=|Caseofexpr|Default(* newvar: newscope: *)andcatch=pattern*stmt(* newscope: *)andfinally=stmtandlabel=identandfor_header=|ForClassicoffor_var_or_exprlist(* init *)*expr(* cond *)*expr(* next *)(* newvar: *)|ForEachofpattern*expr(* pattern 'in' expr *)andfor_var_or_expr=(* newvar: *)|ForInitVarofentity*variable_definition|ForInitExprofexprandother_stmt_with_stmt_operator=(* Python *)|OSWS_With(* TODO: newvar: in OtherStmtWithStmt with LetPattern
* and newscope: *)andother_stmt_operator=(* Python *)|OS_Delete|OS_ForOrElse|OS_WhileOrElse|OS_TryOrElse|OS_ThrowFrom|OS_ThrowNothing|OS_Global|OS_NonLocal|OS_Pass|OS_Async(* Java *)|OS_Sync(* C *)|OS_Asm(*****************************************************************************)(* Pattern *)(*****************************************************************************)andpattern=|PatLiteralofliteral(* Or-Type *)|PatConstructorofname*patternlist(* And-Type *)|PatRecordoffield_patternlist(* newvar:! *)|PatVarofident*id_info(* Always Local or Param *)(* special cases of PatConstructor *)|PatTupleofpatternlist|PatListofpatternlist|PatKeyValofpattern*pattern(* a kind of PatTuple *)(* special case of PatVar *)|PatUnderscoreoftok(* OCaml *)|PatDisjofpattern*pattern|PatTypedofpattern*type_|PatWhenofpattern*expr|PatAsofpattern*(ident*id_info)|OtherPatofother_pattern_operator*anylistandfield_pattern=name*patternandother_pattern_operator=(* Python *)|OP_Expr(* todo: should transform in pattern when can *)(* Javascript *)|OP_Var(* todo: should transform in pattern when can *)(*****************************************************************************)(* Type *)(*****************************************************************************)andtype_=(* todo? a type_builtin = TInt | TBool | ...? see Literal *)|TyBuiltinofstringwrap(* int, bool, etc. could be TApply with no args *)|TyFunoftype_list(* use parameter? args (not curried) *)*type_(* return type *)(* covers tuples, list, etc. and also regular typedefs *)|TyApplyofname*type_arguments|TyVarofident(* typedef? no type variable in polymorphic type *)(* a special case of TApply, also a special case of TPointer *)|TyArrayof(* const_expr *)exproption*type_|TyPointeroftype_|TyTupleoftype_list|TyQuestionoftype_(* option type *)|OtherTypeofother_type_operator*anylistandtype_arguments=type_argumentlistandtype_argument=|TypeArgoftype_|OtherTypeArgofother_type_argument_operator*anylistandother_type_argument_operator=|OTA_Questionandother_type_operator=(* Python *)|OT_Expr|OT_Arg(* todo: should transform in type_ when can *)(* C *)|OT_StructName|OT_UnionName|OT_EnumName(* PHP *)|OT_Shape|OT_Variadic(* ------------------------------------------------------------------------- *)(* Attribute *)(* ------------------------------------------------------------------------- *)(* a.k.a decorators, annotations *)andattribute=|Static|Volatile|Extern(* for class fields *)|Public|Private|Protected|Abstract|Final(* for vars (JS) *)|Var|Let(* for fields *)|Mutable|Const(* for functions *)|Generator|Async|Recursive|MutuallyRecursive(* for methods *)|Ctor|Dtor|Getter|Setter(* for parameters *)|Variadic(* for general @annotations *)|NamedAttrofident*anylist|OtherAttributeofother_attribute_operator*anylistandother_attribute_operator=(* Java *)|OA_StrictFP|OA_Transient|OA_Synchronized|OA_Native|OA_AnnotJavaOther|OA_AnnotThrow(* Python *)|OA_Expr(* todo: should transform in NamedAttr when can *)(*****************************************************************************)(* Definitions *)(*****************************************************************************)anddefinition=entity*definition_kind(* (or decl) *)andentity={name:ident;attrs:attributelist;type_:type_option;(* less: use ref to enable typechecking *)tparams:type_parameterlist;(* naming/typing *)info:id_info;}(* can have empty "body" when the definition is actually a declaration
* in a header file *)anddefinition_kind=|FuncDefoffunction_definition(* valid for methods too *)(* newvar: *)|VarDefofvariable_definition(* valid for constants and fields too *)|TypeDefoftype_definition|ClassDefofclass_definition|ModuleDefofmodule_definition|MacroDefofmacro_definition|Signatureoftype_(* template/generics/polymorphic *)andtype_parameter=ident*type_parameter_constraintsandtype_parameter_constraints=type_parameter_constraintlistandtype_parameter_constraint=|Extendsoftype_(* ------------------------------------------------------------------------- *)(* Function (or method) definition *)(* ------------------------------------------------------------------------- *)(* less: could be merged with variable_definition *)andfunction_definition={(* less: could be merged in entity.type_ *)fparams:parameters;frettype:type_option;(* return type *)(* newscope: *)fbody:stmt;}andparameters=parameterlist(* newvar: *)andparameter=|ParamClassicofparameter_classic|ParamPatternofpattern|OtherParamofother_parameter_operator*anylist(* less: could be merged with variable_definition, or pattern *)andparameter_classic={pname:ident;pdefault:exproption;ptype:type_option;pattrs:attributelist;(* naming *)pinfo:id_info;(* Always Param *)}andother_parameter_operator=(* Python *)|OPO_KwdParam(* PHP *)|OPO_Ref(* less: or encode in type? *)(* ------------------------------------------------------------------------- *)(* Variable definition *)(* ------------------------------------------------------------------------- *)(* Also used for constant_definition with attrs = [Const].
* Also used for field definition in a class (and record).
* Could also use for function_definition with vinit = Some (Lambda (...))
*)andvariable_definition={(* less: could remove function_definition as expr can be a Lambda but maybe
* useful to explicitely makes the difference for now? *)vinit:exproption;(* less: could merge in entity.type_ *)vtype:type_option;}(* ------------------------------------------------------------------------- *)(* Type definition *)(* ------------------------------------------------------------------------- *)andtype_definition={tbody:type_definition_kind;}andtype_definition_kind=|OrTypeofor_type_elementlist(* enum/ADTs *)(* field.vtype should be defined here *)|AndTypeoffieldlist(* record/struct/union *)|AliasTypeoftype_|Exceptionofident(* same name than entity *)*type_list|OtherTypeKindofother_type_kind_operator*anylistandor_type_element=|OrConstructorofident*type_list|OrEnumofident*expr|OrUnionofident*type_|OtherOrofother_or_type_element_operator*anylistandother_or_type_element_operator=(* Java *)|OOTEO_EnumWithMethods|OOTEO_EnumWithArguments(* Field definition and use, for classes and records *)(* less: could be merged with variable_definition,
* I don't call it field_definition because it's used both to
* define the shape of a field (a definition), and when creating
* an actual field (a value)
*)andfield=|FieldVarofentity*variable_definition|FieldMethodofentity*function_definition|FieldDynamicofexpr(* dynamic name *)*attributelist*expr(* value*)|FieldSpreadofexpr(* usually a Name *)|FieldStmtofstmtandother_type_kind_operator=(* C *)|OTKO_EnumWithValue(* obsolete actually now that has OrEnum *)(* OCaml *)|OTKO_AbstractType(* ------------------------------------------------------------------------- *)(* Class definition *)(* ------------------------------------------------------------------------- *)(* less: could be a special kind of type_definition *)andclass_definition={ckind:class_kind;cextends:type_list;cimplements:type_list;(* newscope: *)cbody:fieldlist;}andclass_kind=|Class|Interface|Trait(* ------------------------------------------------------------------------- *)(* Module definition (a.k.a package, a.k.a namespace) *)(* ------------------------------------------------------------------------- *)andmodule_definition={mbody:module_definition_kind;}andmodule_definition_kind=|ModuleAliasofname(* newscope: *)|ModuleStructofdotted_identoption*itemlist|OtherModuleofother_module_operator*anylistandother_module_operator=(* OCaml *)|OMO_Functor(* ------------------------------------------------------------------------- *)(* Macro definition *)(* ------------------------------------------------------------------------- *)andmacro_definition={macroparams:identlist;macrobody:anylist;}(*****************************************************************************)(* Directives (Module import/export, macros) *)(*****************************************************************************)anddirective=(* newvar: *)|ImportFromofmodule_name*aliaslist|ImportAsofmodule_name*identoption(* as name *)|OtherDirectiveofother_directive_operator*anylistandalias=ident*identoption(* as name *)andother_directive_operator=(* Javascript *)|OI_Export|OI_ImportCss|OI_ImportEffect(*****************************************************************************)(* Toplevel *)(*****************************************************************************)(* less: should merge stmt, item, and field? *)anditem=|IStmtofstmt(* could be removed since they are as LocalDef and LocalDirective in stmt *)|IDefofdefinition|IDirofdirectiveandprogram=itemlist(*****************************************************************************)(* Any *)(*****************************************************************************)(* mentioned in many OtherXxx so must be part of the mutually recursive type *)andany=|Idofident|Nofname|Enofentity|Eofexpr|Sofstmt|Toftype_|Pofpattern|Defofdefinition|Dirofdirective|Iofitem|Paofparameter|Arofargument|Atofattribute|Dkofdefinition_kind|Diofdotted_ident|Fldoffield|Ssofstmtlist|Profprogram(* with tarzan *)(*****************************************************************************)(* Wrappers *)(*****************************************************************************)letstr_of_name=fst(*****************************************************************************)(* Error *)(*****************************************************************************)(* this can be used in the xxx_to_generic.ml file to signal limitations *)exceptionErrorofstring*Parse_info.tleterrortokmsg=raise(Error(msg,tok))(*****************************************************************************)(* Helpers *)(*****************************************************************************)(* use 0 for globals, if needed *)letgensym_counter=ref0letgensym()=incrgensym_counter;!gensym_counterletempty_name_info={name_qualifier=None;name_typeargs=None;}letempty_id_info()={id_resolved=refNone;id_type=refNone;}letbasic_paramid={pname=id;pdefault=None;ptype=None;pattrs=[];pinfo=empty_id_info();}letbasic_entityidattrs={name=id;attrs=attrs;type_=None;tparams=[];info=empty_id_info();}letbasic_fieldidtypeopt=letentity=basic_entityid[]inFieldVar(entity,{vinit=None;vtype=typeopt})letempty_var()={vinit=None;vtype=None}letexpr_to_arge=Argeletentity_to_param{name;attrs;type_;tparams=_unused;info}={pname=name;pdefault=None;ptype=type_;pattrs=attrs;pinfo=info;}letopt_to_nopopt=matchoptwith|None->Nop|Somee->eletopt_to_nameopt=matchoptwith|None->"FakeNAME",Parse_info.fake_info"FakeNAME"|Somen->nletstmt1xs=matchxswith|[]->Block[]|[st]->st|xs->Blockxs(* todo? sign that should merge field with item and stmt? *)letstmt_to_fieldst=matchstwith|DefStmt(entity,VarDefdef)->FieldVar(entity,def)|DefStmt(entity,FuncDefdef)->FieldMethod(entity,def)|_->FieldStmtst(* less: could be a Block containing LocalDef or LocalDirective *)letstmt_to_itemst=matchstwith|DefStmtdef->IDefdef|DirectiveStmtdir->IDirdir|_->IStmtstletis_boolean_operator=function|Plus(* unary too *)|Minus(* unary too *)|Mult|Div|Mod|Pow|FloorDiv(* Python *)|LSL|LSR|ASR(* L = logic, A = Arithmetic, SL = shift left *)|BitOr|BitXor|BitAnd|BitNot(* unary *)->false|And|Or|Xor|Not|Eq|NotEq|PhysEq|NotPhysEq|Lt|LtE|Gt|GtE->trueletvardef_to_assign(ent,def)resolved=letidinfo={(empty_id_info())withid_resolved=refresolved}inletname=Name((ent.name,empty_name_info),idinfo)inletv=opt_to_nopdef.vinitinAssign(name,v)letfuncdef_to_lambda(ent,def)resolved=letidinfo={(empty_id_info())withid_resolved=refresolved}inletname=Name((ent.name,empty_name_info),idinfo)inletv=LambdadefinAssign(name,v)