ocat-lang
Version:
A programming language for the web design and development
371 lines (370 loc) • 16.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = void 0;
const types_1 = require("./types");
const lexer_1 = require("../lexer");
const error_1 = require("../../error");
const adapters_1 = require("./adapters");
let tokens;
let currentIndex = 0;
const parse = (tokensK) => {
const nodes = [];
tokens = tokensK;
let line = 1;
currentIndex = 0;
while (currentIndex < tokens.length) {
let token = getToken();
let node = {
type: types_1.NodeType.ERR,
params: { cause: "Unknown token error" },
base: token,
line,
};
try {
switch (token.type) {
case lexer_1.TokenType.IO:
if (token.value === "print") {
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Shape) {
throw new error_1.OSyntaxError(`Expected '(' after 'print', but got: ${token.value} (Type: ${token.type})`);
}
node.type = types_1.NodeType.OUTPUT;
nextToken();
node.params = { content: collectString() };
nextToken();
}
break;
case lexer_1.TokenType.IERQ:
node.type = types_1.NodeType.IMPORT;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected value after 'import', but got: ${token.value} (Type: ${token.type})`);
}
node.params = { name: sanitizeTokenValue(token.value) };
break;
case lexer_1.TokenType.Component:
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Identifier) {
throw new error_1.OSyntaxError(`Expected identifier after 'component', but got: ${token.value} (Type: ${token.type})`);
}
const name = sanitizeTokenValue(token.value);
node.type = types_1.NodeType.CDECLARE;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.PageRequest) {
throw new error_1.OSyntaxError(`Expected page request after 'component', but got: ${token.value} (Type: ${token.type})`);
}
nextToken();
token = getToken();
const params = collectTag().join(" ");
node.params = { name, content: params };
break;
case lexer_1.TokenType.PageRequest:
node.type = types_1.NodeType.SHOW;
nextToken();
const tags = collectTag();
const joinedTags = tags
//.map((tag) => tag.trim())
.join(" ")
.trim();
if (joinedTags.startsWith("%css-global%")) {
node.type = types_1.NodeType.STYLE;
node.params = {
content: joinedTags.replace("%css-global%", ""),
};
break;
}
nextToken();
if (!getToken() || getToken().value !== "as") {
throw new error_1.OSyntaxError(`Expected 'as' after value, but got: ${getToken() ? getToken().value : "\\eof"} (Type: ${getToken() ? getToken().type : lexer_1.TokenType.EOF} at index ${currentIndex})`);
}
nextToken();
node.params = {
content: joinedTags,
route: sanitizeTokenValue(getToken().value),
};
break;
case lexer_1.TokenType.EOF:
return nodes.map(adapters_1.NodeAdapter);
case lexer_1.TokenType.Comment:
skipComment();
node.type = types_1.NodeType.NONE;
break;
case lexer_1.TokenType.Meta:
node.type = types_1.NodeType.META;
if (token.value === "title") {
node.params.type = "\\title";
}
else {
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected value after 'meta', but got: ${token.value} (Type: ${token.type})`);
}
node.params.type = sanitizeTokenValue(collectString());
}
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected value after 'meta', but got: ${token.value} (Type: ${token.type})`);
}
node.params.content = sanitizeTokenValue(collectString());
break;
case lexer_1.TokenType.Datatype:
const type = token.value;
nextToken();
token = getToken();
const vname = token.value;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Assign) {
throw new error_1.OSyntaxError(`Expected '=' after variable name, but got: ${token.value} (Type: ${token.type})`);
}
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected value after '=', but got: ${token.value} (Type: ${token.type})`);
}
node.type = types_1.NodeType.DECLARE;
node.params.name = vname;
if (type === "string") {
node.params.value = sanitizeTokenValue(collectString());
}
else {
node.params.value = sanitizeTokenValue(token.value);
}
node.params.type = type;
break;
case lexer_1.TokenType.ExportW:
node.type = types_1.NodeType.EXPORTW;
break;
case lexer_1.TokenType.Conditional:
node.params.condition = {};
switch (token.value) {
case "if":
node.type = types_1.NodeType.IF;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Shape) {
throw new error_1.OSyntaxError(`Expected '(' after 'if', but got: ${token.value} (Type: ${token.type})`);
}
nextToken();
token = getToken();
const params = collectParam().join(" ");
nextToken();
token = getToken();
node.params.condition.cond = params;
node.params.condition.body = collectBlock();
break;
}
break;
case lexer_1.TokenType.Function:
node.type = types_1.NodeType.Function;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Identifier) {
throw new error_1.OSyntaxError(`Expected identifier after 'func', but got: ${token.value} (Type: ${token.type})`);
}
node.params.name = sanitizeTokenValue(token.value);
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Block) {
throw new error_1.OSyntaxError(`Expected '{' after function name, but got: ${token.value} (Type: ${token.type})`);
}
nextToken();
token = getToken();
const content = collectBlock();
node.params.content = content;
break;
case lexer_1.TokenType.FCall:
node.type = types_1.NodeType.FCall;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Identifier) {
throw new error_1.OSyntaxError(`Expected identifier after 'call', but got: ${token.value} (Type: ${token.type})`);
}
node.params.name = sanitizeTokenValue(token.value);
break;
case lexer_1.TokenType.ORDER:
const orderName = token.value.replace("@", "");
if (orderName === "strict") {
node.type = types_1.NodeType.UseStrict;
}
else {
node.type = types_1.NodeType.ORDER;
nextToken();
token = getToken();
node.params.name = orderName;
if (token.type !== lexer_1.TokenType.Shape) {
node.params.content = "true";
currentIndex--;
break;
}
nextToken();
token = getToken();
const params = token.value;
nextToken();
token = getToken();
node.params.content = params;
}
break;
case lexer_1.TokenType.SCS:
node.type = types_1.NodeType.Create;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Identifier) {
throw new error_1.OSyntaxError(`Expected identifier after 'call', but got: ${token.value} (Type: ${token.type})`);
}
const dtype = sanitizeTokenValue(token.value);
node.params.type = dtype;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected value after 'call', but got: ${token.value} (Type: ${token.type})`);
}
const dname = sanitizeTokenValue(collectString());
node.params.name = dname;
if (dtype === "file") {
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected value after 'call', but got: ${token.value} (Type: ${token.type})`);
}
const content = sanitizeTokenValue(collectString());
node.params.content = content;
}
break;
case lexer_1.TokenType.Layout:
node.type = types_1.NodeType.Layout;
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.PageRequest) {
throw new error_1.OSyntaxError(`Expected page request after 'layout', but got: ${token.value} (Type: ${token.type})`);
}
nextToken();
const tag = collectTag().join(" ");
node.params = { content: tag };
break;
case lexer_1.TokenType.Load:
node.type = types_1.NodeType.LOAD;
let _type = "";
switch (token.value) {
case "loadComponent":
_type = "component";
break;
case "loadLayout":
_type = "layout";
break;
case "loadTemplate":
_type = "layout";
break;
}
nextToken();
token = getToken();
if (token.type !== lexer_1.TokenType.Value) {
throw new error_1.OSyntaxError(`Expected string after load, but got: ${token.value} (Type: ${token.type})`);
}
const path = sanitizeTokenValue(collectString());
node.params = { route: path, type: _type };
break;
default:
throw new error_1.OSyntaxError(`Unexpected token: ${token.value} (Type: ${token.type})`);
}
nextToken();
nodes.push((0, adapters_1.NodeAdapter)(node));
}
catch (e) {
if (e instanceof error_1.Warning || e instanceof error_1.CustomError) {
e.display(line);
}
}
}
return nodes;
};
exports.parse = parse;
const getToken = () => {
return tokens[currentIndex];
};
const nextToken = () => {
currentIndex++;
};
const collectString = () => {
let token = getToken();
let str = "";
while (token.type !== lexer_1.TokenType.Shape && !isStringEnd(token.value)) {
str += sanitizeTokenValue(token.value) + " ";
nextToken();
token = getToken();
}
if (isStringEnd(token.value)) {
str += sanitizeTokenValue(token.value);
}
return str.trim();
};
const collectBlock = () => {
let token = getToken();
let str = "";
while (token.type !== lexer_1.TokenType.Block) {
str += token.value + " ";
nextToken();
token = getToken();
}
str += token.value;
return str.replace(/\{/g, "").replace(/\}/g, "").trim();
};
const collectParam = () => {
let token = getToken();
let param = [];
while (token.type !== lexer_1.TokenType.Shape) {
param.push(token.value);
nextToken();
token = getToken();
}
nextToken();
token = getToken();
param.push(token.value);
return param;
};
const collectTag = () => {
let token = getToken();
const param = [];
while (token.type !== lexer_1.TokenType.PageRequest) {
param.push(token.value.trim());
nextToken();
token = getToken();
}
return param;
};
const isStringEnd = (value) => {
return value.endsWith('"') || value.endsWith("'") || value.endsWith("`");
};
const sanitizeTokenValue = (value) => {
return value
.replace(/["'`]/g, "")
.replace(/\n/g, "")
.replace(/\r/g, "")
.replace("%", " ");
};
function skipComment() { }
function collectObject() {
let token = getToken();
let str = "";
let iteration = 1;
while (iteration !== 0) {
if (token.type === lexer_1.TokenType.Block) {
if (token.value === "{") {
iteration++;
}
else if (token.value === "}") {
iteration--;
}
}
str += token.value + " ";
nextToken();
token = getToken();
}
return str.trim();
}