tools-scripts/Complie-script/comple/lexer.mjs

131 lines
3.6 KiB
JavaScript
Raw Normal View History

2024-11-20 19:07:12 +08:00
// lexer.mjs
import { token } from './token.mjs';
export class Lexer {
constructor(string) {
this.string = string;
this.pos = 0;
}
advance() {
return this.string[this.pos++];
}
lookAhead() {
return this.string[this.pos];
}
trimQuotes(str) {
return str.replace(/^['"]|['"]$/g, ''); // Remove surrounding quotes
}
lex() {
let text = '';
while (true) {
let t = this.advance();
let tokenResult = ''; // Renamed to avoid conflict with outer token variable
switch (t) {
case '<':
if (this.lookAhead() === '/') {
tokenResult = this.handleEndTag();
} else {
tokenResult = this.handleStartTag();
}
break;
case '\n':
break;
case ' ':
if (text !== '') {
text += t;
} else {
break;
}
break;
case undefined:
if (this.pos >= this.string.length) {
tokenResult = [token.eof, 'eof', []];
break;
}
break;
default:
text += t;
tokenResult = this.handleTextTag(text);
break;
}
this.string = this.string.slice(this.pos);
this.pos = 0;
if (tokenResult !== '') {
return tokenResult;
}
}
}
handleStartTag() {
let idx = this.string.indexOf('>');
if (idx === -1) {
throw new Error('parse err! miss match ' + '>');
}
let str = this.string.slice(this.pos, idx);
let s = '';
if (str.includes(' ')) {
s = str.split(' ')[0]; // Fixed splitting logic
} else {
s = str;
}
let type = s.slice(1);
this.pos += type.length;
let props = this.handlePropTag();
this.advance();
return [token.startTag, type, props];
}
handlePropTag() {
let idx = this.string.indexOf('>');
if (idx == -1) {
throw new Error('parse err! miss match ' + '>');
}
let string = this.string.slice(this.pos, idx);
let pm = [];
if (string.trim() != '') { // Checking if string is not empty
let props = string.split(' ');
pm = props.filter((prop) => {
return prop != '';
}).map((prop) => {
let kv = prop.split('=');
let o = {};
// Ensure kv[1] exists before calling trimQuotes
if (kv[1]) {
o[kv[0]] = this.trimQuotes(kv[1]);
} else {
o[kv[0]] = ''; // Or assign a default value
}
return o;
});
this.pos += string.length;
}
return pm;
}
handleEndTag() {
this.advance();
let idx = this.string.indexOf('>');
let type = this.string.slice(this.pos, idx);
this.pos += type.length;
if (this.advance() !== '>') {
throw new Error('parse err! miss match ' + '>');
}
return [token.endTag, type, []];
}
handleTextTag(text) {
let t = text.trim();
if (this.lookAhead() === '<') {
return [token.text, t, []];
} else {
return '';
}
}
}