Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #14 from DemonExposer/curly-parsing
Browse files Browse the repository at this point in the history
Curly parsing
  • Loading branch information
DemonExposer authored Aug 18, 2022
2 parents 0b274bd + c0eaffc commit c16bb89
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 43 deletions.
178 changes: 136 additions & 42 deletions Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
using Interpreter.Tokens.Statements.Binary;
using Interpreter.Tokens.Statements.Unary;

namespace Interpreter;
namespace Interpreter;

public class Parser {
public static int GetTopElementIndex(Token[] line, int startIndex, bool isRightBound) {
if (line[startIndex] is BinaryStatement)
if (line[startIndex] is BinaryStatement or MultilineStatementOperator)
return startIndex;

int highestPriorityNum = -1;
int index = -1;
for (int i = startIndex; i < line.Length && i >= 0; i += isRightBound ? 1 : -1) {
Expand All @@ -23,7 +23,7 @@ public static int GetTopElementIndex(Token[] line, int startIndex, bool isRightB
numBrackets++;
else if (Program.ClosingBrackets.Contains(line[i].Str))
numBrackets--;

while (numBrackets != 0) {
i += isRightBound ? 1 : -1;
if (Program.OpeningBrackets.Contains(line[i].Str))
Expand All @@ -46,15 +46,15 @@ public static int GetTopElementIndex(Token[] line, int startIndex, bool isRightB

return index;
}

public static CheckedString[] CheckComment(CheckedString[] line) {
for (int i = 0; i < line.Length; i++)
if (line[i].Str == "#")
return line.Take(i).ToArray();

return line;
}

/**
* This now practically just parses everything, so maybe some refactoring is needed
*/
Expand Down Expand Up @@ -96,15 +96,15 @@ private static Token[] BracketsParse(Token[] line, int i, string[] lines, ref in
numBrackets++;
else if (Program.ClosingBrackets.Contains(line[j].Str))
numBrackets--;

while (numBrackets != 0) {
if (isRightBound)
subLine.Add(line[j]);
else
subLine = subLine.Prepend(line[j]).ToList();

j += isRightBound ? 1 : -1;

if (Program.OpeningBrackets.Contains(line[j].Str))
numBrackets++;
else if (Program.ClosingBrackets.Contains(line[j].Str))
Expand Down Expand Up @@ -132,23 +132,21 @@ private static Token[] BracketsParse(Token[] line, int i, string[] lines, ref in
arguments.Add(subLine.ToArray());
else
arguments = arguments.Prepend(subLine.ToArray()).ToList();

// Parse each element in the brackets and put it in a new list
List<Token> properArguments = new List<Token>();
for (int j = 0; j < arguments.Count; j++)
properArguments.Add(Parse(arguments[j], GetTopElementIndex(arguments[j].ToArray(), 0, isRightBound), lines, ref lineNo, depth + 1));

return properArguments.ToArray();
}

/**
* Note that this is a bad implementation with too strict constraints, but for now, only functionality is important
*/
private static MultilineStatementOperator CurlyBracketsParse(Token[] line, string[] lines, ref int i, Token parent, int depth) {
// Get copy of vars so that it doesn't get affected by method calls lower in the recursion tree
List<Token> tokens = new List<Token>();
int initialIndex = ++i; // immediately increment i so that this function doesn't try to parse itself, but instead the next line (also fixes the error message)
int initialIndex = i;
int numBrackets = 1;
bool isFirstBracketFound = false;
MultilineStatementOperator firstFoundBracket = null!;
for (; i < lines.Length; i++) {
CheckedString[] lexedLine = Lexer.Lex(lines[i], i + 1);

Expand All @@ -158,36 +156,122 @@ private static MultilineStatementOperator CurlyBracketsParse(Token[] line, strin

Token[] tokenizedLine = Tokenizer.Tokenize(lexedLine);

// Find first curly bracket
int before = i;
bool doContinue = false;
if (!isFirstBracketFound) {
doContinue = true;
for (int j = 0; j < tokenizedLine.Length; j++) {
if (tokenizedLine[j] is MultilineStatementOperator mso) {
isFirstBracketFound = true;
firstFoundBracket = mso;
tokenizedLine = new ArraySegment<Token>(tokenizedLine, j + 1, tokenizedLine.Length - (j + 1)).ToArray();
doContinue = tokenizedLine.Length == 0; // Happens if first line of declaration ends with an opening curly bracket
break;
}
}
}

if (doContinue) // Happens for before mentioned case and if no curly bracket is found at all
continue;

tokens.Add(Parse(tokenizedLine, GetTopElementIndex(tokenizedLine, 0, true), lines, ref i, depth + 1));

if (i != before)
continue;

foreach (CheckedString cs in lexedLine) {
if (cs.Str == "}")
foreach (Token t in tokenizedLine) {
if (t.Str == "}")
numBrackets--;
else if (cs.Str == "{")
else if (t.Str == "{")
numBrackets++;

if (numBrackets == 0) {
if (parent is OnStatement onStat && tokenizedLine.Length > 1 && tokenizedLine[1] is ElseStatement)
onStat.ElseChild = (ElseStatement) Parse(tokenizedLine, 1, lines, ref i, depth + 1);

goto FullBreak;
}
}
}
FullBreak:

if (i >= lines.Length)
throw new FormatException("no matched bracket for bracket on line " + initialIndex);
throw new FormatException("no matched bracket for bracket on line " + (initialIndex + 1));

firstFoundBracket.Children = tokens.ToArray();

return firstFoundBracket;
}

private static DictionaryAssignmentOperator[] SimpleObjectParse(Token[] line, string[] lines, ref int i, int startIndex, int depth) {
int initialIndex = i;
int numBrackets = 0;
List<Token[]> properLines = new List<Token[]>();
List<Token> subLine = new List<Token>();
for (; i < lines.Length; i++) {
Token[] tokenizedLine;
int j = 0;
if (i == initialIndex) {
tokenizedLine = line;
j = startIndex;
} else {
CheckedString[] lexedLine = Lexer.Lex(lines[i], i + 1);

lexedLine = CheckComment(lexedLine);
if (lexedLine.Length == 0)
continue;

tokenizedLine = Tokenizer.Tokenize(lexedLine);
}

for (; j < tokenizedLine.Length; j++) {
Token t = tokenizedLine[j];
if (t.Str == "}")
numBrackets--;
else if (t.Str == "{") {
if (numBrackets == 0) { // Exclude opening bracket from line
numBrackets++;
continue;
}
numBrackets++;
}

if (t is CommaSeparator && numBrackets == 1) {
properLines.Add(subLine.ToArray());
subLine = new List<Token>();
continue;
}

if (numBrackets == 0) {
properLines.Add(subLine.ToArray());
goto FullBreak;
}

subLine.Add(t);
}
}
FullBreak:

List<DictionaryAssignmentOperator> objectBody = new List<DictionaryAssignmentOperator>();
foreach (Token[] properLine in properLines) {
// TODO: fix the ConcatenationOperator thing, because right here it's not performing concatenation
if (properLine[0] is not StringToken || properLine[1] is not ConcatenationOperator)
throw new FormatException("simple objects should only consist of declarations");

Token[] parseLine = new ArraySegment<Token>(properLine, 2, properLine.Length - 2).ToArray();
DictionaryAssignmentOperator objAssOp = new DictionaryAssignmentOperator();
objAssOp.Left = properLine[0];
objAssOp.Right = Parse(parseLine, GetTopElementIndex(parseLine, 0, true), lines, ref i, depth + 1);
objectBody.Add(objAssOp);
}

((MultilineStatementOperator) line[^1]).Children = tokens.ToArray();
if (i >= lines.Length)
throw new FormatException("no matched bracket for bracket on line " + (initialIndex + 1));

return (MultilineStatementOperator) line[^1];
return objectBody.ToArray();
}

public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, int depth) {
Token t = line[i];

Expand All @@ -197,12 +281,12 @@ public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, i
line[i].IsDone = true;

// Parse only the appropriate section (i.e. Left should only parse to the left and Right only to the right, that's what the array slicing does)
((BinaryOperator) t).Left = SymmetricBinaryOperatorParse(line.Take(i+1).ToArray(), i, lines, ref lineNo, depth + 1, false);
((BinaryOperator) t).Left = SymmetricBinaryOperatorParse(line.Take(i + 1).ToArray(), i, lines, ref lineNo, depth + 1, false);
((BinaryOperator) t).Right = SymmetricBinaryOperatorParse(new ArraySegment<Token>(line, i, line.Length - i).ToArray(), 0, lines, ref lineNo, depth + 1, true);
break;
case DeclarationOperator decOp: {
decOp.Left = Parse(line, i + 1, lines, ref lineNo, depth+1);
decOp.Left = Parse(line, i + 1, lines, ref lineNo, depth + 1);

if (i + 2 < line.Length) // Only Parse right hand side if it exists
decOp.Right = Parse(line, i + 2, lines, ref lineNo, depth + 1);
break;
Expand All @@ -218,10 +302,10 @@ public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, i
numBrackets++;
else if (Program.ClosingBrackets.Contains(line[j].Str))
numBrackets--;

while (numBrackets != 0) {
j--;

if (Program.OpeningBrackets.Contains(line[j].Str))
numBrackets++;
else if (Program.ClosingBrackets.Contains(line[j].Str))
Expand All @@ -231,10 +315,10 @@ public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, i

if (j >= 0 && line[j] is DotOperator)
j--;
assOp.Left = Parse(line, j + 1, lines, ref lineNo, depth+1);

assOp.Left = Parse(line, j + 1, lines, ref lineNo, depth + 1);
Token[] subLine = new ArraySegment<Token>(line, i, line.Length - i).ToArray();
assOp.Right = Parse(subLine, GetTopElementIndex(subLine, 1, true), lines, ref lineNo, depth+1);
assOp.Right = Parse(subLine, GetTopElementIndex(subLine, 1, true), lines, ref lineNo, depth + 1);
break;
}
case ParenthesesOperator parOp:
Expand All @@ -248,7 +332,7 @@ public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, i
break;
case VariableToken vt: {
if (i + 1 < line.Length)
switch (line[i+1]) {
switch (line[i + 1]) {
case ParenthesesOperator:
vt.Args = Parse(line, i + 1, lines, ref lineNo, depth + 1);
break;
Expand All @@ -267,31 +351,31 @@ public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, i
addition = 2;
fs.Name = line[i + 1].Str;
}

Token left = Parse(line, i + addition, lines, ref lineNo, depth + 1);
if (left is not ParenthesesOperator po)
throw new FormatException("statement condition/parameter declaration on line " + left.Line + " is missing parentheses");

statement.Left = po;

int numBrackets = 0;
int j = i+1;
int j = i + 1;
do {
if (Program.ClosingBrackets.Contains(line[j].Str))
numBrackets--;
else if (Program.OpeningBrackets.Contains(line[j].Str))
numBrackets++;

j++;
} while (numBrackets != 0);

statement.Right = CurlyBracketsParse(line, lines, ref lineNo, statement, depth + 1);
break;
}
case ElseStatement or ClassStatement: {
if (t is ClassStatement classStat)
classStat.Name = line[i + 1].Str;

Token child = CurlyBracketsParse(line, lines, ref lineNo, t, depth + 1);
if (child is not MultilineStatementOperator mso)
throw new FormatException("statement argument on line " + child.Line + " needs curly brackets");
Expand All @@ -307,12 +391,22 @@ public static Token Parse(Token[] line, int i, string[] lines, ref int lineNo, i
unStat.Child = po;
break;
}
case MultilineStatementOperator mso: { // TODO: fix parsing of nested dictionaries
if (mso.Str == "}")
break;

// If for some reason the Token[] is changed within mso and an element is replaced by a type
// which is not a subclass or superclass of DictionaryAssignmentOperator, the program will error, but that should never happen
mso.Children = SimpleObjectParse(line, lines, ref lineNo, i, depth + 1);
mso.IsDictionary = true;
break;
}
}

t.Line = line[i].Line;

line[i].IsDone = true;

return t;
}
}
15 changes: 15 additions & 0 deletions Tokens/Operators/Binary/DictionaryAssignmentOperator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using TrieDictionary;
using Interpreter.Types.Util;
using String = Interpreter.Types.Comparable.String;
using Object = Interpreter.Types.Object;

namespace Interpreter.Tokens.Operators.Binary;

public class DictionaryAssignmentOperator : BinaryOperator {
public DictionaryAssignmentOperator() {
Symbol = ":";
}

public override Object Evaluate(List<TrieDictionary<Object>> vars) => new DictionaryEntry((String) Left.Evaluate(vars), Right.Evaluate(vars));
}

3 changes: 2 additions & 1 deletion Tokens/Operators/Binary/DotOperator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Interpreter.Types.Comparable;
using Interpreter.Types.Function;
using Interpreter.Types.Util;
using Interpreter.Types;
using TrieDictionary;
using Array = Interpreter.Types.Array;
using Object = Interpreter.Types.Object;
Expand All @@ -14,7 +15,7 @@ public DotOperator() {

public override Object Evaluate(List<TrieDictionary<Object>> vars) {
Object leftObj = Left.Evaluate(vars);
Object res = leftObj.Properties[Right.Str];
Object res = leftObj.Properties.Contains(Right.Str) ? leftObj.Properties[Right.Str] : new Null();

VariableToken properRight = (VariableToken) Right;
if (res is Function f) {
Expand Down
Loading

0 comments on commit c16bb89

Please sign in to comment.