UNPKG

ocat-lang

Version:

A programming language for the web design and development

371 lines (370 loc) 16.1 kB
"use strict"; 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(); }