Compare commits

..

3 Commits

6 changed files with 185 additions and 85 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.meta

View File

@@ -1,4 +1,6 @@
namespace Convention.RScript.Matcher using System.Text.RegularExpressions;
namespace Convention.RScript.Matcher
{ {
public class NamespaceMater : IRSentenceMatcher public class NamespaceMater : IRSentenceMatcher
{ {
@@ -14,6 +16,21 @@
sentence.mode = RScriptSentence.Mode.ExitNamespace; sentence.mode = RScriptSentence.Mode.ExitNamespace;
return true; return true;
} }
else if (expression.StartsWith("namespace"))
{
sentence.mode = RScriptSentence.Mode.NamedSpace;
Regex regex = new(@"namespace\s*\(([a-zA-Z_][a-zA-Z0-9_]*)\)");
var match = regex.Match(expression);
if (match.Success)
{
sentence.content = match.Groups[1].Value;
return true;
}
else
{
throw new RScriptRuntimeException("Invalid namespace declaration", -1);
}
}
return false; return false;
} }
} }

View File

@@ -3,9 +3,16 @@
namespace Convention.RScript namespace Convention.RScript
{ {
[Serializable] [Serializable]
public class RScriptException : Exception public class RScriptRuntimeException : Exception
{ {
public RScriptException(string message, int runtimePointer) : base($"when running {runtimePointer}, {message}") { } public RScriptRuntimeException(string message, int runtimePointer) : base($"when running {runtimePointer}, {message}") { }
public RScriptException(string message, int runtimePointer, Exception inner) : base($"when running {runtimePointer}, {message}", inner) { } public RScriptRuntimeException(string message, int runtimePointer, Exception inner) : base($"when running {runtimePointer}, {message}", inner) { }
}
[Serializable]
public class RScriptCompileException : Exception
{
public RScriptCompileException(string message, int line, int chIndex) : base($"when compile on line {line} char {chIndex}, {message}") { }
public RScriptCompileException(string message, int line, int chIndex, Exception inner) : base($"when compile on line {line} char {chIndex}, {message}", inner) { }
} }
} }

View File

@@ -1,6 +1,7 @@
using Convention.RScript.Matcher; using Convention.RScript.Matcher;
using Convention.RScript.Parser; using Convention.RScript.Parser;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -31,11 +32,11 @@ namespace Convention.RScript
/// </summary> /// </summary>
ExitNamespace, ExitNamespace,
/// <summary> /// <summary>
/// 标签, 格式: label(labelname) /// 标签, 格式: label(labelname);
/// </summary> /// </summary>
Label, Label,
/// <summary> /// <summary>
/// 跳转到指定标签, 格式: goto(boolean,labelname) /// 跳转到指定标签, 格式: goto(boolean,labelname);
/// <para>判断为真时跳转到labelname</para> /// <para>判断为真时跳转到labelname</para>
/// </summary> /// </summary>
Goto, Goto,
@@ -47,6 +48,10 @@ namespace Convention.RScript
/// 跳转到上次跳转的位置的后一个位置, 格式: back(boolean); /// 跳转到上次跳转的位置的后一个位置, 格式: back(boolean);
/// </summary> /// </summary>
Backpoint, Backpoint,
/// <summary>
/// 命名空间命名, 格式: namespace(labelname){}
/// </summary>
NamedSpace,
} }
public string content; public string content;
@@ -65,7 +70,8 @@ namespace Convention.RScript
public readonly RScriptVariables Variables; public readonly RScriptVariables Variables;
private readonly RScriptSentence[] Sentences; private readonly RScriptSentence[] Sentences;
private readonly Dictionary<string, int> Labels; private readonly Dictionary<string, int> Labels;
private readonly Dictionary<int, int> Namespace; private readonly Dictionary<int, int> NamespaceLayer;
private readonly Dictionary<string, int> NamespaceLabels;
public List<IRSentenceMatcher> SentenceParser = new() public List<IRSentenceMatcher> SentenceParser = new()
{ {
@@ -85,8 +91,8 @@ namespace Convention.RScript
mode = RScriptSentence.Mode.Expression mode = RScriptSentence.Mode.Expression
}; };
expression = expression.Trim(); expression = expression.Trim();
expression.TrimEnd(';'); expression = expression.TrimEnd(';');
SentenceParser.Any(matcher => matcher.Match(expression, ref result)); var _ = SentenceParser.Any(matcher => matcher.Match(expression, ref result));
return result; return result;
} }
@@ -106,14 +112,14 @@ namespace Convention.RScript
else if (Sentences[i].mode == RScriptSentence.Mode.ExitNamespace) else if (Sentences[i].mode == RScriptSentence.Mode.ExitNamespace)
{ {
if (namespaceLayers.Count == 0) if (namespaceLayers.Count == 0)
throw new RScriptException("Namespace exit without enter.", i); throw new RScriptRuntimeException("Namespace exit without enter.", i);
var enterPointer = namespaceLayers.Pop(); var enterPointer = namespaceLayers.Pop();
namespaceIndicator[enterPointer] = i; namespaceIndicator[enterPointer] = i;
} }
} }
if (namespaceLayers.Count > 0) if (namespaceLayers.Count > 0)
{ {
throw new RScriptException("Namespace enter without exit.", namespaceLayers.Peek()); throw new RScriptRuntimeException("Namespace enter without exit.", namespaceLayers.Peek());
} }
} }
@@ -123,8 +129,9 @@ namespace Convention.RScript
this.Variables = variables ?? new(); this.Variables = variables ?? new();
this.Sentences = (from item in expressions select ParseToSentence(item)).ToArray(); this.Sentences = (from item in expressions select ParseToSentence(item)).ToArray();
this.Labels = new(); this.Labels = new();
this.Namespace = new(); this.NamespaceLayer = new();
BuildUpLabelsAndNamespace(ref this.Labels, ref this.Namespace); this.NamespaceLabels = new();
BuildUpLabelsAndNamespace(ref this.Labels, ref this.NamespaceLayer);
} }
@@ -170,7 +177,7 @@ namespace Convention.RScript
} }
else else
{ {
throw new RScriptException($"Unsupported variable type '{varTypeName}'.", CurrentRuntimePointer); throw new RScriptRuntimeException($"Unsupported variable type '{varTypeName}'.", CurrentRuntimePointer);
} }
} }
if (CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false) if (CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false)
@@ -181,7 +188,7 @@ namespace Convention.RScript
} }
else else
{ {
throw new RScriptException($"Variable '{varName}' already defined on this namespace.", CurrentRuntimePointer); throw new RScriptRuntimeException($"Variable '{varName}' already defined on this namespace.", CurrentRuntimePointer);
} }
} }
@@ -251,7 +258,7 @@ namespace Convention.RScript
} }
else else
{ {
throw new RScriptException($"Label '{sentence.content}' not found.", CurrentRuntimePointer); throw new RScriptRuntimeException($"Label '{sentence.content}' not found.", CurrentRuntimePointer);
} }
} }
} }
@@ -265,7 +272,7 @@ namespace Convention.RScript
{ {
CurrentRuntimePointer = Sentences.Length; CurrentRuntimePointer = Sentences.Length;
} }
else if (Namespace.TryGetValue(RuntimePointerStack.Peek(), out var exitPointer)) else if (NamespaceLayer.TryGetValue(RuntimePointerStack.Peek(), out var exitPointer))
{ {
CurrentRuntimePointer = exitPointer; CurrentRuntimePointer = exitPointer;
DoExitNamespace(parser); DoExitNamespace(parser);
@@ -293,17 +300,13 @@ namespace Convention.RScript
} }
} }
private void RunNextStep(ExpressionParser parser) private object RunNextStep(ExpressionParser parser)
{ {
var sentence = CurrentSentence; var sentence = CurrentSentence;
switch (sentence.mode) switch (sentence.mode)
{ {
case RScriptSentence.Mode.Expression: case RScriptSentence.Mode.Expression:
{ return parser.Evaluate(sentence.content);
// 执行表达式
parser.Evaluate(sentence.content);
}
break;
case RScriptSentence.Mode.DefineVariable: case RScriptSentence.Mode.DefineVariable:
{ {
DoDefineVariable(parser, sentence); DoDefineVariable(parser, sentence);
@@ -326,7 +329,7 @@ namespace Convention.RScript
break; break;
case RScriptSentence.Mode.Breakpoint: case RScriptSentence.Mode.Breakpoint:
{ {
DoBreakpoint(parser,sentence); DoBreakpoint(parser, sentence);
} }
break; break;
case RScriptSentence.Mode.Backpoint: case RScriptSentence.Mode.Backpoint:
@@ -338,6 +341,7 @@ namespace Convention.RScript
// Do nothing // Do nothing
break; break;
} }
return null;
} }
private readonly Stack<int> RuntimePointerStack = new(); private readonly Stack<int> RuntimePointerStack = new();
@@ -345,7 +349,17 @@ namespace Convention.RScript
private int CurrentRuntimePointer = 0; private int CurrentRuntimePointer = 0;
private readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new(); private readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new();
public Dictionary<string, RScriptVariableEntry> Run(ExpressionParser parser) public Dictionary<string, RScriptVariableEntry> GetCurrentVariables()
{
Dictionary<string, RScriptVariableEntry> result = new();
foreach (var (key, value) in Variables)
{
result[key] = value;
}
return result;
}
public void Run(ExpressionParser parser)
{ {
CurrentLocalSpaceVariableNames.Clear(); CurrentLocalSpaceVariableNames.Clear();
RuntimePointerStack.Clear(); RuntimePointerStack.Clear();
@@ -362,7 +376,30 @@ namespace Convention.RScript
if (Variables.ContainsKey(varName)) if (Variables.ContainsKey(varName))
Variables.SetValue(varName, varValue); Variables.SetValue(varName, varValue);
} }
return Variables.ToDictionary(); }
public IEnumerator RunAsync(ExpressionParser parser)
{
CurrentLocalSpaceVariableNames.Clear();
RuntimePointerStack.Clear();
GotoPointerStack.Clear();
CurrentLocalSpaceVariableNames.Clear();
CurrentLocalSpaceVariableNames.Push(new());
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
{
var ret = RunNextStep(parser);
if (ret is IEnumerator ir)
{
yield return ir;
}
yield return null;
}
// 更新上下文变量
foreach (var (varName, varValue) in parser.context.Variables)
{
if (Variables.ContainsKey(varName))
Variables.SetValue(varName, varValue);
}
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using Convention.RScript.Parser; using Convention.RScript.Parser;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -18,10 +19,7 @@ namespace Convention.RScript
StringBuilder builder = new(); StringBuilder builder = new();
List<string> statements = new(); List<string> statements = new();
for (int i = 0, e = script.Length; i < e; i++) void PushBuilder()
{
char c = script[i];
if (c == ';')
{ {
if (builder.Length > 0) if (builder.Length > 0)
{ {
@@ -29,6 +27,18 @@ namespace Convention.RScript
builder.Clear(); builder.Clear();
} }
} }
var lines = script.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++)
{
string line = lines[lineIndex];
for (int i = 0, e = line.Length; i < e; i++)
{
char c = line[i];
if (c == ';')
{
PushBuilder();
}
else if (c == '/' && i + 1 < e) else if (c == '/' && i + 1 < e)
{ {
// Skip single-line comment // Skip single-line comment
@@ -71,29 +81,45 @@ namespace Convention.RScript
if (i < e) if (i < e)
builder.Append(script[i]); builder.Append(script[i]);
else else
throw new RScriptException("Invalid escape sequence in string literal", -1); throw new RScriptCompileException("Invalid escape sequence in string literal", lineIndex, i);
} }
} }
} }
else if (c == '{' || c == '}') else if (c == '{' || c == '}')
{ {
// Treat braces as statement separators PushBuilder();
if (builder.Length > 0)
{
statements.Add(builder.ToString().Trim());
builder.Clear();
}
statements.Add(c.ToString()); statements.Add(c.ToString());
} }
else if (string.Compare("namespace", 0, script, i, "namespace".Length) == 0)
{
builder.Append("namespace");
i += "namespace".Length;
if (i >= e)
throw new RScriptCompileException("Invalid namespace declaration", lineIndex, i);
Regex regex = new(@"^\s*\([a-zA-Z_][a-zA-Z0-9_]*\)");
var match = regex.Match(script, i);
if (match.Success)
{
builder.Append(match.Value);
PushBuilder();
i += match.Length;
}
else
{
throw new RScriptCompileException("Invalid namespace declaration", lineIndex, i);
}
// 前面的操作中已经完成位移, 此处是抵消循环中的i++
i -= 1;
}
else else
{ {
builder.Append(c); builder.Append(c);
} }
} }
}
if (builder.Length > 0) if (builder.Length > 0)
{ {
statements.Add(builder.ToString().Trim()); PushBuilder();
builder.Clear();
} }
return statements.Where(s => !string.IsNullOrWhiteSpace(s)); return statements.Where(s => !string.IsNullOrWhiteSpace(s));
@@ -105,7 +131,17 @@ namespace Convention.RScript
context = new(SplitScript(script).ToArray(), import, variables); context = new(SplitScript(script).ToArray(), import, variables);
foreach (var type in context.Import) foreach (var type in context.Import)
parser.context.Imports.AddType(type); parser.context.Imports.AddType(type);
return context.Run(parser); context.Run(parser);
return context.GetCurrentVariables();
}
public IEnumerator RunAsync(string script, RScriptImportClass import = null, RScriptVariables variables = null)
{
parser = new(new());
context = new(SplitScript(script).ToArray(), import, variables);
foreach (var type in context.Import)
parser.context.Imports.AddType(type);
return context.RunAsync(parser);
} }
} }
} }