diff --git a/Source/.idea/.idea.Furesoft.PrattParser/.idea/.gitignore b/Source/.idea/.idea.Furesoft.PrattParser/.idea/.gitignore deleted file mode 100644 index 20f1115..0000000 --- a/Source/.idea/.idea.Furesoft.PrattParser/.idea/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Rider ignored files -/projectSettingsUpdater.xml -/contentModel.xml -/modules.xml -/.idea.Furesoft.PrattParser.iml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/Source/.idea/.idea.Furesoft.PrattParser/.idea/.name b/Source/.idea/.idea.Furesoft.PrattParser/.idea/.name deleted file mode 100644 index 2abca0e..0000000 --- a/Source/.idea/.idea.Furesoft.PrattParser/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Furesoft.PrattParser \ No newline at end of file diff --git a/Source/.idea/.idea.Furesoft.PrattParser/.idea/encodings.xml b/Source/.idea/.idea.Furesoft.PrattParser/.idea/encodings.xml deleted file mode 100644 index df87cf9..0000000 --- a/Source/.idea/.idea.Furesoft.PrattParser/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Source/.idea/.idea.Furesoft.PrattParser/.idea/indexLayout.xml b/Source/.idea/.idea.Furesoft.PrattParser/.idea/indexLayout.xml deleted file mode 100644 index 7b08163..0000000 --- a/Source/.idea/.idea.Furesoft.PrattParser/.idea/indexLayout.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Source/.idea/.idea.Furesoft.PrattParser/.idea/vcs.xml b/Source/.idea/.idea.Furesoft.PrattParser/.idea/vcs.xml deleted file mode 100644 index 6c0b863..0000000 --- a/Source/.idea/.idea.Furesoft.PrattParser/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Source/Furesoft.PrattParser/Parser.DynamicHelper.cs b/Source/Furesoft.PrattParser/Parser.DynamicHelper.cs new file mode 100644 index 0000000..e645bcd --- /dev/null +++ b/Source/Furesoft.PrattParser/Parser.DynamicHelper.cs @@ -0,0 +1,130 @@ + +using System.Collections.Generic; +using Furesoft.PrattParser.Nodes; +using Furesoft.PrattParser.Parselets; +using Furesoft.PrattParser.Parselets.Builder; +using Furesoft.PrattParser.Parselets.Builder.Elements; + +namespace Furesoft.PrattParser; + +public partial class Parser +{ + /// Add a dynamic parselet to parse an expression based on a declarative definition + public void ExprBuilder(SyntaxElement definition) + where TNode : AstNode + { + Builder(definition, NodeType.Expression); + } + + /// Add a dynamic parselet to parse a statement based on a declarative definition + public void StmtBuilder(SyntaxElement definition) + where TNode : AstNode + { + Builder(definition, NodeType.Statement); + } + + private static void GetKeywordsFromDefinition(SyntaxElement definition, List result) + { + if (definition is KeywordElement kw) + { + result.Add(kw.Keyword); + + return; + } + + if (definition is BinaryElement and) + { + GetKeywordsFromDefinition(and.First, result); + GetKeywordsFromDefinition(and.Second, result); + } + } + + private static bool TryMatchUnaryOperatorKind(SyntaxElement definition, out TFirst first, out TSecond second) + { + if (definition is AndElement andElement) + { + if (andElement.First is TFirst firstElement && andElement.Second is TSecond secondElement) + { + first = firstElement; + second = secondElement; + + return true; + } + } + + first = default; + second = default; + + return false; + } + + protected void Operator(SyntaxElement definition, string precedenceName = null) + { + if (TryMatchUnaryOperatorKind(definition, out var prefixKw, out var prefixExpr)) + { + _lexer.AddSymbol(prefixKw.Keyword); + Prefix(prefixKw.Keyword, precedenceName ?? "Prefix"); + } + else if (TryMatchUnaryOperatorKind(definition, out var postfixExpr, out var postfixKw)) + { + _lexer.AddSymbol(postfixKw.Keyword); + Postfix(postfixKw.Keyword, precedenceName ?? "Postfix"); + } + } + + private void Builder(SyntaxElement definition, NodeType type) + where TNode : AstNode + { + AddSymbolsFromBuilderToLexer(definition); + + var parselet = new BuilderParselet(BindingPowers.Get("Product"), definition); //Todo: enable custom binding power + + if (definition is AndElement andElement && andElement.First is KeywordElement kw && andElement.Second is ExprElement) + { + Prefix(kw.Keyword); + } + + var recognitionKeywords = new List(); + GetRecognitionKeywords(definition, recognitionKeywords); + + foreach (var keyword in recognitionKeywords) + { + switch (type) + { + default: + case NodeType.Expression: + Register(keyword, (IPrefixParselet)parselet); + break; + case NodeType.Statement: + Register(keyword, (IStatementParselet)parselet); + break; + } + } + } + + private void AddSymbolsFromBuilderToLexer(SyntaxElement definition) + { + var allSymbols = new List(); + GetKeywordsFromDefinition(definition, allSymbols); + + _lexer.AddSymbols([.. allSymbols]); + } + + static void GetRecognitionKeywords(SyntaxElement element, List keywords) + { + if (element is KeywordElement keywordElement) + { + keywords.Add(keywordElement.Keyword); + } + + if (element is AndElement and) + { + GetRecognitionKeywords(and.First, keywords); + } + else if (element is OrElement or) + { + GetRecognitionKeywords(or.First, keywords); + GetRecognitionKeywords(or.Second, keywords); + } + } +} \ No newline at end of file diff --git a/Source/Furesoft.PrattParser/Parser.cs b/Source/Furesoft.PrattParser/Parser.cs index 0ada12d..3c2fce1 100644 --- a/Source/Furesoft.PrattParser/Parser.cs +++ b/Source/Furesoft.PrattParser/Parser.cs @@ -61,125 +61,6 @@ public void Block(Symbol start, Symbol terminator, Symbol seperator = null, bool Register(start, new BlockParselet(terminator, seperator, wrapExpressions)); } - /// Add a dynamic parselet to parse an expression based on a declarative definition - public void ExprBuilder(SyntaxElement definition) - where TNode : AstNode - { - Builder(definition, NodeType.Expression); - } - - /// Add a dynamic parselet to parse a statement based on a declarative definition - public void StmtBuilder(SyntaxElement definition) - where TNode : AstNode - { - Builder(definition, NodeType.Statement); - } - - private static void GetKeywordsFromDefinition(SyntaxElement definition, List result) - { - if (definition is KeywordElement kw) - { - result.Add(kw.Keyword); - - return; - } - - if (definition is BinaryElement and) - { - GetKeywordsFromDefinition(and.First, result); - GetKeywordsFromDefinition(and.Second, result); - } - } - - private static bool TryMatchOperatorKind(SyntaxElement definition, out TFirst first, out TSecond second) - { - if (definition is AndElement andElement) - { - if (andElement.First is TFirst firstElement && andElement.Second is TSecond secondElement) - { - first = firstElement; - second = secondElement; - - return true; - } - } - - first = default; - second = default; - - return false; - } - - protected void Operator(SyntaxElement definition, string precedenceName = null) - { - if (TryMatchOperatorKind(definition, out var prefixKw, out var prefixExpr)) - { - _lexer.AddSymbol(prefixKw.Keyword); - Prefix(prefixKw.Keyword, precedenceName ?? "Prefix"); - } - else if (TryMatchOperatorKind(definition, out var postfixExpr, out var postfixKw)) - { - _lexer.AddSymbol(postfixKw.Keyword); - Postfix(postfixKw.Keyword, precedenceName ?? "Postfix"); - } - } - - private void Builder(SyntaxElement definition, NodeType type) - where TNode : AstNode - { - AddSymbolsFromBuilderToLexer(definition); - - var parselet = new BuilderParselet(BindingPowers.Get("Product"), definition); //Todo: enable custom binding power - - if (definition is AndElement andElement && andElement.First is KeywordElement kw && andElement.Second is ExprElement) - { - Prefix(kw.Keyword); - } - - var recognitionKeywords = new List(); - GetRecognitionKeywords(definition, recognitionKeywords); - - foreach (var keyword in recognitionKeywords) - { - switch (type) - { - default: - case NodeType.Expression: - Register(keyword, (IPrefixParselet)parselet); - break; - case NodeType.Statement: - Register(keyword, (IStatementParselet)parselet); - break; - } - } - } - - private void AddSymbolsFromBuilderToLexer(SyntaxElement definition) - { - var allSymbols = new List(); - GetKeywordsFromDefinition(definition, allSymbols); - - _lexer.AddSymbols([.. allSymbols]); - } - - static void GetRecognitionKeywords(SyntaxElement element, List keywords) - { - if (element is KeywordElement keywordElement) - { - keywords.Add(keywordElement.Keyword); - } - - if (element is AndElement and) - { - GetRecognitionKeywords(and.First, keywords); - } - else if (element is OrElement or) - { - GetRecognitionKeywords(or.First, keywords); - GetRecognitionKeywords(or.Second, keywords); - } - } - public AstNode ParseStatement(bool wrapExpressions = false) { var token = LookAhead(0);