util.mli 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. (** Utility functions used by multiple phases. *)
  2. open Types
  3. (** {2 Generating variables} *)
  4. (** Generate a new identifier from a given base, e.g. ["foo"] becomes
  5. ["_foo_1"]. Uses an [int] reference defined in the implementation file as a
  6. counter to assert uniqueness of the generated variable. *)
  7. val fresh_id : string -> string
  8. (** Generate a new constant (a variable that is known to be assigned only once
  9. in total) from a given id, e.g. ["foo"] becomes ["_foo_1_"]. Uses the same
  10. counter as {!fresh_id}. *)
  11. val fresh_const : string -> string
  12. (** Check if an identifier is generated by the compiler. *)
  13. val is_generated_id : string -> bool
  14. (** Check if an identifier is a constant generated by the compiler. *)
  15. val is_const_id : string -> bool
  16. (** Generate an identifier from a base and a number.
  17. E.g., [generate_id "foo" 1] returns ["_foo_1"]*)
  18. val generate_id : string -> int -> string
  19. (** Generate a constant identifier from a base and a number.
  20. E.g., [generate_id "foo" 1] returns ["_foo_1_"]*)
  21. val generate_const : string -> int -> string
  22. (** Array dimensions are a special case sine they are suffixed by a non-fresh
  23. number (the dimension index), therefore an additional underscore is prefixed
  24. to assert uniqueness *)
  25. val generate_array_dim : string -> int -> string
  26. (** {2 AST traversal} *)
  27. (** Default transformation traversal for AST nodes of arbitrary constructor:
  28. [traverse unit_type fold_results visit_node node]. For each constructor that
  29. has one or more children of type {!Types.node}, the children are transformed
  30. with the given transformation function. A [(node, result)] tuple is
  31. returned, where the secondary result has the type of the given unit type.
  32. [visit_node] must also return such a tuple. [fold_results] is used to reduce
  33. results of multiple children to a single result.
  34. For [Program] nodes, {!flatten_blocks} is called on the resulting
  35. declaration list. This allows the transformation function to return multiple
  36. nodes as a replacement, in the form of a [Block] node with multiple
  37. children. *)
  38. val traverse : 'a -> ('a -> 'a -> 'a) -> (node -> (node * 'a)) -> node ->
  39. (node * 'a)
  40. (** Wrapper for {!traverse} that ignores the secondary traversal result. Returns
  41. {!Types.node} instead of a tuple. *)
  42. val traverse_unit : (node -> node) -> node -> node
  43. (** Wrapper for {!traverse} for list results. Defined as:
  44. [let traverse_list visit = traverse [] (@) visit] *)
  45. val traverse_list : (node -> (node * 'a list)) -> node -> (node * 'a list)
  46. (** Flatten [Block] nodes into containing node lists.
  47. E.g., [[A; Block [B; Block [C; D]]; E] -> [A; B; C; D; E]].
  48. Traverses into elements of the list recursively first, so this is
  49. essentially a traversal, as can be seen in the example. Therefore the best
  50. practice is to call this function once on the children of a [Program] node
  51. after any traversal that may generate [Block] nodes that need to be
  52. flattened. *)
  53. val flatten_blocks : node list -> node list
  54. (** Extract the list of child nodes from a [Block] node. *)
  55. val block_body : node -> node list
  56. (** {2 AST node annotations} *)
  57. (** Add a single annotation to a node. *)
  58. val annotate : annotation -> node -> node
  59. (** Extract annotations from a node of arbitrary constructor. *)
  60. val annof : node -> annotation list
  61. (** Get the value of the [Loc] annotation of a node, or {!noloc} if no location
  62. can be found. *)
  63. val locof : node -> location
  64. (** Empty node location: [("", 0, 0, 0, 0)]. Used then location of a node is
  65. unknown (if the annotation was removed at some point) or
  66. non-existant/irrelevant (for generated nodes on which no errors will occur --
  67. hopefully...). *)
  68. val noloc : location
  69. (** Get the value of the [Depth] annotation of a node. Raises
  70. {!Types.InvalidNode} if the annotation can not be found. *)
  71. val depthof : node -> int
  72. (** Get the value of the [Index] annotation of a node. Raises
  73. {!Types.InvalidNode} if the annotation can not be found. *)
  74. val indexof : node -> int
  75. (** Get the value of the [Type] annotation of a node. Some node types
  76. do not need to be annotated since they have inherent types. For example, a
  77. [VarDec] node has a type attribute, and a [Dim] node is always an [Int]
  78. (because array dimensions are integers). All nodes which have inherent types
  79. are [VarDec], [Param], [FunDec], [FunDef], [GlobalDec], [GlobalDef],
  80. [TypeCast], and [Dim]. Raises a {!Types.InvalidNode} if the annotation can
  81. not be found, and the type has no inherent type. *)
  82. val typeof : node -> ctype
  83. (** Get the value of the [LabelName] annotation of a node. Raises
  84. {!Types.InvalidNode} if the annotation can not be found. *)
  85. val labelof : node -> string
  86. (** Get the basic type of a declaration, removing array dimensions *)
  87. val basetypeof : node -> ctype
  88. (** Get the value of the name attribute from a variable or function declaration
  89. (similar to {!typeof} for nodes that have types attributes). Raises
  90. {!Types.InvalidNode} if the node is not one of [GlobalDec], [GlobalDef],
  91. [FunDec], [FunDef], [VarDec], [Param], or [Dim]. *)
  92. val nameof : node -> string
  93. (** Get the CiviC data type of a constant value. *)
  94. val const_type : const -> ctype
  95. (** Check if a constant value is eligible for creating optimized assembly
  96. instructions. E.g. [Intval (-1)] is eligible because the instruction
  97. [iloadc_m1] exists. Used to decide on which {!Types.instr} constructor to
  98. use during the assembly phases. This function always returns [false] when
  99. optimizations are disabled (when {!Globals.args}[.optimize = false]). *)
  100. val is_immediate_const : const -> bool
  101. (** Check if a node has an array type. I.e., [Array] or [ArrayDims]. *)
  102. val is_array : node -> bool
  103. (** {2 Logging} *)
  104. (** Horizontal line of ['-'] characters, used to separate output sections. *)
  105. val hline : string
  106. (** Print the stringification of a node to [stderr] (uses
  107. {!Stringify.node2str}). *)
  108. val prt_node : node -> unit
  109. (** Output a line to stderr if the verbosity level in {!Globals.args} is at
  110. least as high as the specified verbosity level. The line is indented with a
  111. number of spaces to match the longest phase identifier (so that logged lines
  112. align with identifiers logged by {!Main}). A newline is added automatically.
  113. *)
  114. val log_line : int -> string -> unit
  115. (** Print a line to [stderr] without indent (but do add a newline). *)
  116. val log_plain_line : int -> string -> unit
  117. (** Same as {!log_line}, but prints a node stringification instead of a literal
  118. string. *)
  119. val log_node : int -> node -> unit
  120. (** Generate an location tuple from Lexing data structures *)
  121. val loc_from_lexpos : Lexing.position -> Lexing.position -> location
  122. (** Print location tuple to stderr. Produces
  123. something like the following: {v
  124. int foo;
  125. ^^^ v}
  126. The location tuple is likely to originate from a node annotation, extracted
  127. using {!locof}.*)
  128. val prerr_loc : location -> unit
  129. (** Print location tuple to stderr, along with an error message. Produces
  130. something like the following: {v
  131. File "foo.cvc", line 10, characters 8-11:
  132. <message>
  133. int foo;
  134. ^^^ v} *)
  135. val prerr_loc_msg : location -> string -> unit
  136. (** Print an error message for a node. Calls {!prerr_loc_msg}. *)
  137. val node_error : node -> string -> unit
  138. (** Print a warning message for a node. Calls {!prerr_loc_msg}. *)
  139. val node_warning : node -> string -> unit
  140. (** Print an error message of type {!Types.error_msg}. *)
  141. val print_error : error_msg -> unit
  142. (** Raise a {!Types.FatalError} if the given error list is not empty, and
  143. print the errors before quitting. *)
  144. val quit_on_error : error_msg list -> node -> node
  145. (** {2 String utilities} *)
  146. (** [repeat s n] returns a new string of [n] times [s]. *)
  147. val repeat : string -> int -> string
  148. (** [expand n s] adds spaces to [s] until the resulting string is at least [n]
  149. characters long. *)
  150. val expand : int -> string -> string
  151. (** {2 List utilities} *)
  152. (** [optmap f opt] maps [f] to the list value of [opt] if [opt] exists, and
  153. [None] otherwise. *)
  154. val optmap : ('a -> 'b) -> 'a list option -> 'b list option
  155. (** Same as {!optmap}, but returns the list value instead, or an empty list if
  156. [opt] is [None]. *)
  157. val optmapl : ('a -> 'b) -> 'a list option -> 'b list
  158. (** [List.mapi] clone (only available in OCaml version >= 4.00. Maps a function
  159. to a list like [List.map] does, but the iterator function is called with the
  160. element's index as an additional argument. *)
  161. val mapi : (int -> 'a -> 'b) -> 'a list -> 'b list
  162. (** {2 List utilities} *)
  163. (** [optdo f opt] applies [f] to the value of [opt] if [opt] exists, and
  164. returns [None] otherwise. *)
  165. val optdo : ('a -> 'b) -> 'a option -> 'b option