1 /*------------------------------------------------------------------------- 2 * A stack of automaton states to handle nested conditionals. 3 * 4 * This file describes a stack of automaton states which 5 * allow a manage nested conditionals. 6 * 7 * It is used by: 8 * - "psql" interpreter for handling \if ... \endif 9 * - "pgbench" interpreter for handling \if ... \endif 10 * - "pgbench" syntax checker to test for proper nesting 11 * 12 * The stack holds the state of enclosing conditionals (are we in 13 * a true branch? in a false branch? have we already encountered 14 * a true branch?) so that the interpreter knows whether to execute 15 * code and whether to evaluate conditions. 16 * 17 * Copyright (c) 2000-2019, PostgreSQL Global Development Group 18 * 19 * src/include/fe_utils/conditional.h 20 * 21 *------------------------------------------------------------------------- 22 */ 23 #ifndef CONDITIONAL_H 24 #define CONDITIONAL_H 25 26 /* 27 * Possible states of a single level of \if block. 28 */ 29 typedef enum ifState 30 { 31 IFSTATE_NONE = 0, /* not currently in an \if block */ 32 IFSTATE_TRUE, /* currently in an \if or \elif that is true 33 * and all parent branches (if any) are true */ 34 IFSTATE_FALSE, /* currently in an \if or \elif that is false 35 * but no true branch has yet been seen, and 36 * all parent branches (if any) are true */ 37 IFSTATE_IGNORED, /* currently in an \elif that follows a true 38 * branch, or the whole \if is a child of a 39 * false parent branch */ 40 IFSTATE_ELSE_TRUE, /* currently in an \else that is true and all 41 * parent branches (if any) are true */ 42 IFSTATE_ELSE_FALSE /* currently in an \else that is false or 43 * ignored */ 44 } ifState; 45 46 /* 47 * The state of nested \ifs is stored in a stack. 48 * 49 * query_len is used to determine what accumulated text to throw away at the 50 * end of an inactive branch. (We could, perhaps, teach the lexer to not add 51 * stuff to the query buffer in the first place when inside an inactive branch; 52 * but that would be very invasive.) We also need to save and restore the 53 * lexer's parenthesis nesting depth when throwing away text. (We don't need 54 * to save and restore any of its other state, such as comment nesting depth, 55 * because a backslash command could never appear inside a comment or SQL 56 * literal.) 57 */ 58 typedef struct IfStackElem 59 { 60 ifState if_state; /* current state, see enum above */ 61 int query_len; /* length of query_buf at last branch start */ 62 int paren_depth; /* parenthesis depth at last branch start */ 63 struct IfStackElem *next; /* next surrounding \if, if any */ 64 } IfStackElem; 65 66 typedef struct ConditionalStackData 67 { 68 IfStackElem *head; 69 } ConditionalStackData; 70 71 typedef struct ConditionalStackData *ConditionalStack; 72 73 74 extern ConditionalStack conditional_stack_create(void); 75 76 extern void conditional_stack_destroy(ConditionalStack cstack); 77 78 extern int conditional_stack_depth(ConditionalStack cstack); 79 80 extern void conditional_stack_push(ConditionalStack cstack, ifState new_state); 81 82 extern bool conditional_stack_pop(ConditionalStack cstack); 83 84 extern ifState conditional_stack_peek(ConditionalStack cstack); 85 86 extern bool conditional_stack_poke(ConditionalStack cstack, ifState new_state); 87 88 extern bool conditional_stack_empty(ConditionalStack cstack); 89 90 extern bool conditional_active(ConditionalStack cstack); 91 92 extern void conditional_stack_set_query_len(ConditionalStack cstack, int len); 93 94 extern int conditional_stack_get_query_len(ConditionalStack cstack); 95 96 extern void conditional_stack_set_paren_depth(ConditionalStack cstack, int depth); 97 98 extern int conditional_stack_get_paren_depth(ConditionalStack cstack); 99 100 #endif /* CONDITIONAL_H */ 101