Browse Source

Specify special formatted keywords

Bepsi 6 years ago
parent
commit
2370bfa475

+ 34 - 29
NTERA.Compiler/Compiler.cs

@@ -87,6 +87,8 @@ namespace NTERA.Compiler
 			"ITEMSALES",
 			"FORWARD", //special casing for SORTCHARA
 			"BACK", //special casing for SORTCHARA
+			"LEFT", //special casing for __FORMAT
+			"RIGHT", //special casing for __FORMAT
 			"DEBUG_MODE",
 		};
 
@@ -173,6 +175,7 @@ namespace NTERA.Compiler
 				new FunctionDefinition("POWER", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
 				new FunctionDefinition("GETPALAMLV", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
 				new FunctionDefinition("GETBIT", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
+				new FunctionDefinition("GETEXPLV", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
 				new FunctionDefinition("UNICODE", new[] { new FunctionParameter("a", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
 				new FunctionDefinition("MATCH", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]), new FunctionParameter("c", new string[0], "a"), new FunctionParameter("d", new string[0], "f"), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
 				new FunctionDefinition("INRANGE", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]), new FunctionParameter("c", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
@@ -199,34 +202,36 @@ namespace NTERA.Compiler
 				new FunctionDefinition("GETMILLISECOND", new FunctionParameter[0], new FunctionVariable[0], true, "_GLOBAL", new Marker()),
 			};
 
-			var stringStatements = new List<string>
+			var stringStatements = new List<Keyword>
 			{
-				"DRAWLINEFORM",
-				"PRINTFORML",
-				"PRINT",
-				"PRINTW",
-				"PRINTV",
-				"PRINTL",
-				"PRINTLC",
-				"PRINTC",
-				"ALIGNMENT",
-				"CALL",
-				"CUSTOMDRAWLINE",
-				"DATAFORM",
-				"GOTO",
-				"PRINTFORMDL",
-				"PRINTFORMW",
-				"PRINTFORMDW",
-				"PRINTFORMC",
-				"PRINTFORMLC",
-				"PRINTFORM",
-				"PRINTPLAINFORM",
-				"DEBUGPRINTL",
-				"DEBUGPRINTFORML",
-				"REUSELASTLINE",
-				"PRINTPLAIN",
-				"PRINT_TRAIN_NAME",
-				"PRINT_STR",
+				new Keyword("DRAWLINEFORM", true, true),
+				new Keyword("PRINTFORML", true, true),
+				new Keyword("DATAFORM", true, true),
+				new Keyword("PRINTFORMD", true, true),
+				new Keyword("PRINTFORMDL", true, true),
+				new Keyword("PRINTFORMW", true, true),
+				new Keyword("PRINTFORMDW", true, true),
+				new Keyword("PRINTFORMC", true, true),
+				new Keyword("PRINTFORMLC", true, true),
+				new Keyword("PRINTFORM", true, true),
+				new Keyword("PRINTPLAINFORM", true, true),
+				new Keyword("DEBUGPRINTFORML", true, true),
+
+				new Keyword("PRINT", true),
+				new Keyword("PRINTW", true),
+				new Keyword("PRINTV", true),
+				new Keyword("PRINTL", true),
+				new Keyword("PRINTLC", true),
+				new Keyword("PRINTC", true),
+				new Keyword("ALIGNMENT", true),
+				new Keyword("CALL", true, true),
+				new Keyword("CUSTOMDRAWLINE", true),
+				new Keyword("GOTO", true),
+				new Keyword("DEBUGPRINTL", true),
+				new Keyword("REUSELASTLINE", true),
+				new Keyword("PRINTPLAIN", true),
+				new Keyword("PRINT_TRAIN_NAME", true),
+				new Keyword("PRINT_STR", true),
 			};
 
 			string csvPath = Path.Combine(InputDirectory, "CSV");
@@ -252,7 +257,7 @@ namespace NTERA.Compiler
 #else
 			Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories), new ParallelOptions
 			{
-				MaxDegreeOfParallelism = 4
+				MaxDegreeOfParallelism = 8
 			}, file =>
 #endif
 			{
@@ -283,7 +288,7 @@ namespace NTERA.Compiler
 #else
 			Parallel.ForEach(DeclaredFunctions, new ParallelOptions
 			{
-				MaxDegreeOfParallelism = 4
+				MaxDegreeOfParallelism = 8
 			}, kv =>
 #endif
 			{

+ 30 - 23
NTERA.Compiler/HTMLWriter.cs

@@ -8,19 +8,7 @@ namespace NTERA.Compiler
 {
 	public class HTMLWriter
 	{
-		protected virtual string ReportHeader { get; } =
-			@"<!DOCTYPE html>
-
-<html lang=""en"" xmlns=""http://www.w3.org/1999/xhtml"">
-	<head>
-		<meta charset=""utf-8""/>
-		<title></title>
-	</head>
-	<body style=""font-family: sans-serif"">";
-
-		protected virtual string ReportFooter { get; } =
-			@"	</body>
-</html>";
+		protected virtual string ReportFooter { get; } = "	</body>\r\n</html>";
 
 		public long TotalFileSize { get; set; }
 		public int TotalFileCount { get; set; }
@@ -31,6 +19,18 @@ namespace NTERA.Compiler
 
 		public void WriteReportToFile(Stream outputStream)
 		{
+			string ReportHeader = $@"<!DOCTYPE html>
+
+<html lang=""en"" xmlns=""http://www.w3.org/1999/xhtml"">
+	<head>
+		<meta charset=""utf-8""/>
+		<title>NTERA Compilation Report</title>
+		<style>
+{GetCSSStyle()}
+		</style>
+	</head>
+	<body>";
+
 			using (StreamWriter writer = new StreamWriter(outputStream, Encoding.UTF8, 4096, true))
 			{
 				writer.WriteLine(ReportHeader);
@@ -41,6 +41,14 @@ namespace NTERA.Compiler
 			}
 		}
 
+		protected virtual string GetCSSStyle()
+		{
+			return @"			body { font-family: sans-serif; }
+			table { height: 98px; width: 100% }
+			.message { width: 33.33% }
+			.symbol { width: 66.67% }";
+		}
+
 		protected virtual void EmitSummary(StreamWriter streamWriter)
 		{
 			string fileSizeStr = (TotalFileSize / 1048576D).ToString("0.0");
@@ -49,12 +57,12 @@ namespace NTERA.Compiler
 		<hr />
 		<p>NTERA v0.X</p>
 		<p>Processed {fileSizeStr} MB in {TotalFileCount} files<br />
-			Processed {FunctionCount} functions
+		   Processed {FunctionCount} functions
 		</p>
 		<p>{Errors.Count} errors, {Warnings.Count} warnings</p>");
 
 			streamWriter.WriteLine(@"		<h4>Warnings</h4>
-		<table style=""height: 98px;"" width=""100%"">
+		<table>
 			<tbody>");
 
 			foreach (var warning in Warnings)
@@ -62,12 +70,12 @@ namespace NTERA.Compiler
 				EmitError(streamWriter, warning.Item1, warning.Item2);
 			}
 
-			streamWriter.WriteLine($@"			</tbody>
+			streamWriter.WriteLine(@"			</tbody>
 		</table>
 		<br />");
 			
 			streamWriter.WriteLine(@"		<h4>Errors</h4>
-		<table style=""height: 98px;"" width=""100%"">
+		<table>
 			<tbody>");
 
 			foreach (var error in Errors)
@@ -75,16 +83,15 @@ namespace NTERA.Compiler
 				EmitError(streamWriter, error.Item1, error.Item2);
 			}
 
-			streamWriter.WriteLine($@"			</tbody>
-		</table>");
+			streamWriter.WriteLine("			</tbody>\r\n		</table>");
 		}
 
 		protected virtual void EmitError(StreamWriter streamWriter, ParserError error, string message)
 		{
-			streamWriter.WriteLine($@"					<tr>
-						<td style=""width: 30.6667%;"">{message}</td>
-						<td style=""width: 66.3333%;"">{error.SymbolMarker} : {error.ErrorMessage}</td>
-					</tr>");
+			streamWriter.WriteLine($@"<tr>
+<td class=""message"">{message}</td>
+<td class=""symbol"">{error.SymbolMarker} : {error.ErrorMessage}</td>
+</tr>");
 		}
 	}
 }

+ 1 - 1
NTERA.Compiler/Program.cs

@@ -19,7 +19,7 @@ namespace NTERA.Compiler
 			Console.WriteLine("NTERA 0.X");
 			Console.WriteLine("-------------------------");
 			Console.WriteLine($"Compiling '{path}' to '{outputPath}'");
-			Console.WriteLine("Using 4 threads");
+			Console.WriteLine("Using 8 threads");
 			
 
 

+ 23 - 0
NTERA.Interpreter/Compiler/Keyword.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace NTERA.Interpreter.Compiler
+{
+	public class Keyword
+	{
+		public string Name { get; }
+
+		public bool ImplicitString { get; }
+		public bool ImplicitFormatted { get; }
+
+		public Keyword(string name, bool implicitString = false, bool implicitFormatted = false)
+		{
+			if (implicitFormatted && !implicitString)
+				throw new ArgumentException("Keyword cannot support formatting if it does not use implicit strings");
+
+			Name = name;
+
+			ImplicitString = implicitString;
+			ImplicitFormatted = implicitFormatted;
+		}
+	}
+}

+ 39 - 35
NTERA.Interpreter/Compiler/Parser.cs

@@ -21,7 +21,7 @@ namespace NTERA.Interpreter.Compiler
 
 		protected VariableDictionary LocalVariables { get; }
 
-		protected ICollection<string> StringStatements { get; }
+		protected ICollection<Keyword> ExplicitKeywords { get; }
 
 		protected CSVDefinition CsvDefinition { get; }
 
@@ -48,7 +48,7 @@ namespace NTERA.Interpreter.Compiler
 			Lexer.TokenMarker.Line + SelfDefinition.Position.Line - 1,
 			Lexer.TokenMarker.Column);
 
-		public Parser(string input, FunctionDefinition selfDefinition, ICollection<FunctionDefinition> functionDefinitions, ICollection<FunctionDefinition> procedureDefinitions, VariableDictionary globalVariables, VariableDictionary localVariables, ICollection<string> stringStatements, CSVDefinition csvDefinition)
+		public Parser(string input, FunctionDefinition selfDefinition, ICollection<FunctionDefinition> functionDefinitions, ICollection<FunctionDefinition> procedureDefinitions, VariableDictionary globalVariables, VariableDictionary localVariables, ICollection<Keyword> explicitKeywords, CSVDefinition csvDefinition)
 		{
 			Lexer = new Lexer(input);
 			Enumerator = Lexer.GetEnumerator();
@@ -58,7 +58,7 @@ namespace NTERA.Interpreter.Compiler
 			ProcedureDefinitions = procedureDefinitions;
 			GlobalVariables = globalVariables;
 			LocalVariables = localVariables;
-			StringStatements = stringStatements;
+			ExplicitKeywords = explicitKeywords;
 			CsvDefinition = csvDefinition;
 		}
 
@@ -433,9 +433,11 @@ namespace NTERA.Interpreter.Compiler
 
 						List<ExecutionNode> parameters = new List<ExecutionNode>();
 
-						if (StringStatements.Contains(statementName))
+						Keyword keyword = ExplicitKeywords.FirstOrDefault(x => x.Name == statementName);
+
+						if (keyword?.ImplicitString == true)
 						{
-							var value = ParseString(out error, true, true);
+							var value = ParseString(out error, true, keyword.ImplicitFormatted);
 							if (error != null)
 								return null;
 
@@ -858,11 +860,11 @@ namespace NTERA.Interpreter.Compiler
 			if (token != Token.QuestionMark)
 				return result;
 
-			var resultTrue = ternaryString ? ParseString(out error, useModulo, true, true) : Expression(out error, useModulo);
+			var resultTrue = ternaryString ? ParseString(out error, useModulo, true, true) : Expression(out error, useModulo, false);
 			if (error != null)
 				return null;
 
-			var resultFalse = ternaryString ? ParseString(out error, useModulo, true, true) : Expression(out error, useModulo);
+			var resultFalse = ternaryString ? ParseString(out error, useModulo, true, true) : Expression(out error, useModulo, false);
 			if (error != null)
 				return null;
 
@@ -880,18 +882,21 @@ namespace NTERA.Interpreter.Compiler
 			if (nestedTernary && (Lexer.CurrentChar == '?' || Lexer.CurrentChar == '#'))
 				Lexer.GetNextChar();
 
-			if (char.IsWhiteSpace(Lexer.CurrentChar))
-				Lexer.GetNextChar();
-
-			if (Lexer.CurrentChar == '@')
+			if (!implicitString)
 			{
-				canFormat = true;
-				Lexer.GetNextChar();
-			}
+				if (char.IsWhiteSpace(Lexer.CurrentChar))
+					Lexer.GetNextChar();
 
-			if (!implicitString && Lexer.CurrentChar == '"')
-			{
-				Lexer.GetNextChar();
+				if (Lexer.CurrentChar == '@')
+				{
+					canFormat = true;
+					Lexer.GetNextChar();
+				}
+
+				if (Lexer.CurrentChar == '"')
+				{
+					Lexer.GetNextChar();
+				}
 			}
 
 			StringBuilder currentBlock = new StringBuilder();
@@ -908,7 +913,7 @@ namespace NTERA.Interpreter.Compiler
 				if (nestedTernary && Lexer.CurrentChar == '#')
 					break;
 
-				if (Lexer.CurrentChar == '\\')
+				if (canFormat && Lexer.CurrentChar == '\\')
 				{
 					Lexer.GetNextChar();
 
@@ -932,29 +937,28 @@ namespace NTERA.Interpreter.Compiler
 					continue;
 				}
 
-				if (canFormat && Lexer.CurrentChar == '%')
+				if (canFormat && (Lexer.CurrentChar == '{' || Lexer.CurrentChar == '%'))
 				{
-					var expressionValue = Expression(out error, false);
-					if (error != null)
-						return null;
+					bool useModulo = Lexer.CurrentChar != '%';
 
-					value = value == null
-						? expressionValue
-						: OperateNodes(value, expressionValue, Token.Plus);
+					List<ExecutionNode> formatParams = new List<ExecutionNode>();
 
-					Lexer.GetNextChar();
-					continue;
-				}
+					Marker symbolMarker = CurrentPosition;
 
-				if (canFormat && Lexer.CurrentChar == '{')
-				{
-					var expressionValue = Expression(out error, true);
-					if (error != null)
-						return null;
+					do
+					{
+						var expressionValue = Expression(out error, useModulo, nestedTernary);
+						if (error != null)
+							return null;
+
+						formatParams.Add(expressionValue);
+					} while (Enumerator.Current == Token.Comma);
+
+					var formattedValue = CallMethod("__FORMAT", symbolMarker, formatParams.ToArray());
 
 					value = value == null
-						? expressionValue
-						: OperateNodes(value, expressionValue, Token.Plus);
+						? formattedValue
+						: OperateNodes(value, formattedValue, Token.Plus);
 
 					Lexer.GetNextChar();
 					continue;

+ 1 - 0
NTERA.Interpreter/NTERA.Interpreter.csproj

@@ -41,6 +41,7 @@
     <Compile Include="Compiler\CSVDefinition.cs" />
     <Compile Include="Compiler\ExecutionNode.cs" />
     <Compile Include="Compiler\FunctionDefinition.cs" />
+    <Compile Include="Compiler\Keyword.cs" />
     <Compile Include="Compiler\Parser.cs" />
     <Compile Include="Compiler\ParserError.cs" />
     <Compile Include="Compiler\Preprocessor.cs" />