@@ -30,6 +30,156 @@ const builtInTypes = new Set([
3030 /* src/include/nodes/nodes.h */
3131 'Cost' , 'Selectivity' , 'Cardinality' , 'ParseLoc' , 'NodeTag' ,
3232] ) ;
33+ const identifierRegex = / ^ [ a - z A - Z _ ] [ a - z A - Z 0 - 9 _ ] * $ / ;
34+
35+ /**
36+ * Check that given string represents valid C identifier.
37+ * Identifier can represent struct fields, type names, variable names etc...
38+ *
39+ * @param value String to test
40+ * @returns true if string represents valid C identifier
41+ */
42+ export function isValidIdentifier ( value : string ) {
43+ return identifierRegex . test ( value ) ;
44+ }
45+
46+ export function getStructNameFromType ( type : string ) {
47+ /* [const] [struct] NAME [*]+ */
48+ /*
49+ * Start locating from end, because we can use '*' as the boundary of
50+ * typename end.
51+ *
52+ * During some manual testing observed common behavior of debuggers:
53+ * after type name can be only pointer - that is no qualifiers will follow.
54+ *
55+ * i.e. declared in src -> DAP 'type':
56+ *
57+ * PlannerInfo const * -> const PlannerInfo *
58+ * int volatile * const -> volatile int * const
59+ * int const * const -> const int * const;
60+ * const Relids -> const Relids
61+ *
62+ * XXX: this is broken for FLA (they have [] at the end), but they
63+ * don't get here yet, so don't worry.
64+ */
65+ const lastPtrIndex = type . indexOf ( '*' ) ;
66+ let endOfIdentifier ;
67+ if ( lastPtrIndex === - 1 ) {
68+ /* Type without any pointer */
69+ endOfIdentifier = type . length ;
70+ } else {
71+ endOfIdentifier = lastPtrIndex - 1 ;
72+ while ( endOfIdentifier >= 0 && type . charAt ( endOfIdentifier ) === ' ' ) {
73+ endOfIdentifier -- ;
74+ continue ;
75+ }
76+
77+ /*
78+ * Another observation is that all debuggers add spaces around pointers,
79+ * so one might think we can omit such check. But do not forget that
80+ * we are working with *effective* types - after we have substituted
81+ * aliased typename and user can omit spaces in between.
82+ */
83+ if ( endOfIdentifier < 0 ) {
84+ endOfIdentifier = lastPtrIndex ;
85+ }
86+ }
87+
88+ /* Search for start of typename - it must be first space before typename */
89+ let startOfIndentifier = type . lastIndexOf ( ' ' , endOfIdentifier ) ;
90+ if ( startOfIndentifier === - 1 ) {
91+ /* Type without any qualifiers */
92+ startOfIndentifier = 0 ;
93+ } else {
94+ startOfIndentifier ++ ;
95+ }
96+
97+ return type . substring ( startOfIndentifier , endOfIdentifier + 1 ) ;
98+ }
99+
100+ /**
101+ * Substitute struct name from type to provided struct name.
102+ * This takes qualifiers into account (const, volatile, *, etc...)
103+ *
104+ * @param type Whole type name of original variable (including qualifiers)
105+ * @param target The name of the type (or base type) to be substituted
106+ * @returns Result type name
107+ */
108+ export function substituteStructName ( type : string , target : string ) {
109+ const typename = getStructNameFromType ( type ) ;
110+ return type . replace ( typename , target ) ; }
111+
112+ /*
113+ * Check that 'type' contains exact count of pointers in it
114+ */
115+ export function havePointersCount ( type : string , count : number ) {
116+ const firstIndex = type . indexOf ( '*' ) ;
117+
118+ /* For now only 0 and 1 will be used, so add specialized codepath */
119+ if ( count === 0 ) {
120+ return firstIndex === - 1 ;
121+ }
122+ if ( count === 1 ) {
123+ return firstIndex !== - 1 && firstIndex === type . lastIndexOf ( '*' ) ;
124+ }
125+
126+ let result = 1 ;
127+ let index = firstIndex ;
128+ while ( ( index = type . indexOf ( '*' , index + 1 ) ) !== - 1 ) {
129+ ++ result ;
130+ }
131+
132+ return result === count ;
133+ }
134+
135+ /**
136+ * Check that type represent either value struct or pointer type, i.e.
137+ * it is not array type. Roughly speaking, type contains at most 1 pointer.
138+ *
139+ * @param type Type specifier
140+ * @returns Type represents plain value struct or pointer type
141+ */
142+ export function isValueStructOrPointerType ( type : string ) {
143+ const firstPointerPos = type . indexOf ( '*' ) ;
144+ if ( firstPointerPos === - 1 ) {
145+ /* Value struct */
146+ return true ;
147+ }
148+
149+ const secondPointerPos = type . indexOf ( '*' , firstPointerPos + 1 ) ;
150+ if ( secondPointerPos === - 1 ) {
151+ /* Pointer type, not array */
152+ return true ;
153+ }
154+
155+ return false ;
156+ }
157+
158+ /**
159+ * Check that output from evaluation is correct enum value.
160+ * That is it is not error message, pointer or something else.
161+ * So, 'result' looks like real enum value.
162+ *
163+ * @returns 'true' if looks like enum value, 'false' otherwise
164+ */
165+ export function isEnumResult ( result : string ) {
166+ return isValidIdentifier ( result ) ;
167+ }
168+
169+ export function isFlexibleArrayMember ( type : string ) {
170+ return type . endsWith ( '[]' ) ;
171+ }
172+
173+ /**
174+ * Shortcut function to test that pointer is NULL.
175+ * Used for situations, where only pointer value is present, without variable.....
176+ *
177+ * @param pointer Pointer value in HEX form
178+ * @returns true if pointer value is NULL
179+ */
180+ export function pointerIsNull ( pointer : string ) {
181+ return pointer === '0x0' || / 0 x 0 + / . test ( pointer ) ;
182+ }
33183
34184export enum DebuggerType {
35185 CppDbg ,
@@ -950,17 +1100,6 @@ export class CodeLLDBDebuggerFacade extends GenericDebuggerFacade {
9501100 }
9511101}
9521102
953- /**
954- * Shortcut function to test that pointer is NULL.
955- * Used for situations, where only pointer value is present, without variable.....
956- *
957- * @param pointer Pointer value in HEX form
958- * @returns true if pointer value is NULL
959- */
960- export function pointerIsNull ( pointer : string ) {
961- return pointer === '0x0' || / 0 x 0 + / . test ( pointer ) ;
962- }
963-
9641103export function setupDebugger ( context : vscode . ExtensionContext ,
9651104 variablesView : PgVariablesViewProvider ) {
9661105 if ( ! Features . debugFocusEnabled ( ) ) {
0 commit comments