//todo nullability // type checking // language consts (WORLD,SELF,SCRIPT) // scope /// <summary> /// Parses a variable declaration /// </summary> /// <param name="at">position to start parsing in the ast</param> /// <returns>Declaration node</returns> private bool ParseVarDeclaration(ref int at) { DeclarationNode dNode = new DeclarationNode(); //at 0 is always Signature.TYPENAME dNode.Variable.ValueNodeType = ValueNodeType.VARIABLE; string declTypeName = Ast[at].Word; at++; if (Ast[at].Signature != Signature.IDENTIFIER) { return(false); } //Search tree for existing declaration var varDecl = SeekVariableDeclarationWithName(Ast[at].Word, true); if (varDecl != null) { _logger.LogFatal("Redeclaration of variable"); return(false); } dNode.Variable.VarName = Ast[at].Word; at++; if (Ast[at].Signature != Signature.OP_ASSIGN) { //not assignation case; _logger.LogFatal("Variable declaration without assignation"); return(false); } //Right side value at++; switch (Ast[at].Signature) { case Signature.IDENTIFIER: //Search tree for existing declaration var r_varDecl = SeekVariableDeclarationWithName(Ast[at].Word); if (r_varDecl == null) { _logger.LogFatal("No declaration of right side identifier"); goto default; } string varName = dNode.Variable.VarName; dNode.Variable = r_varDecl.Variable; dNode.Variable.VarName = varName; break; case Signature.I_CONST: case Signature.F_CONST: case Signature.STRINGLITTERAL: dNode.Variable.ValueNodeType = ValueNodeType.CONSTLITERAL; dNode.Variable.IsNull = false; bool badTypeflag = false; if (Ast[at].Signature == Signature.I_CONST) { if (int.TryParse(Ast[at].Word, out int intValue) && declTypeName == "int") { dNode.Variable.Value = intValue; dNode.Variable.ValueType = TypesEnum.INT; } else { badTypeflag = true; } } else if (Ast[at].Signature == Signature.F_CONST) { if (float.TryParse(Ast[at].Word, out float floatValue) && declTypeName == "float") { dNode.Variable.Value = floatValue; dNode.Variable.ValueType = TypesEnum.FLOAT; } else { badTypeflag = true; } } else /*STRINGLITTERAL*/ { { dNode.Variable.Value = Ast[at].Word; dNode.Variable.ValueType = TypesEnum.STRING; } } if (badTypeflag) { _logger.LogFatal("Mismatched type"); } break; case Signature.KW_TRUE: case Signature.KW_FALSE: dNode.Variable.ValueNodeType = ValueNodeType.CONSTLITERAL; dNode.Variable.IsNull = false; dNode.Variable.ValueType = TypesEnum.BOOL; if (Ast[at].Signature == Signature.KW_TRUE) { dNode.Variable.Value = true; } else if (Ast[at].Signature == Signature.KW_FALSE) { dNode.Variable.Value = false; } break; case Signature.CONST_SELF: case Signature.CONST_WORLD: case Signature.CONST_SCRIPT: //Todo verify that the accessed const returns the valid type dNode.Variable.ValueNodeType = ValueNodeType.VARIABLE; dNode.Variable.IsNull = true; break; case Signature.KW_NULL: dNode.Variable.ValueNodeType = ValueNodeType.CONSTLITERAL; dNode.Variable.IsNull = true; dNode.Variable.ValueType = TypesEnum.VOID; dNode.Variable.Value = null; break; default: return(false); } at++; if (Ast[at].Signature != Signature.END) { return(false); } Tree.Current.AddChild(dNode); //TODO not best way of doing that Tree.VariableStack.Add(dNode); //TODO check that we return a valid position in the AST return(true); }
private void ExtractTokens() { if (string.IsNullOrEmpty(Script)) { Logger.LogFatal("Invalid Script file"); return; } if (!AreOpenCloseStatementsPaired()) { return; } for (int i = 0; i < Script.Length; i++) { switch (Script[i]) { case ' ': case '\r': case '\n': case '\t': break; case '(': Tokens.Add(new Token() { Signature = Signature.LPAREN }); break; case ')': Tokens.Add(new Token() { Signature = Signature.RPAREN }); break; case '{': Tokens.Add(new Token() { Signature = Signature.LBRACE }); break; case '}': Tokens.Add(new Token() { Signature = Signature.RBRACE }); break; case '[': Tokens.Add(new Token() { Signature = Signature.LBRACKET }); break; case ']': Tokens.Add(new Token() { Signature = Signature.RBRACKET }); break; case ',': Tokens.Add(new Token() { Signature = Signature.COMMA }); break; case '#': Tokens.Add(new Token() { Signature = Signature.PREPROCESSOR }); break; case ';': Tokens.Add(new Token() { Signature = Signature.END }); break; case '.': Tokens.Add(new Token() { Signature = Signature.OP_DOT }); break; case '>': if (Script[i + 1] == '=') { Tokens.Add(new Token() { Signature = Signature.OP_GREATER_THAN_OR_EQUALS }); i += 2; } else { Tokens.Add(new Token() { Signature = Signature.OP_GREATER_THAN }); } break; case '<': if (IsNextIndexValid(i)) { if (Script[i + 1] == '=') { Tokens.Add(new Token() { Signature = Signature.OP_LESS_THAN_OR_EQUALS }); i += 2; } else { Tokens.Add(new Token() { Signature = Signature.OP_LESS_THAN }); } } break; case '/': if (IsNextIndexValid(i)) { switch (Script[i + 1]) { case '=': Tokens.Add(new Token() { Signature = Signature.OP_DIVIDE_ASSIGN }); i += 1; break; default: Tokens.Add(new Token() { Signature = Signature.OP_DIVIDE }); break; } } break; case '*': if (IsNextIndexValid(i)) { switch (Script[i + 1]) { case '=': Tokens.Add(new Token() { Signature = Signature.OP_MUL_ASSIGN }); i += 1; break; default: Tokens.Add(new Token() { Signature = Signature.OP_MUL }); break; } } break; case '+': if (IsNextIndexValid(i)) { switch (Script[i + 1]) { case '+': Tokens.Add(new Token() { Signature = Signature.OP_INCREMENT }); i += 1; break; case '=': Tokens.Add(new Token() { Signature = Signature.OP_PLUS_ASSIGN }); i += 1; break; default: Tokens.Add(new Token() { Signature = Signature.OP_PLUS }); break; } } break; case '-': if (IsNextIndexValid(i)) { switch (Script[i + 1]) { case '-': Tokens.Add(new Token() { Signature = Signature.OP_DECREMENT }); i += 1; break; case '=': Tokens.Add(new Token() { Signature = Signature.OP_MINUS_ASSIGN }); i += 1; break; default: Tokens.Add(new Token() { Signature = Signature.OP_MINUS }); break; } } break; case '=': if (IsNextIndexValid(i)) { if (Script[i + 1] == '=') { Tokens.Add(new Token() { Signature = Signature.OP_EQUALS }); i += 1; if (IsNextIndexValid(i)) { if (char.IsWhiteSpace(Script[i + 1])) { i += 1; } } break; } else { Tokens.Add(new Token() { Signature = Signature.OP_ASSIGN }); } } break; case '!': if (IsNextIndexValid(i)) { if (Script[i + 1] == '=') { Tokens.Add(new Token() { Signature = Signature.OP_NOTEQUALS }); i += 1; break; } else { Tokens.Add(new Token() { Signature = Signature.OP_NOT }); } } break; case '&': if (IsNextIndexValid(i)) { if (Script[i + 1] == '&') { Tokens.Add(new Token() { Signature = Signature.OP_AND }); Console.WriteLine("returns at: " + (i + 2) + " char: " + Script[i + 2]); i += 1; break; } else { Logger.LogFatal("Invalid symbol"); return; } } break; case '|': if (IsNextIndexValid(i)) { if (Script[i + 1] == '|') { Tokens.Add(new Token() { Signature = Signature.OP_OR }); i += 1; break; } else { Logger.LogFatal("Invalid symbol"); return; } } break; case '"': var word = new StringBuilder(); for (int j = i + 1; j < Script.Length; j++) { if (Script[j] == '"') { i = j; break; } else { word.Append(Script[j]); } } Tokens.Add(new Token() { Word = word.ToString(), Signature = Signature.STRINGLITTERAL }); break; default: if (char.IsDigit(Script[i])) { int numberScanResult = ScanNumber(i); if (numberScanResult >= Script.Length || numberScanResult == -1) { return; } else { i = numberScanResult; } } else if (char.IsLetter(Script[i])) { int identifierScanResult = ScanIdentifier(i); if (identifierScanResult >= Script.Length) { return; } else { i = identifierScanResult; } } else { Logger.LogFatal("Illegal char: " + Script[i]); return; } break; } } }