Skip to content

Commit

Permalink
Поддержка меток в парсере
Browse files Browse the repository at this point in the history
  • Loading branch information
EvilBeaver committed Oct 19, 2023
1 parent 8fa327f commit 4735767
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/OneScript.Language/LanguageDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ static LanguageDef()
AddToken(Token.RemoveHandler, "УдалитьОбработчик", "RemoveHandler");
AddToken(Token.Async, "Асинх", "Async");
AddToken(Token.Await, "Ждать", "Await");
AddToken(Token.Goto, "Перейти", "Goto");

#endregion

Expand Down
16 changes: 15 additions & 1 deletion src/OneScript.Language/LexicalAnalysis/LabelLexerState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public class LabelLexerState : LexerState
"Ожидается имя метки",
"Label name expected"
);

private static BilingualString INVALID_LABEL = new BilingualString(
"Неверно задана метка",
"Invalid label definition"
);

WordLexerState _wordExtractor = new WordLexerState();

Expand All @@ -25,11 +30,20 @@ public override Lexem ReadNextLexem(SourceCodeIterator iterator)
throw CreateExceptionOnCurrentLine(MESSAGE_NAME_EXPECTED.ToString(), iterator);

var result = _wordExtractor.ReadNextLexem(iterator);
if (!LanguageDef.IsUserSymbol(result))
{
throw CreateExceptionOnCurrentLine(INVALID_LABEL.ToString(), iterator);
}

result.Type = LexemType.LabelRef;
if (iterator.CurrentSymbol == SpecialChars.Colon)
{
result.Type = LexemType.Label;
iterator.MoveNext();
var tail = iterator.ReadToLineEnd();
if (tail.Trim().Length != 0)
{
throw CreateExceptionOnCurrentLine(INVALID_LABEL.ToString(), iterator);
}
}

result.Location = start;
Expand Down
1 change: 1 addition & 0 deletions src/OneScript.Language/LexicalAnalysis/Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public enum Token
RemoveHandler,
Async,
Await,
Goto,

// operators
Plus,
Expand Down
14 changes: 14 additions & 0 deletions src/OneScript.Language/SyntaxAnalysis/AstNodes/LabelNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using OneScript.Language.LexicalAnalysis;

namespace OneScript.Language.SyntaxAnalysis.AstNodes
{
public class LabelNode : LineMarkerNode
{
public LabelNode(Lexem labelLexem) : base(labelLexem.Location, NodeKind.Label)
{
LabelName = labelLexem.Content;
}

public string LabelName { get; }
}
}
10 changes: 10 additions & 0 deletions src/OneScript.Language/SyntaxAnalysis/BslSyntaxWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,19 @@ private void CreateVisitors()
_nodeVisitors[(int)NodeKind.RemoveHandler] = VisitHandlerOperation;
_nodeVisitors[(int)NodeKind.NewObject] = (x) => VisitNewObjectCreation((NewObjectNode)x);
_nodeVisitors[(int)NodeKind.Preprocessor] = (x) => VisitPreprocessorDirective((PreprocessorDirectiveNode)x);
_nodeVisitors[(int)NodeKind.Goto] = (x) => VisitGotoNode((NonTerminalNode)x);
_nodeVisitors[(int)NodeKind.Label] = (x) => VisitLabelNode((LabelNode)x);

}

protected virtual void VisitGotoNode(NonTerminalNode node)
{
}

protected virtual void VisitLabelNode(LabelNode node)
{
}

protected void SetDefaultVisitorFor(NodeKind kind, Action<BslSyntaxNode> action)
{
_nodeVisitors[(int)kind] = action;
Expand Down
32 changes: 32 additions & 0 deletions src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,12 @@ private void BuildCodeBatch(params Token[] endTokens)
continue;
}

if (_lastExtractedLexem.Type == LexemType.Label)
{
DefineLabel(_lastExtractedLexem);
continue;
}

if (_lastExtractedLexem.Type != LexemType.Identifier && _lastExtractedLexem.Token != Token.EndOfText)
{
AddError(LocalizedErrors.UnexpectedOperation());
Expand All @@ -642,6 +648,13 @@ private void BuildCodeBatch(params Token[] endTokens)
PopStructureToken();
}

private void DefineLabel(Lexem label)
{
var node = new LabelNode(label);
_nodeContext.AddChild(node);
NextLexem();
}

#region Statements

private void BuildStatement()
Expand Down Expand Up @@ -694,6 +707,9 @@ private void BuildComplexStructureStatement()
case Token.Await:
BuildGlobalCallAwaitOperator();
break;
case Token.Goto:
BuildGotoOperator();
break;
default:
var expected = _tokenStack.Peek();
AddError(LocalizedErrors.TokenExpected(expected));
Expand Down Expand Up @@ -734,6 +750,22 @@ private BslSyntaxNode BuildExpressionAwaitOperator(Lexem lexem)
return new ErrorTerminalNode(_lastExtractedLexem);
}
}

private void BuildGotoOperator()
{
var gotoNode = new NonTerminalNode(NodeKind.Goto, _lastExtractedLexem);
NextLexem();

if (_lastExtractedLexem.Type != LexemType.LabelRef)
{
AddError(LocalizedErrors.LabelNameExpected());
}

gotoNode.AddChild(new LabelNode(_lastExtractedLexem));
NextLexem();

_nodeContext.AddChild(gotoNode);
}

private void CheckAsyncMethod()
{
Expand Down
6 changes: 6 additions & 0 deletions src/OneScript.Language/SyntaxAnalysis/LocalizedErrors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ private static CodeError Create(string ru, string en, [CallerMemberName] string

public static CodeError IdentifierExpected()
=> Create("Ожидается идентификатор", "Identifier expecting");

public static CodeError LabelNameExpected()
=> Create("Ожидается имя метки", "Label name expected");

public static CodeError ExpressionSyntax()
=> Create("Ошибка в выражении", "Expression syntax error");
Expand Down Expand Up @@ -139,5 +142,8 @@ public static CodeError DuplicateMethodDefinition(string methodName) =>

public static CodeError SymbolNotFound(string symbol) =>
Create($"Неизвестный символ: {symbol}", $"Symbol not found {symbol}");

public static CodeError AsyncMethodsNotSupported() =>
Create("Асинхронные методы не поддерживаются", "Async methods aren't supported");
}
}
2 changes: 2 additions & 0 deletions src/OneScript.Language/SyntaxAnalysis/NodeKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,7 @@ public enum NodeKind
Preprocessor,
Import,
TopLevelExpression,
Label,
Goto
}
}
15 changes: 15 additions & 0 deletions src/OneScript.Native/Compiler/ModuleCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This Source Code Form is subject to the terms of the
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using System;
using System.Linq;
using OneScript.Compilation;
using OneScript.Compilation.Binding;
Expand Down Expand Up @@ -166,8 +167,22 @@ protected override void VisitModuleVariable(VariableDefinitionNode varNode)
}
}

protected override void VisitGotoNode(NonTerminalNode node)
{
throw new NotSupportedException();
}

protected override void VisitLabelNode(LabelNode node)
{
throw new NotSupportedException();
}

protected override void VisitMethod(MethodNode methodNode)
{
if (methodNode.IsAsync)
{
AddError(LocalizedErrors.AsyncMethodsNotSupported(), methodNode.Location);
}
var methodSymbol = Symbols.GetScope(Symbols.ScopeCount - 1).Methods[methodNode.Signature.MethodName];
var methodInfo = (BslNativeMethodInfo)methodSymbol.Method;

Expand Down
14 changes: 14 additions & 0 deletions src/ScriptEngine/Compiler/StackMachineCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,23 @@ private static string[] GetVariableNames(SymbolScope localCtx)
return localCtx.Variables.Select(v => v.Name).ToArray();

}

protected override void VisitGotoNode(NonTerminalNode node)
{
throw new NotSupportedException();
}

protected override void VisitLabelNode(LabelNode node)
{
throw new NotSupportedException();
}

protected override void VisitMethod(MethodNode methodNode)
{
if (methodNode.IsAsync)
{
AddError(LocalizedErrors.AsyncMethodsNotSupported(), methodNode.Location);
}
var signature = methodNode.Signature;
var methodBuilder = NewMethod();

Expand Down
5 changes: 3 additions & 2 deletions src/Tests/OneScript.Language.Tests/LexerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -634,9 +634,10 @@ public void Lexer_Ignores_Comments()
}

[Fact]
public void Leer_Extracts_Labels()
public void Lexer_Extracts_Labels()
{
string code = "~ImALabel: ~LabelRef;";
string code = "~ImALabel:\n" +
" ~LabelRef;";
var lexer = GetLexerForCode(code);

var lex = lexer.NextLexem();
Expand Down
32 changes: 32 additions & 0 deletions src/Tests/OneScript.Language.Tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,38 @@ public void DoubleAwaitIsForbidden()

CatchParsingError(code, err => err.Single().ErrorId.Should().Be("ExpressionSyntax"));
}

[Fact]
public void Labels_Can_Appear_In_CodeBlocks()
{
var code =
@"А = 1;
~Метка:
Б = 2;
";

var validator = ParseBatchAndGetValidator(code);

validator.NextChildIs(NodeKind.Assignment);
validator.NextChildIs(NodeKind.Label);
validator.NextChildIs(NodeKind.Assignment);
}

[Fact]
public void Goto_Can_Appear_In_CodeBlocks()
{
var code =
@"А = 1;
Перейти ~Метка;
Б = 2;
";

var validator = ParseBatchAndGetValidator(code);

validator.NextChildIs(NodeKind.Assignment);
validator.NextChildIs(NodeKind.Goto);
validator.NextChildIs(NodeKind.Assignment);
}

private static void CatchParsingError(string code)
{
Expand Down

0 comments on commit 4735767

Please sign in to comment.