You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.2 KiB
JavaScript
115 lines
2.2 KiB
JavaScript
const KEYWORDS = [
|
|
"let",
|
|
"for",
|
|
"print",
|
|
"input",
|
|
"//"
|
|
];
|
|
|
|
const TYPES = [
|
|
"int",
|
|
"float",
|
|
"string",
|
|
"bool"
|
|
];
|
|
|
|
const PATTERNS = [
|
|
"asgn": [ "ident", "eq", "expr" ],
|
|
"let": [ "type", "ident", "eq?", "expr" ],
|
|
];
|
|
|
|
class UnexpectedTokenError extends SyntaxError {
|
|
constructor (expectedTokens, token, line, col) {
|
|
const expected = expectedTokens.map((t) => `"${t}"`).join(", ");
|
|
super(`Expected ${expected} but got ${token}`);
|
|
this.lineNumber = line;
|
|
this.columnNumber = col;
|
|
}
|
|
}
|
|
|
|
class UnexpectedEndOfInputError {
|
|
constructor (line, col) {
|
|
super(`Unexpected end of input at ${line}:${col}.`);
|
|
}
|
|
}
|
|
|
|
const inPath = Deno.args[0];
|
|
const dec = new TextDecoder("utf-8);
|
|
const raw = Deno.readFile(inPath);
|
|
const input = dec.decode(raw);
|
|
|
|
const lines = input.split("\n");
|
|
|
|
let tree = [];
|
|
let stack = [];
|
|
let ctx = "";
|
|
|
|
// keyword, ident, type, num, string, op, group, eof
|
|
let expectedTokens = ["keyword", "ident"];
|
|
let tokenType = null;
|
|
// ` `, `{`, `}`
|
|
let delim = " ";
|
|
let token = "";
|
|
|
|
let idents = [];
|
|
|
|
for (let line = 0; line < lines.length; line++) {
|
|
const currentLine = lines[line];
|
|
for (let col = 0; col < currentLine.length; col++) {
|
|
if (currentLine[col] === delim) {
|
|
tokenType = null;
|
|
const tokenHandlers = {
|
|
"keyword": () => {
|
|
if (KEYWORDS.includes(token)) {
|
|
stack.push(token);
|
|
tokenType = "keyword";
|
|
}
|
|
},
|
|
"ident": () => {
|
|
if (idents.includes(token)) {
|
|
stack.push(token);
|
|
idents.push(token);
|
|
tokenType = "ident";
|
|
}
|
|
},
|
|
};
|
|
|
|
for (type in expectedTokens) {
|
|
tokenHandlers[type]();
|
|
if (tokenType !== null) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!expectedTokens.includes(tokenType)) {
|
|
throw new UnexpectedTokenError(expectedTokens, token, line, col);
|
|
} else {
|
|
switch (tokenType) {
|
|
case "keyword":
|
|
switch (token) {
|
|
case "let":
|
|
ctx = patterns["let"];
|
|
expectedToken = "ident";
|
|
delim = " ";
|
|
break;
|
|
}
|
|
break;
|
|
case "ident":
|
|
|
|
|
|
|
|
} else {
|
|
token.push(line[j]);
|
|
}
|
|
|
|
switch (mode) {
|
|
case "keyword": {
|
|
const keyword = line.split(" ")[0];
|
|
if (KEYWORDS.includes(keyword)) {
|
|
stack.push(keyword);
|
|
} else {
|
|
throw new UnknownKeywordError(keyword, i, 0);
|
|
|
|
|
|
|