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