304 lines
10 KiB
C#
304 lines
10 KiB
C#
//-----------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------
|
|
// file="ExpSyntaxAnalyzer.Common"
|
|
// Project: StgSharp
|
|
// AuthorGroup: Nitload Space
|
|
// Copyright (c) Nitload Space. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
// -----------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
|
|
using StgSharp.Script;
|
|
using StgSharp.Script.Express;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Schema;
|
|
|
|
using ExpKeyword = StgSharp.Script.Express.ExpressCompile.Keyword;
|
|
|
|
namespace StgSharp.Model.Step
|
|
{
|
|
internal partial class StepExpSyntaxAnalyzer
|
|
{
|
|
|
|
private static Regex _entityTypeCheckPattern = GetEntityTypeCheckPattern();
|
|
|
|
private StepDependencyDetector _dependencyDetector = new StepDependencyDetector();
|
|
|
|
[GeneratedRegex(@"^[A-Z0-9_]+$", RegexOptions.Singleline)]
|
|
private static partial Regex GetEntityTypeCheckPattern();
|
|
|
|
private bool IsSeparatorMatch(Token leftSeparator, Token rightSeparator)
|
|
{
|
|
return leftSeparator.Value switch
|
|
{
|
|
ExpKeyword.LeftBrace => rightSeparator.Value == ExpKeyword.RightBrace,
|
|
ExpKeyword.LeftParen => rightSeparator.Value == ExpKeyword.RightParen,
|
|
ExpKeyword.Comma => rightSeparator.Value == ExpKeyword.Comma,
|
|
ExpKeyword.Semicolon => rightSeparator.Value == ExpKeyword.Semicolon,
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
private bool TryAppendIndexLeft(Token t)
|
|
{
|
|
if (t.Flag != TokenFlag.Index_Left) {
|
|
return false;
|
|
}
|
|
if (_cache.TryPeekOperand(out bool isNode, out _, out ExpSyntaxNode? node))
|
|
{
|
|
if (node.EqualityTypeConvert is not ExpCollectionBase) {
|
|
ExpInvalidSyntaxException.ThrowNonCollectionIndex(t);
|
|
}
|
|
}
|
|
_cache.PushOperator(t);
|
|
_cache.IncreaseDepth((int)ExpCompileStateCode.CollectionIndex);
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendIndexRight(Token t)
|
|
{
|
|
if (t.Flag != TokenFlag.Index_Right) {
|
|
return false;
|
|
}
|
|
|
|
// reverse building
|
|
ClosePrefixReverse(t);
|
|
|
|
// make index node
|
|
_cache.PopOperand(out _, out ExpSyntaxNode? expNode);
|
|
if (!_cache.PopOperand(out Token colleToken, out ExpSyntaxNode? colleNode)) { }
|
|
_cache.PushOperand(
|
|
ExpCollectionIndexNode.Create(
|
|
t, (colleNode as ExpCollectionInstanceBase)!, expNode));
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendMember(Token t)
|
|
{
|
|
if (t.Flag != TokenFlag.Member) {
|
|
return false;
|
|
}
|
|
if (TryParseConstant(t)) {
|
|
return true;
|
|
}
|
|
if (TryParseFunction(t)) {
|
|
return true;
|
|
}
|
|
if (TryParseInstance(t)) {
|
|
return true;
|
|
}
|
|
if (TryParseKeyword(t)) {
|
|
return true;
|
|
}
|
|
if (TryParseElementName(t)) {
|
|
return true;
|
|
}
|
|
|
|
// Many thing miss here
|
|
_cache.PushOperand(ExpElementMemberNameNode.Create(t));
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendMiddleSeparator(Token t)
|
|
{
|
|
if (t.Flag != TokenFlag.Separator_Middle) {
|
|
return false;
|
|
}
|
|
while (_cache.OperatorAheadOfDepth > 0)
|
|
{
|
|
_cache.TryPopOperator(out Token op);
|
|
ExpSyntaxNode node = ConvertAndPushOneOperator(op);
|
|
}
|
|
switch (_cache.OperandAheadOfDepth)
|
|
{
|
|
case 0:
|
|
if (t.Value == ";") {
|
|
return true;
|
|
}
|
|
_cache.StatementsInDepth.Push(ExpSyntaxNode.Empty);
|
|
goto case 1;
|
|
case 1:
|
|
_cache.PopOperand(out _, out ExpSyntaxNode? statement);
|
|
if (t.Value == ";")
|
|
{
|
|
StepEntityDefineSequence sequence = new StepEntityDefineSequence(
|
|
statement, _dependencyDetector.ExportAllDependencies());
|
|
StepEntityInitStatements.Enqueue(sequence);
|
|
} else
|
|
{
|
|
_cache.StatementsInDepth.Push(statement);
|
|
}
|
|
|
|
return true;
|
|
default:
|
|
ExpInvalidSyntaxException.ThrowNoOperator(t);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendNumAndStrLiteral(Token t)
|
|
{
|
|
if ((t.Flag & (TokenFlag.String | TokenFlag.Number)) == 0) {
|
|
return false;
|
|
}
|
|
_cache.PushOperand(ExpElementInstance.CreateLiteral(t));
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendPrefixSeparator(Token t)
|
|
{
|
|
if (t.Flag != TokenFlag.Separator_Left) {
|
|
return false;
|
|
}
|
|
_cache.PushOperator(t);
|
|
_cache.IncreaseDepth((int)ExpCompileStateCode.Common);
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendPrefixSeparatorEnd(Token t)
|
|
{
|
|
if (t.Flag != TokenFlag.Separator_Right) {
|
|
return false;
|
|
}
|
|
ClosePrefixReverse(t);
|
|
return true;
|
|
}
|
|
|
|
private bool TryAppendSymbol(Token t)
|
|
{
|
|
if ((t.Flag & (TokenFlag.Symbol_Unary | TokenFlag.Symbol_Binary)) == 0) {
|
|
return false;
|
|
}
|
|
|
|
int cmp = -1;
|
|
processPrecedence:
|
|
if (_cache.TryPeekOperator(out Token tmp))
|
|
{
|
|
cmp = CompareOperatorPrecedence(t, tmp);
|
|
if (cmp >= 0)
|
|
{
|
|
_cache.PopOperator();
|
|
ExpSyntaxNode node = ConvertAndPushOneOperator(tmp);
|
|
goto processPrecedence;
|
|
}
|
|
}
|
|
_cache.PushOperator(t);
|
|
return true;
|
|
}
|
|
|
|
private bool TryParseConstant(Token t)
|
|
{
|
|
switch (t.Value)
|
|
{
|
|
case "$":
|
|
_cache.PushOperand(StepEntityInstanceNode.RegisterNull(t));
|
|
return true;
|
|
case "*":
|
|
_cache.PushOperand(StepEntityInstanceNode.RegisterRuntimeInference(t));
|
|
return true;
|
|
case ExpKeyword.E:
|
|
_cache.PushOperand(new ExpRealNumberNode(t, MathF.E, true));
|
|
return true;
|
|
case ExpKeyword.Pi:
|
|
_cache.PushOperand(new ExpRealNumberNode(t, MathF.PI, true));
|
|
return true;
|
|
default:
|
|
if (ExpElementInstance.TryCreateLiteral(t, out ExpElementInstance? node))
|
|
{
|
|
_cache.PushOperand(node);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool TryParseElementName(Token t)
|
|
{
|
|
if (_context.TryGetType(t.Value, out ExpTypeSource? type))
|
|
{
|
|
_cache.PushOperand(ExpMetaRefNode.RefType(t, type));
|
|
return true;
|
|
}
|
|
if (_context.TryGetEntity(t.Value, out ExpEntitySource? entity))
|
|
{
|
|
_cache.PushOperand(ExpMetaRefNode.RefEntity(t, entity));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool TryParseFunction(Token t)
|
|
{
|
|
if (_entityTypeCheckPattern.IsMatch(t.Value))
|
|
{
|
|
if (_cache.PeekOperator().Flag == TokenFlag.Member)
|
|
{
|
|
Token op = _cache.PopOperator();
|
|
ConvertAndPushOneOperator(op);
|
|
}
|
|
_cache.PushOperator(t);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool TryParseInstance(Token t)
|
|
{
|
|
if (t.Value[0] == '#')
|
|
{
|
|
StepEntityInstanceNode node = StepEntityInstanceNode.Register(t);
|
|
if (t.Column != 0) {
|
|
_dependencyDetector.AddDependency(node);
|
|
}
|
|
_cache.PushOperand(node);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool TryParseKeyword(Token t)
|
|
{
|
|
switch (t.Value)
|
|
{
|
|
case ExpKeyword.Return:
|
|
_cache.PushOperator(t);
|
|
return true;
|
|
case ExpKeyword.Skip:
|
|
_cache.PushOperand(ExpProcedureControlNode.Skip(t));
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|