1
+ import { ILispFragment } from './ILispFragment' ;
2
+ import { Position , Range } from 'vscode' ;
3
+ import { Sexpression } from './sexpression' ;
4
+
5
+
6
+ // General purpose test for basic known primitive values; Including: T, NIL, Number, (single or multi-line) Strings & Comments
7
+ export const primitiveRegex = / ^ ( [ \( \) \' \. ] | " [ \s \S ] * " | ; [ \s \S ] * | ' ? [ t T ] | ' ? [ n N ] [ i I ] [ l L ] | ' ? - ? \d + [ e E ] [ + - ] ? \d + | - ? \d + | - ? \d + \. \d + ) $ / ;
8
+ const primitiveGlyphs = [ '\'' , '(' , ')' , '.' , ';' ] ; //, '']; //, null, undefined];
9
+
10
+
11
+ // Represents the most fundamental building blocks of a lisp document
12
+ export class LispAtom implements ILispFragment {
13
+ public symbol : string ;
14
+ protected _line : number ;
15
+ protected _column : number ;
16
+
17
+ get line ( ) : number {
18
+ return this . _line ;
19
+ }
20
+
21
+ set line ( value ) {
22
+ this . _line = value ;
23
+ }
24
+
25
+ get column ( ) : number {
26
+ return this . _column ;
27
+ }
28
+
29
+ set column ( value ) {
30
+ this . _column = value ;
31
+ }
32
+
33
+ // These 3 fields exist to support comment driven intelligence. Creation of Symbol mappings is an expensive operation
34
+ // and these 2 fields prevent ~80% of the required overhead when working in concert with the highly efficient parser
35
+ public flatIndex : number ;
36
+ public commentLinks ?: Array < number > ;
37
+ public hasGlobalFlag ?: boolean ;
38
+
39
+ constructor ( line : number , column : number , sym : string , flatIdx = - 1 ) {
40
+ this . _line = line ;
41
+ this . _column = column ;
42
+ this . symbol = sym ;
43
+ this . flatIndex = flatIdx ;
44
+ }
45
+
46
+
47
+ // Does a simple comparison between 2 ILispFragments without the reference problem
48
+ equal ( atom : ILispFragment ) : boolean {
49
+ return JSON . stringify ( this ) === JSON . stringify ( atom ) ;
50
+ }
51
+
52
+
53
+ // Determines if this LispAtom or its derived type can be used as an ILispFragment
54
+ isLispFragment ( ) : boolean {
55
+ if ( this instanceof Sexpression ) {
56
+ return false ;
57
+ } else {
58
+ return true ;
59
+ }
60
+ }
61
+
62
+
63
+ // returns the start or ending line of the LispAtom depending on the boolean flag
64
+ symbLine ( last : boolean = true ) : number {
65
+ if ( last ) {
66
+ let internalLines = 0 ;
67
+ if ( this . symbol . startsWith ( ';|' ) ) {
68
+ for ( let i = 0 ; i < this . symbol . length ; i ++ ) {
69
+ if ( this . symbol . charAt ( i ) === '\n' ) { // it can handle the \r\n and \n
70
+ internalLines ++ ;
71
+ }
72
+ }
73
+ }
74
+ return this . line + internalLines ;
75
+ } else {
76
+ return this . line ;
77
+ }
78
+ }
79
+
80
+
81
+ // Returns the length of the LispAtom's text value
82
+ length ( ) : number {
83
+ return this . symbol . length ;
84
+ }
85
+
86
+
87
+ // Tests if the LispAtom is representing a single-line comment
88
+ isLineComment ( ) : boolean {
89
+ return this . symbol . startsWith ( ';' ) && ! this . symbol . startsWith ( ';|' ) ;
90
+ }
91
+
92
+
93
+ // Tests if the LispAtom is representing any type of comment
94
+ isComment ( ) : boolean {
95
+ return this . symbol . startsWith ( ';' ) ;
96
+ }
97
+
98
+
99
+ // Tests if the LispAtom is representing a structural closing parenthesis
100
+ isRightParen ( ) : boolean {
101
+ return this . symbol === ')' ;
102
+ }
103
+
104
+
105
+ // Tests if the LispAtom is representing a structural opening parenthesis
106
+ isLeftParen ( ) : boolean {
107
+ return this . symbol === '(' ;
108
+ }
109
+
110
+ isPrimitive ( ) : boolean {
111
+ // if (!this['atoms']) {
112
+ // return primitiveRegex.test(this.symbol);
113
+ // }
114
+ // return false;
115
+ return primitiveGlyphs . indexOf ( this . symbol [ 0 ] ) > - 1
116
+ || primitiveRegex . test ( this . symbol ) ;
117
+ }
118
+
119
+ // Returns true if this LispAtom encapsulates the provided Position
120
+ contains ( position : Position ) : boolean {
121
+ return this . getRange ( ) . contains ( position ) ;
122
+ }
123
+
124
+
125
+ // Gets the full range of the LispAtom and is capable of handling multi line strings or comments
126
+ getRange ( ) : Range {
127
+ let cLine = this . line ;
128
+ let cColm = this . column ;
129
+ const begin : Position = new Position ( cLine , cColm ) ;
130
+ for ( let i = 0 ; i < this . symbol . length ; i ++ ) {
131
+ const ch = this . symbol [ i ] ;
132
+ if ( ch === '\n' ) {
133
+ cLine += 1 ;
134
+ cColm = 0 ;
135
+ } else {
136
+ cColm += 1 ;
137
+ }
138
+ }
139
+ const close : Position = new Position ( cLine , cColm ) ;
140
+ return new Range ( begin . line , begin . character , close . line , close . character ) ;
141
+ }
142
+
143
+ }
0 commit comments