123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- import { IVProgParser } from "../ast/ivprogParser";
- import * as Expressions from "../ast/expressions";
- import { Types } from "../typeSystem/types";
- import { convertBoolToString } from "../typeSystem/parsers";
- import * as Commands from "../ast/commands";
- import { ArrayType } from "../typeSystem/array_type";
- import { Literal } from "../ast/expressions/literal";
- const TYPES = {
- VARIABLE: "var",
- CONST: "const",
- FUNCTION: "function",
- RELATIONAL: "relational",
- LOGIC: "logic",
- ARITHMETIC: "arithmetic",
- };
- function translateOp (type, op) {
- switch (type) {
- case TYPES.ARITHMETIC:
- return op.value;
- case TYPES.RELATIONAL:
- return op.value;
- case TYPES.LOGIC: {
- if (op.ord === 11) {
- return "and";
- } else if (op.ord === 12) {
- return "or";
- } else {
- return "not";
- }
- }
- }
- }
- function getOpType (op) {
- switch (op.ord) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- return TYPES.ARITHMETIC;
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- return TYPES.RELATIONAL;
- default:
- return TYPES.LOGIC;
- }
- }
- /**
- * @param {Commands.Case} switchCase
- * */
- function switchCaseWalker (switchCase) {
- const commands = switchCase.commands.map(commandWalker);
- const expression = switchCase.isDefault
- ? null
- : expressionWalker(switchCase.expression);
- return {
- type: "switchcase",
- line: switchCase.sourceInfo.line,
- expression,
- commands,
- };
- }
- /**
- * @param {Commands.Switch} switchCommand
- * */
- function switchWalker (switchCommand) {
- const expression = expressionWalker(switchCommand.expression);
- const cases = switchCommand.cases.map(switchCaseWalker);
- return {
- type: "switch",
- expression,
- cases,
- };
- }
- /**
- * @param {Commands.Return} returnCommand
- * */
- function returnWalker (returnCommand) {
- const expression = expressionWalker(returnCommand.expression);
- return {
- type: "return",
- expression,
- };
- }
- function breakWalker (_) {
- return { type: "break" };
- }
- /**
- * @param {Commands.For} forLoop
- * */
- function forWalker (forLoop) {
- const var_attribution = expressionWalker(forLoop.for_id);
- const var_initial = expressionWalker(forLoop.for_from);
- const condition = expressionWalker(forLoop.for_to);
- const step_expression = forLoop.for_pass
- ? expressionWalker(forLoop.for_pass)
- : [];
- const commands = forLoop.commands.map(commandWalker);
- return {
- type: "repeatNtimes",
- var_attribution,
- var_initial,
- condition,
- step_expression,
- commands,
- };
- }
- /**
- * @param {Commands.While} whileLoop
- * */
- function whileWalker (whileLoop) {
- const expression = expressionWalker(whileLoop.expression);
- const commands = whileLoop.commands.map(commandWalker);
- let type = whileLoop.testFirst ? "whiletrue" : "dowhiletrue";
- return {
- type,
- expression,
- commands,
- };
- }
- /**
- * @param {Commands.IfThenElse} ifthenelse
- * */
- function ifThenElseWalker (ifthenelse) {
- //ifthenelse.
- const expression = expressionWalker(ifthenelse.condition);
- const ifTrue = ifthenelse.ifTrue.commands.map(commandWalker);
- let ifFalse = [];
- if (ifthenelse.ifFalse) {
- if (ifthenelse.ifFalse instanceof Commands.CommandBlock) {
- ifFalse = ifthenelse.ifFalse.commands.map(commandWalker);
- } else {
- ifFalse = [ifThenElseWalker(ifthenelse.ifFalse)];
- }
- }
- return {
- type: "iftrue",
- expression,
- ifTrue,
- ifFalse,
- };
- }
- /**
- * @param {Commands.Assign} assingment
- * */
- function assignmentWalker (assingment) {
- let variable = null;
- if (assingment instanceof Commands.ArrayIndexAssign) {
- const line = expressionWalker(assingment.line);
- let arrayClass = "vector";
- let column = null;
- if (assingment.column) {
- arrayClass = "matrix";
- column = expressionWalker(assingment.column);
- }
- variable = [
- {
- instance: "expression",
- type: TYPES.VARIABLE,
- class: arrayClass,
- column: column,
- line: line,
- value: assingment.id,
- },
- ];
- } else {
- variable = [
- { instance: "expression", type: TYPES.VARIABLE, value: assingment.id },
- ];
- }
- const expression = expressionWalker(assingment.expression);
- return {
- type: "attribution",
- variable,
- expression,
- };
- }
- /**
- * @param {Command} command
- * */
- function commandWalker (command) {
- let parsedCommand = null;
- if (command instanceof Commands.FunctionCall) {
- parsedCommand = functionCallWalker(command);
- } else if (command instanceof Commands.Assign) {
- parsedCommand = assignmentWalker(command);
- } else if (command instanceof Commands.IfThenElse) {
- parsedCommand = ifThenElseWalker(command);
- } else if (command instanceof Commands.While) {
- parsedCommand = whileWalker(command);
- } else if (command instanceof Commands.Break) {
- parsedCommand = breakWalker(command);
- } else if (command instanceof Commands.Return) {
- parsedCommand = returnWalker(command);
- } else if (command instanceof Commands.Switch) {
- parsedCommand = switchWalker(command);
- } else if (command instanceof Commands.For) {
- parsedCommand = forWalker(command);
- } else {
- throw new Error("not implemented");
- }
- parsedCommand.line = command.sourceInfo.line;
- return parsedCommand;
- }
- /**
- * @param {Commands.FunctionCall} functionCall
- * */
- function functionCallWalker (functionCall) {
- let name = functionCall.id;
- if (name.indexOf(".") !== -1) {
- name = name.split(".")[1];
- }
- const parameters = functionCall.actualParameters.map(expressionWalker);
- if (name === "$write") {
- const lastInput = parameters[parameters.length - 1][0];
- // if lastInput is an object with value === '\n', newLine is true
- const newLine = lastInput.value && lastInput.value.match(/^\n$/) !== null;
- const content = newLine
- ? parameters.slice(0, parameters.length - 1)
- : parameters;
- return {
- type: "writer",
- newLine,
- content,
- };
- }
- if (name === "$read") {
- return {
- type: "reader",
- variable: parameters[0],
- };
- }
- return {
- type: "functioncall",
- parameters_list: parameters,
- name: functionCall.id,
- };
- }
- /**
- * @param {Commands.Function} func
- * */
- function functionWalker (func) {
- const funcDeclaration = {
- name: func.name,
- line: func.sourceInfo.line,
- return_type: "",
- return_dimensions: 0,
- parameters_list: [],
- variables_list: [],
- commands: [],
- };
- if (func.returnType instanceof ArrayType) {
- funcDeclaration.return_type = func.returnType.innerType.value;
- funcDeclaration.return_dimensions = func.returnType.dimensions;
- } else {
- funcDeclaration.return_type = func.returnType.value;
- }
- funcDeclaration.parameters_list = func.formalParameters.map(
- functionParameterWalker
- );
- funcDeclaration.variables_list = func.variablesDeclarations.map(
- variableDeclarationWalker
- );
- funcDeclaration.commands = func.commands.map(commandWalker);
- return funcDeclaration;
- }
- /**
- * @param {Commands.FormalParameter} formalParameter
- * */
- function functionParameterWalker (formalParameter) {
- const variable = {
- name: formalParameter.id,
- line: formalParameter.sourceInfo.line,
- type: "",
- rows: 0,
- columns: 0,
- dimension: 0,
- value: 0,
- is_const: false,
- reference: formalParameter.byRef,
- };
- if (formalParameter.type instanceof ArrayType) {
- variable.type = formalParameter.type.innerType.value;
- variable.dimension = formalParameter.type.dimensions;
- } else {
- variable.type = formalParameter.type.value;
- }
- return variable;
- }
- /**
- * @param {Commands.Declaration} command
- * @param {boolean} global
- * */
- function variableDeclarationWalker (command, global = false) {
- const variable = {
- name: command.id,
- line: command.sourceInfo.line,
- type: "",
- rows: 0,
- columns: 0,
- dimension: 0,
- value: 0,
- is_const: false,
- };
- variable.is_const = global && command.isConst;
- if (command instanceof Commands.ArrayDeclaration) {
- // array
- const lines = expressionWalker(command.lines).pop();
- variable.type = command.type.innerType.value;
- if (command.isVector) {
- variable.columns = lines.value;
- variable.dimension = 1;
- const values = command.initial.value.map((exp) =>
- variableInitialWalker(exp)
- );
- variable.value = values;
- } else {
- const columns = expressionWalker(command.columns).pop();
- variable.dimension = 2;
- variable.rows = lines.value;
- variable.columns = columns.value;
- const values = command.initial.value.map((rows) =>
- rows.value.map((exp) => variableInitialWalker(exp))
- );
- variable.value = values;
- }
- } else {
- // atomic
- variable.type = command.type.value;
- variable.value = variableInitialWalker(command.initial);
- }
- return variable;
- }
- /**
- * @param {any} expression
- * */
- function variableInitialWalker (expression) {
- if (expression instanceof Expressions.UnaryApp) {
- const left = variableInitialWalker(expression.left);
- const opType = getOpType(expression.op);
- if (opType !== TYPES.ARITHMETIC) {
- throw new Error(
- "invalid variable initial value: " + expression.toString()
- );
- }
- return `${expression.op.value}${left}`;
- } else if (expression instanceof Expressions.BoolLiteral) {
- const value = expression.value;
- return convertBoolToString(value);
- } else if (expression instanceof Literal) {
- let value = expression.value;
- if (expression.value.toNumber) {
- if (
- Types.REAL.isCompatible(expression.type) &&
- expression.value.decimalPlaces() == 0
- ) {
- value = expression.value.toFixed(2);
- } else {
- value = expression.value.toNumber();
- }
- }
- return value;
- }
- throw new Error("invalid variable initial value: " + expression.toString());
- }
- /**
- *
- * @return {[]}
- **/
- function expressionWalker (expression) {
- let result;
- if (expression instanceof Expressions.VariableLiteral) {
- result = [
- { instance: "expression", type: TYPES.VARIABLE, value: expression.id },
- ];
- } else if (expression instanceof Expressions.FunctionCall) {
- const funcObj = {
- instance: "expression",
- type: TYPES.FUNCTION,
- value: expression.id,
- };
- const paramsList = expression.actualParameters.map((e) =>
- expressionWalker(e)
- );
- //const params = Array.prototype.concat.apply([], paramsList);
- funcObj.params = paramsList;
- result = [funcObj];
- } else if (expression instanceof Expressions.UnaryApp) {
- console.log(expression);
- const left = expressionWalker(expression.left);
- const opType = getOpType(expression.op);
- const opValue = translateOp(opType, expression.op);
- result = [{ instance: "operator", type: opType, value: opValue }, ...left];
- } else if (expression instanceof Expressions.InfixApp) {
- const left = expressionWalker(expression.left);
- const right = expressionWalker(expression.right);
- const opType = getOpType(expression.op);
- const opValue = translateOp(opType, expression.op);
- result = [
- ...left,
- { instance: "operator", type: opType, value: opValue },
- ...right,
- ];
- } else if (expression instanceof Expressions.ArrayAccess) {
- const line = expressionWalker(expression.line);
- let arrayClass = "vector";
- let column = null;
- if (expression.column) {
- arrayClass = "matrix";
- column = expressionWalker(expression.column);
- }
- result = [
- {
- instance: "expression",
- type: TYPES.VARIABLE,
- class: arrayClass,
- column: column,
- line: line,
- value: expression.id,
- },
- ];
- } else if (expression instanceof Expressions.BoolLiteral) {
- const value = expression.value;
- result = [
- {
- instance: "expression",
- class: "simple",
- type: TYPES.CONST,
- value: convertBoolToString(value),
- },
- ];
- } else {
- let value = expression.value;
- if (expression.value.toNumber) {
- if (
- Types.REAL.isCompatible(expression.type) &&
- expression.value.decimalPlaces() == 0
- ) {
- value = expression.value.toFixed(2);
- } else {
- value = expression.value.toNumber();
- }
- }
- result = [
- {
- instance: "expression",
- class: "simple",
- type: TYPES.CONST,
- value: value,
- },
- ];
- }
- if (expression.parenthesis) return ["(", ...result, ")"];
- else return result;
- }
- export function parseExpression (text) {
- const parser = IVProgParser.createParser(text);
- const expressionAST = parser.parseExpressionOR();
- return expressionWalker(expressionAST);
- }
- /**
- * @param {string} text
- * */
- export function parseCode (text) {
- const parser = IVProgParser.createParser(text, false);
- const codeLinesMap = new Map();
- const tokens = Array.from(parser.lexer.reset(text));
- const tokenStream = [];
- for (const token of tokens) {
- if (token.type === parser.ruleNames.ERROR) {
- return null;
- }
- if (token.type === parser.ruleNames.COMMENTS) {
- for (let i = 0; i <= token.lineBreaks; i++) {
- if (codeLinesMap.has(i + token.line))
- codeLinesMap.get(i + token.line).push(token);
- else codeLinesMap.set(i + token.line, [token]);
- }
- continue;
- }
- if (token.type !== parser.ruleNames.WHITESPACE) {
- tokenStream.push(token);
- }
- }
- parser.fill(tokenStream);
- try {
- const program = parser.parseTree();
- const globals = program.global.map((decl) =>
- variableDeclarationWalker(decl, true)
- );
- const functions = program.functions.map(functionWalker);
- return { globals, functions };
- } catch (e) {
- console.error(e);
- return null;
- }
- }
|