/// <summary> /// Ejecuta una instrucción Nhaml /// </summary> private void Execute(InstructionNhaml instruction) { int index = 0; // Asigna la indentación Builder.Indent = instruction.Token.Indent; // Añade la etiqueta de apertura Builder.AddTag(GetTagHtml(instruction.Token, true) + " " + GetAttributes(instruction), false, instruction.IsInner); // Añade los literales foreach (InstructionBase innerInstruction in instruction.Instructions) { if (innerInstruction is InstructionComment) { Execute(innerInstruction as InstructionComment); } else if (innerInstruction is InstructionNhaml || innerInstruction.Token.Type == Token.TokenType.Sentence) // ... tiene que estar antes de comprobar si es una instrucción base { Execute(innerInstruction); } else if (innerInstruction is InstructionVariableIdentifier) { Builder.Add(" " + GetVariableValue(innerInstruction as InstructionVariableIdentifier)); } else if (innerInstruction is InstructionBase || innerInstruction is InstructionLiteral) { bool addSpace = MustAddSpace(index, innerInstruction.Token.Content); string content = innerInstruction.Token.Content; // Añade el contenido Builder.Add((addSpace ? " " : "") + content); // Incrementa el índice index++; } } // Añade la etiqueta de cierre Builder.Indent = instruction.Token.Indent; Builder.AddTag(GetTagHtml(instruction.Token, false), true, instruction.IsInner); }
/// <summary> /// Obtiene los atributos de una instrucción /// </summary> private string GetAttributes(InstructionNhaml instruction) { string attributes = ""; // Añade los parámetros foreach (Parameter parameter in instruction.Attributes) { ValueBase result = ExpressionComputer.Evaluate(parameter.VariableRPN); // Añade el nombre attributes += $" {parameter.Name}="; // Añade el valor if (result.HasError) { Compiler.LocalErrors.Add(instruction.Token, result.Error); } else { attributes += $"\"{result.Content}\""; } } // Devuelve los atributos return(attributes); }
/// <summary> /// Lee los atributos de una instrucción /// </summary> private void ReadAttributes(InstructionNhaml instruction) { Token token = GetToken(); bool withError = false; // ... supone que hay algún error // Lee el primer token (el anterior sólo ha quitado la llave) token = GetToken(); // Lee los atributos while (!IsEof(token) && token.Type != Token.TokenType.RightLlave && !withError) { Parameter attribute = new Parameter(); // Obtiene el atributo if (token.Type == Token.TokenType.Literal) { // Nombre del atributo attribute.Name = token.Content; // El nombre de un atributo puede ser del tipo http-equiv, es decir, puede tener un guión intermedio, // aquí obtiene el resto token = GetToken(true); if (token.Type == Token.TokenType.Literal && token.Content.StartsWith("-")) { // Quita el token token = GetToken(); // Añade el guión al nombre del atributo attribute.Name += token.Content; } // Signo igual token = GetToken(); if (token.Type == Token.TokenType.Equal) { // Literal token = GetToken(true); // Comprueba y lo añade if (token.IsExpressionPart) { // Obtiene las expresiones de la variable attribute.Variable = ReadExpression(ExpressionReaderMode.AtAttributes, out string error); attribute.VariableRPN = _expressionEvaluator.ConvertToRPN(attribute.Variable); // Indica si hay un error if (!error.IsEmpty()) { withError = true; instruction.Error = error; } } else { withError = false; } } } else { withError = true; } // Si no hay ningún error, añade el atributo y lee el siguiente token if (!withError) { // Añade el atributo instruction.Attributes.Add(attribute); // Lee el siguiente token token = GetToken(); } } // Si hay algún error, lo añade if (withError) { instruction.Error = "Error en la definición de parámetros"; } }
/// <summary> /// Lee el Html de una página /// </summary> private InstructionNhaml ReadHtml(Token token) { InstructionNhaml instruction = new InstructionNhaml(token); Token nextToken = GetToken(true); // ... lee el siguiente token sin sacarlo del buffer bool end = false; // Si es una llave de apertura, lee los argumentos if (nextToken.Type == Token.TokenType.LeftLlave) { // Lee los atributos ReadAttributes(instruction); // Lee el siguiente token nextToken = GetToken(true); } // Recorre los tokens de la instrucción while (!IsEof(nextToken) && !end && !instruction.IsError) { // Comprueba si lo siguiente es una instrucción interna o si ya se ha terminado if (IsNextInstructionInternal(instruction, nextToken)) { if (instruction.IsInner) { instruction.Error = "Se ha detectado una instrucción dentro de una etiqueta HTML"; } else { nextToken = ReadInstructions(instruction.Instructions); } } else if (IsNextInstruction(nextToken)) { if (instruction.IsInner) { instruction.Error = "Se ha detectado una instrucción dentro de una etiqueta HTML"; } else { end = true; } } else { // Lee el token token = GetToken(); // Trata el token switch (token.Type) { case Token.TokenType.LeftTagHTMLInner: instruction.Instructions.Add(ReadHtml(token)); break; case Token.TokenType.RightTagHTMLInner: if (instruction.IsInner) { end = true; } else { instruction.Instructions.Add(new InstructionLiteral(token)); } break; case Token.TokenType.Variable: instruction.Instructions.Add(ReadVariableIdentifier(token)); break; default: instruction.Instructions.Add(new InstructionLiteral(token)); break; } // Lee el siguiente token sin sacarlo del buffer nextToken = GetToken(true); } } // Devuelve la instrucción return(instruction); }