-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeserializeLisp.js
More file actions
127 lines (106 loc) · 3.04 KB
/
deserializeLisp.js
File metadata and controls
127 lines (106 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
* Deserializes a Lisp S-expression string into a structured format while preserving whitespace
* @param {string} input The Lisp S-expression string
* @returns {Object} A structured representation with both content and whitespace information
*/
function deserializeLisp(input) {
let pos = 0;
const len = input.length;
function isWhitespace(char) {
return /[\s\n\r\t]/.test(char);
}
function readWhitespace() {
let ws = '';
while (pos < len && isWhitespace(input[pos])) {
ws += input[pos];
pos++;
}
return ws;
}
function readString() {
let str = '"';
pos++; // Skip opening quote
while (pos < len && input[pos] !== '"') {
// Handle escape sequences
if (input[pos] === '\\' && pos + 1 < len) {
str += input[pos];
pos++;
str += input[pos];
pos++;
} else {
str += input[pos];
pos++;
}
}
if (pos < len && input[pos] === '"') {
str += '"';
pos++; // Skip closing quote
}
return str;
}
function readToken() {
let token = '';
// Handle strings specially
if (input[pos] === '"') {
return readString();
}
while (pos < len && !isWhitespace(input[pos]) && input[pos] !== '(' && input[pos] !== ')') {
token += input[pos];
pos++;
}
return token;
}
function parseExpression() {
const beforeWs = readWhitespace();
if (pos >= len) {
return {
type: 'empty',
beforeWs,
afterWs: ''
};
}
// Handle opening parenthesis
if (input[pos] === '(') {
pos++; // Skip opening paren
const items = [];
let insideWs = readWhitespace();
while (pos < len && input[pos] !== ')') {
const item = parseExpression();
if (item.type !== 'empty') {
items.push(item);
}
insideWs = readWhitespace();
}
if (pos < len && input[pos] === ')') {
pos++; // Skip closing paren
}
const afterWs = readWhitespace();
return {
type: 'list',
items,
beforeWs,
insideWs,
afterWs
};
}
// Handle atom
const value = readToken();
if (!value) {
return {
type: 'empty',
beforeWs,
afterWs: ''
};
}
const afterWs = readWhitespace();
return {
type: 'atom',
value,
beforeWs,
afterWs
};
}
const result = parseExpression();
return result;
}
module.exports = deserializeLisp;