Commits

Jesse McGrew committed 422fb3e

Added EvalConstant
Got Analyzer working

Comments (0)

Files changed (12)

Rellor.Core/Analyzer.cs

 using System;
 using System.Diagnostics.Contracts;
 using Antlr.Runtime;
+using Rellor.Core.Token;
+using Rellor.Core.Tree;
+using Antlr.Runtime.Tree;
 
 namespace Rellor.Core
 {
             Contract.Invariant(this.GlobalScope != null);
         }
 
+        public ILogSink LogSink { get; set; }
         public IGlobalScope GlobalScope { get; set; }
+        public ITree SyntaxTree { get; private set; }
+        public string[] TokenNames { get; private set; }
 
         public void Load(ICharStream input)
         {
-            throw new NotImplementedException();
+            // lexing
+            var lexer = new Inform6Lexer(input);
+            lexer.LogSink = this.LogSink;
+            var tokenStream = new RellorTokenStream(lexer);
+
+            // parsing
+            var parser = new Inform6Parser(tokenStream);
+            this.TokenNames = parser.TokenNames;
+            parser.LogSink = this.LogSink;
+            var parserResult = parser.program(this.GlobalScope);
+
+            // cleanup
+            var treeAdaptor = new RellorTreeAdaptor();
+            var nodeStream = new CommonTreeNodeStream(treeAdaptor, parserResult.Tree);
+            var cleaner = new SpecializeOperators(nodeStream);
+            var cleanResult = cleaner.Downup(parserResult.Tree, true);
+
+            // validation
+            //XXX
+
+            // result
+            this.SyntaxTree = (ITree)cleanResult;
         }
     }
 }

Rellor.Core/EvalConstant.g3

+tree grammar EvalConstant;
+
+options {
+    language=CSharp3;
+    ASTLabelType=CommonTree;
+	tokenVocab=Inform6;
+}
+
+@header{
+using System;
+using Rellor.Core.Tree;
+
+// 'class' does not need a CLSCompliant attribute because the assembly does not have a CLSCompliant attribute
+#pragma warning disable 3021
+}
+
+@namespace{Rellor.Core}
+
+public
+constantExpr[IScope scope] returns [int? value, System.Func<int> future, string failureReason]
+@init { this.scope = $scope; }
+	:	e=expr
+		{$future = $e.future; $value = ($future == null) ? (int?)$e.value : null; $failureReason = null;}
+	;
+	catch [NotConstantException nce]
+	{
+		$value = null; $future = null; $failureReason = nce.Message;
+	}
+
+expr returns [int value, System.Func<int> future]
+@init { bool match = false, neg = false; }
+@after { if ($future == null) $value = ConstrainValue($value); }
+	:	id=ID
+		{ResolveSymbol($id, out $value, out $future);}
+	|	i=INT
+		{$value = ((NumberTree)$i).Number;}
+	|	^(HASH id=ID)
+		{ResolveSysConst($id, out $value, out $future);}
+	|	^(HASHHASH id=ID)
+		{ResolveAction($id, out $value, out $future);}
+	|	^(hd=HASHDOLLAR id=ID)
+		{ResolveHashDollar($hd, $id, out $value, out $future);}
+	|	str=SQ_STRING
+		{ResolveSqString($str, out $value, out $future);}
+	|	str=DQ_STRING
+		{ResolveDqString($str, out $value, out $future);}
+	|	^(UMINUS e=pexpr)
+		{$value = -$e.value;}
+	|	^('+' l=pexpr r=pexpr)
+		{$value = $l.value + $r.value;}
+	|	^('-' l=pexpr r=pexpr)
+		{$value = $l.value - $r.value;}
+	|	^('*' l=pexpr r=pexpr)
+		{$value = $l.value * $r.value;}
+	|	^('/' l=pexpr r=pexpr)
+		{CheckDivByZero($r.value, $r.start);
+		 $value = $l.value / $r.value;}
+	|	^('%' l=pexpr r=pexpr)
+		{CheckDivByZero($r.value, $r.start);
+		 $value = $l.value \% $r.value;}
+	|	^('&' l=pexpr r=pexpr)
+		{$value = $l.value & $r.value;}
+	|	^('|' l=pexpr r=pexpr)
+		{$value = $l.value | $r.value;}
+	|	^('~' e=pexpr)
+		{$value = ~$e.value;}
+	|	^('&&' l=pexpr r=pexpr)
+		{$value = ($l.value != 0 && $r.value != 0) ? 1 : 0;}
+	|	^('||' l=pexpr r=pexpr)
+		{$value = ($l.value != 0 || $r.value != 0) ? 1 : 0;}
+	|	^('~~' e=pexpr)
+		{$value = ($e.value == 0) ? 1 : 0;}
+	|	^(	('=='|'~=' {neg = true;})
+			{match = false;}
+			l=pexpr
+			(	r=pexpr
+				{if ($l.value == $r.value) match = true;}
+			|	^(OR
+					(	r=pexpr
+						{if ($l.value == $r.value) match = true;}
+					)+
+				)
+			)
+			{$value = (match == neg) ? 0 : 1;}
+		)
+	|	^('<' l=pexpr r=pexpr)
+		{$value = ($l.value < $r.value) ? 1 : 0;}
+	|	^('>' l=pexpr r=pexpr)
+		{$value = ($l.value > $r.value) ? 1 : 0;}
+	|	^('<=' l=pexpr r=pexpr)
+		{$value = ($l.value <= $r.value) ? 1 : 0;}
+	|	^('>=' l=pexpr r=pexpr)
+		{$value = ($l.value >= $r.value) ? 1 : 0;}
+	|	^(nc=non_constant_op .*)
+		{NotConstant($nc.start, $nc.desc);}
+	;
+
+non_constant_op returns [string desc]
+@init { $desc = "'" + ((CommonTree)input.LT(1)).Text + "'"; }
+	:	(	COMMON_METHOD_CALL
+		|	INDIV_METHOD_CALL
+		|	FUNCTION_CALL
+		)
+		{$desc = "function call";}
+    |	(	COMMON_PROP_ASSIGN
+		|	INDIV_PROP_ASSIGN
+		|	BYTE_ARRAY_ASSIGN
+		|	WORD_ARRAY_ASSIGN
+		|	'='
+		)
+		{$desc = "assignment";}
+    |	(	COMMON_PROP_PREINC
+		|	INDIV_PROP_PREINC
+		|	BYTE_ARRAY_PREINC
+		|	WORD_ARRAY_PREINC
+		|	PREINC
+		|	INDIV_PROP_POSTINC
+		|	COMMON_PROP_POSTINC
+		|	BYTE_ARRAY_POSTINC
+		|	WORD_ARRAY_POSTINC
+		|	POSTINC
+		)
+		{$desc = "increment";}
+    |	(	COMMON_PROP_PREDEC
+		|	BYTE_ARRAY_PREDEC
+		|	WORD_ARRAY_PREDEC
+		|	INDIV_PROP_PREDEC
+		|	PREDEC
+		|	COMMON_PROP_POSTDEC
+		|	INDIV_PROP_POSTDEC
+		|	BYTE_ARRAY_POSTDEC
+		|	WORD_ARRAY_POSTDEC
+		|	POSTDEC
+		)
+		{$desc = "decrement";}
+	|	','|HAS|HASNT|IN|NOTIN|PROVIDES|OFCLASS|'.&'|'.#'|'..&'|'..#'
+	|	'.'|'..'|'::'
+	;
+
+pexpr returns [int value]
+	:	e=expr
+		{if ($e.future == null) $value = $e.value; else NotConstant($e.start, "an operation on a backpatched value");}
+	;

Rellor.Core/EvalConstant.g3.cs

+using System;
+using Antlr.Runtime;
+using Antlr.Runtime.Tree;
+
+namespace Rellor.Core
+{
+    partial class EvalConstant
+    {
+        private IScope scope;
+
+        private class NotConstantException : Exception
+        {
+            public NotConstantException(IToken token, string message)
+                : base(message)
+            {
+                this.Token = token;
+            }
+
+            public IToken Token { get; private set; }
+        }
+
+        private void CheckDivByZero(int value, CommonTree tree)
+        {
+            throw new NotImplementedException();
+        }
+
+        private int ConstrainValue(int value)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void ResolveSymbol(CommonTree id, out int value, out Func<int> future)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void ResolveSysConst(CommonTree id, out int value, out Func<int> future)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void ResolveAction(CommonTree id, out int value, out Func<int> future)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void ResolveHashDollar(CommonTree hashDollar, CommonTree id, out int value, out Func<int> future)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void ResolveSqString(CommonTree str, out int value, out Func<int> future)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void ResolveDqString(CommonTree str, out int value, out Func<int> future)
+        {
+            throw new NotImplementedException();
+        }
+
+        private void NotConstant(CommonTree position, string offender)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

Rellor.Core/ITargetValidation.cs

-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics.Contracts;
-
-namespace Rellor.Core
-{
-    [ContractClass(typeof(ITargetValidationContract))]
-    public interface ITargetValidation
-    {
-    }
-
-    [ContractClassFor(typeof(ITargetValidation))]
-    internal abstract class ITargetValidationContract : ITargetValidation
-    {
-
-    }
-}

Rellor.Core/Inform6.g3

 		(	/* nada */
 		|	'#'										{$type = HASHHASH;}
 		|	{input.LA(2)=='$'}?=> ('a'..'z') '$'	{$type = HASHDOLLAR;}
+			(	('a'..'z'|'0'..'9'|'_')=> ('a'..'z'|'0'..'9'|'_')+
+			|	c=.						{logger.Log(CoreMessages.UnexpectedChar, input, (char)$c);}
+			)
 		)
 	;
 
     |	id
 	|	HASH^ id
 	|	HASHHASH^ id
-    |	HASHDOLLAR^ id
+    |	HASHDOLLAR^
     |	SQ_STRING^
     |	DQ_STRING^
     ;

Rellor.Core/Inform6.g3.lexer.cs

 
 namespace Rellor.Core
 {
-    partial class Inform6Lexer
+    partial class Inform6Lexer : ILogSink
     {
         public const int CommentChannel = 2;
         public const int IclChannel = 3;
 
+        private MsgLogger<CoreMessages> logger;
+
+        partial void OnCreated()
+        {
+            logger = new MsgLogger<CoreMessages>(this, "RL");
+        }
+
+        public ILogSink LogSink { get; set; }
+
         private int keyword;
         private bool allowIcl = true;
 
 
             return 0;
         }
+
+        #region ILogSink Members
+
+        void ILogSink.LogMessage(LogLevel level, string text, bool count)
+        {
+            var ls = this.LogSink;
+            if (ls != null)
+                ls.LogMessage(level, text, count);
+        }
+
+        void ILogSink.CountSuppressedMessage(LogLevel level)
+        {
+            var ls = this.LogSink;
+            if (ls != null)
+                ls.CountSuppressedMessage(level);
+        }
+
+        #endregion
     }
 }

Rellor.Core/Inform6.g3.parser.cs

 
         partial void OnCreated()
         {
-            logger = new MsgLogger<CoreMessages>(this, "R");
+            logger = new MsgLogger<CoreMessages>(this, "RP");
             CompatibilityLevel = Compatibility.Relaxed;
         }
 
                 else
                 {
                     existing.Defined = true;
-                    existing.Definition = definition;
+                    existing.DefiningTree = definition;
                 }
                 return existing;
             }
                 {
                     Name = token.Text,
                     Defined = true,
-                    Definition = definition,
+                    DefiningTree = definition,
                     DefiningToken = token,
                     Type = type,
                 };

Rellor.Core/MemoryLogSink.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Rellor.Core
+{
+    public class MemoryLogSink : ILogSink
+    {
+        private int notices, warnings, errors, fatals;
+        private int noticesSup, warningsSup, errorsSup;
+        private readonly List<Tuple<LogLevel, string>> storage = new List<Tuple<LogLevel, string>>();
+
+        public int NoticeCount { get { return notices; } }
+        public int WarningCount { get { return warnings; } }
+        public int ErrorCount { get { return errors; } }
+        public int FatalCount { get { return fatals; } }
+
+        public int SuppressedNoticeCount { get { return noticesSup; } }
+        public int SuppressedWarningCount { get { return warningsSup; } }
+        public int SuppressedErrorCount { get { return errorsSup; } }
+
+        public IEnumerable<Tuple<LogLevel, string>> Messages { get { return storage; } }
+
+        public void LogMessage(LogLevel level, string text, bool count = true)
+        {
+            if (count)
+            {
+                switch (level)
+                {
+                    case LogLevel.Notice:
+                        notices++;
+                        break;
+                    case LogLevel.Warning:
+                        warnings++;
+                        break;
+                    case LogLevel.Error:
+                        errors++;
+                        break;
+                    case LogLevel.Fatal:
+                        fatals++;
+                        break;
+                }
+            }
+
+            storage.Add(new Tuple<LogLevel, string>(level, text));
+        }
+
+        public void CountSuppressedMessage(LogLevel level)
+        {
+            switch (level)
+            {
+                case LogLevel.Notice:
+                    noticesSup++;
+                    break;
+                case LogLevel.Warning:
+                    warningsSup++;
+                    break;
+                case LogLevel.Error:
+                    errorsSup++;
+                    break;
+            }
+        }
+    }
+}

Rellor.Core/Messages.cs

 using System.ComponentModel;
 using Rellor.Core.Token;
 using System.Reflection;
+using Antlr.Runtime;
 
 namespace Rellor.Core
 {
         // 1000 syntax issues
         [Msg(1000, LogLevel.Notice, "'for' loops should use ':' instead of ';'")]
         SemicolonUsedInFor,
+        [Msg(1001, LogLevel.Error, "invalid hash-dollar prefix '{0}'")]
+        InvalidHashDollar,
+        [Msg(1002, LogLevel.Protip, "valid prefixes are #a$, #n$, #r$", Continues = 1001)]
+        InvalidHashDollar_ValidPrefixes,
 
         // 1500 symbol usage: duplicate, undefined, unused
         [Msg(1501, LogLevel.Error, "symbol '{0}' has already been defined as {1}")]
         [Msg(3505, LogLevel.Error, "serial must be 6 characters")]
         SerialWrongLength,
 
-
         // 4000 statements
         [Msg(4000, LogLevel.Error, "statement '{0}' not supported by target '{1}'")]
         StatementNotSupportedByTarget,
         {
             Contract.Requires(token != null);
 
-            LogCore(key, token, s => s);
+            LogCore(key, token.InputStream.SourceName, token.Line, token.CharPositionInLine, s => s);
         }
 
         public void Log(T key, RellorToken token, object arg0)
             Contract.Requires(token != null);
             Contract.Requires(arg0 != null);
 
-            LogCore(key, token, s => string.Format(s, arg0));
+            LogCore(key, token.InputStream.SourceName, token.Line, token.CharPositionInLine, s => string.Format(s, arg0));
         }
 
         public void Log(T key, RellorToken token, object arg0, object arg1)
             Contract.Requires(arg0 != null);
             Contract.Requires(arg1 != null);
 
-            LogCore(key, token, s => string.Format(s, arg0, arg1));
+            LogCore(key, token.InputStream.SourceName, token.Line, token.CharPositionInLine, s => string.Format(s, arg0, arg1));
         }
 
         public void Log(T key, RellorToken token, params string[] args)
             Contract.Requires(token != null);
             Contract.Requires(args != null);
 
-            LogCore(key, token, s => string.Format(s, args));
+            LogCore(key, token.InputStream.SourceName, token.Line, token.CharPositionInLine, s => string.Format(s, args));
         }
 
-        private void LogCore(T key, RellorToken token, Func<string, string> textFormatter)
+        public void Log(T key, ICharStream input)
         {
-            Contract.Requires(token != null);
+            Contract.Requires(input != null);
+
+            LogCore(key, input.SourceName, input.Line, input.CharPositionInLine, s => s);
+        }
+
+        public void Log(T key, ICharStream input, object arg0)
+        {
+            Contract.Requires(input != null);
+            Contract.Requires(arg0 != null);
+
+            LogCore(key, input.SourceName, input.Line, input.CharPositionInLine, s => string.Format(s, arg0));
+        }
+
+        public void Log(T key, ICharStream input, object arg0, object arg1)
+        {
+            Contract.Requires(input != null);
+            Contract.Requires(arg0 != null);
+            Contract.Requires(arg1 != null);
+
+            LogCore(key, input.SourceName, input.Line, input.CharPositionInLine, s => string.Format(s, arg0, arg1));
+        }
+
+        public void Log(T key, ICharStream input, params string[] args)
+        {
+            Contract.Requires(input != null);
+            Contract.Requires(args != null);
+
+            LogCore(key, input.SourceName, input.Line, input.CharPositionInLine, s => string.Format(s, args));
+        }
+
+        private void LogCore(T key, string sourceName, int line, int charPositionInLine, Func<string, string> textFormatter)
+        {
             Contract.Requires(textFormatter != null);
 
             var msg = attributes[key];
             }
             else if (msg.Level == LogLevel.Protip)
             {
-                formattedWithoutSource = Messages.FormatMessage(null, level, prefix, code, text);
+                formattedWithoutSource = Messages.FormatMessage(null,
+                    0,
+                    0,
+                    level,
+                    prefix,
+                    code,
+                    text);
                 string checkMsg = formattedWithoutSource;
 
                 if (msg.Continues > 0)
             if (msg.Continues == 0)
             {
                 if (formattedWithoutSource == null)
-                    formattedWithoutSource = Messages.FormatMessage(null, level, prefix, code, text);
+                    formattedWithoutSource = Messages.FormatMessage(
+                        null,
+                        0,
+                        0,
+                        level,
+                        prefix,
+                        code,
+                        text);
 
                 lastNonContinuationText = formattedWithoutSource;
             }
 
-            string formatted = Messages.FormatMessage(token, level, prefix, code, text);
+            string formatted = Messages.FormatMessage(
+                sourceName,
+                line,
+                charPositionInLine,
+                level,
+                prefix,
+                code,
+                text);
             sink.LogMessage(level, formatted, true);
 
             if (msg.OneShot)
             return result;
         }
 
-        public static string FormatMessage(RellorToken token, LogLevel level, string prefix, int code, string text)
+        public static string FormatMessage(string sourceName, int line, int charPositionInLine, LogLevel level, string prefix, int code, string text)
         {
             Contract.Requires(prefix != null);
             Contract.Requires(!string.IsNullOrEmpty(text));
             Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));
 
-            if (token == null)
+            if (sourceName == null)
                 return string.Format("{0} {1}{2}: {3}", Messages.FormatLevel(level), prefix, code, text);
             else
                 return string.Format("{0}:{1}:{2}: {3} {4}{5}: {6}",
-                    token.InputStream.SourceName, token.Line, token.CharPositionInLine + 1,
+                    sourceName, line, charPositionInLine + 1,
                     Messages.FormatLevel(level), prefix, code, text);
         }
 

Rellor.Core/Rellor.Core.csproj

   </ItemGroup>
   <ItemGroup>
     <Compile Include="Analyzer.cs" />
+    <Compile Include="EvalConstant.g3.cs">
+      <DependentUpon>EvalConstant.g3</DependentUpon>
+    </Compile>
     <Compile Include="ITargetCapabilities.cs" />
-    <Compile Include="ITargetValidation.cs" />
+    <Compile Include="MemoryLogSink.cs" />
     <Compile Include="Messages.cs" />
     <Compile Include="RellorContracts.cs" />
     <Compile Include="Token\RellorToken.cs" />
       <Generator>MSBuild:Compile</Generator>
     </Antlr3>
   </ItemGroup>
+  <ItemGroup>
+    <Antlr3 Include="EvalConstant.g3">
+      <Generator>MSBuild:Compile</Generator>
+    </Antlr3>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Albrecht\" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

Rellor.Core/Symbol.cs

         public SymbolType Type { get; set; }
         public RellorToken FirstReference { get; set; }
         public RellorToken DefiningToken { get; set; }
-        public ITree Definition { get; set; }
+        public ITree DefiningTree { get; set; }
         public bool Defined { get; set; }
         public bool Referenced { get; set; }
         public object Value { get; set; }
+        public Func<int> Future { get; set; }
     }
 }

RellorC/Program.cs

   with before [; print ""Don't touch that.^""; ];
 ";*/
             var logSink = new ConsoleLogSink();
-            var lexer = new Inform6Lexer(new ANTLRStringStream(SText) { name = "<string>" });
-            var parser = new Inform6Parser(new RellorTokenStream(lexer)) { LogSink = logSink };
-            var parserResult = parser.program(null);
+            var stream = new ANTLRStringStream(SText) { name = "<string>" };
 
-            Console.WriteLine("Parser result:");
-            DumpTree(parserResult.Tree, parser.TokenNames);
-            Console.ReadLine();
+            var analyzer = new Analyzer();
+            analyzer.Load(stream);
 
-            var synth = new SpecializeOperators(new CommonTreeNodeStream(new RellorTreeAdaptor(), parserResult.Tree));
-            var synthResult = synth.Downup(parserResult.Tree, true);
-
-            Console.WriteLine("SpecializeOperators result:");
-            DumpTree((ITree)synthResult, parser.TokenNames);
+            DumpTree(analyzer.SyntaxTree, analyzer.TokenNames);
             Console.ReadLine();
         }