public ExitFlag Interpret(bool debug = false) { List <Token> tokens = Tokenize(); if (debug) { PrintTokens(tokens); } globalScope = new GlobalScope(); ExitFlag f; try { f = Execute(tokens, globalScope, debug, true); } catch (FatalErrorException e) { Functions.WriteLineColor(e.Message, ConsoleColor.Red); Functions.WriteLineColor(e.StackTrace, ConsoleColor.DarkYellow); f = ExitFlag.FatalError; } return(f); }
public void Should_return_entire_bound_scope_name_as_path_to_root_scope() { var fakeNode = A.Fake <INode <AstNode> >(); var fakeScope = A.Fake <INamedScope <SymbolNode> >(); A.CallTo(() => fakeScope.Name).Returns("FakeScope"); var globalScope = new GlobalScope <SymbolNode>(); A.CallTo(() => fakeScope.OuterScope).Returns(globalScope); var boundScope = new BoundScope <SymbolNode>(fakeScope, fakeNode); boundScope.Name.ShouldBe("global/FakeScope"); }
public override BoundNode VisitScope(BoundScope node) { Debug.Assert(!node.Locals.IsEmpty); var newLocals = ArrayBuilder <LocalSymbol> .GetInstance(); var hoistedLocalsWithDebugScopes = ArrayBuilder <StateMachineFieldSymbol> .GetInstance(); foreach (var local in node.Locals) { Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.UserDefined && local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchSection); if (!NeedsProxy(local)) { newLocals.Add(local); continue; } hoistedLocalsWithDebugScopes.Add(((CapturedToStateMachineFieldReplacement)proxies[local]).HoistedField); } var statements = VisitList(node.Statements); // wrap the node in an iterator scope for debugging if (hoistedLocalsWithDebugScopes.Count != 0) { BoundStatement translated; if (newLocals.Count == 0) { newLocals.Free(); translated = new BoundStatementList(node.Syntax, statements); } else { translated = node.Update(newLocals.ToImmutableAndFree(), statements); } return(MakeStateMachineScope(hoistedLocalsWithDebugScopes.ToImmutable(), translated)); } else { hoistedLocalsWithDebugScopes.Free(); newLocals.Free(); return(node.Update(node.Locals, statements)); } }
public override BoundNode VisitScope(BoundScope node) { Debug.Assert(!node.Locals.IsEmpty); var newLocalsBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); var hoistedLocalsWithDebugScopes = ArrayBuilder <StateMachineFieldSymbol> .GetInstance(); bool localsRewritten = false; foreach (var local in node.Locals) { // BoundScope is only used for switch Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.UserDefined && (local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchSection || local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchExpressionArm)); LocalSymbol localToUse; if (TryRewriteLocal(local, out localToUse)) { newLocalsBuilder.Add(localToUse); localsRewritten |= ((object)local != localToUse); continue; } hoistedLocalsWithDebugScopes.Add(((CapturedToStateMachineFieldReplacement)proxies[local]).HoistedField); } var statements = VisitList(node.Statements); // wrap the node in an iterator scope for debugging if (hoistedLocalsWithDebugScopes.Count != 0) { BoundStatement translated; if (newLocalsBuilder.Count == 0) { newLocalsBuilder.Free(); translated = new BoundStatementList(node.Syntax, statements); } else { translated = node.Update(newLocalsBuilder.ToImmutableAndFree(), statements); } return(MakeStateMachineScope(hoistedLocalsWithDebugScopes.ToImmutable(), translated)); } else { hoistedLocalsWithDebugScopes.Free(); ImmutableArray <LocalSymbol> newLocals; if (localsRewritten) { newLocals = newLocalsBuilder.ToImmutableAndFree(); } else { newLocalsBuilder.Free(); newLocals = node.Locals; } return(node.Update(newLocals, statements)); } }
protected virtual void ProcessAdd(IList newItems, int newStartingIndex) { var niCopy = (from a in newItems.Cast <Object>() select a).ToList(); foreach (T ni in niCopy) { _contains[ni] = true; } if (!EnableIntegration) { return; } if (BoundScope != null) { // First, we inspect to see if we have a wrapped object or not - if not, we try to do so and REPLACE the current item if (!BoundScope.Settings.EntitySetUsesUnwrapped) { var idx2 = 0; foreach (var ni in niCopy.ToArray()) { if (ni != null) { if (BoundScope.InternalCreateAddBase(ni, true, null, null, null, new Dictionary <object, object>(Globals.DefaultDictionaryCapacity), true, false) is ICEFWrapper w) { var cast = w as T; if (ni != cast) { try { this.SuspendNotifications(true); using (new WriterLock(_lock)) { this.Replace(ni as T, cast); _contains.Add(cast, true); _contains.Remove(newItems[idx2] as T); } } finally { this.SuspendNotifications(false); } } niCopy[idx2] = cast; } } idx2++; } } } if (ParentContainer != null && EnableLinking) { foreach (var ni in niCopy) { if (ni != null) { // Attempt to establish a FK relationship, carry parent key down CEF.CurrentKeyService()?.LinkChildInParentContainer(BoundScope, ParentTypeName, ParentFieldName, ParentContainer, ni); } } } }
public override abstract BoundNode VisitScope(BoundScope node);
public abstract override BoundNode VisitScope(BoundScope node);
private DataType EvaluateExpression(List <Token> expression, BoundScope localScope, out object result) { if (expression == null) { result = 0; return(DataType.Undefined); } if (expression.Count > 2) { // Strip away wrapping separators while (expression.Count(e => e.Type == TokenType.Parenthesis) >= 2 && expression[0].Type == TokenType.Parenthesis && (char)expression[0].Value == '(' && expression[expression.Count - 1].Type == TokenType.Parenthesis && (char)expression[expression.Count - 1].Value == ')') { // If the expression is wrapped with two parentathes, remove them (it's the same thing). This will otherwise cause a weird bug expression.RemoveAt(0); expression.RemoveAt(expression.Count - 1); } // Replace any text-code with mathematical symbols for (int i = 0; i < expression.Count; i++) { switch (expression[i].Type) { case TokenType.Is: if (i + 1 < expression.Count && expression[i + 1].Type == TokenType.Equal) { expression.RemoveAt(i); i--; } break; } } } else if (expression.Count == 2) { if (expression[0].Type == TokenType.Operator && (char)expression[0].Value == '-' && expression[1].Type == TokenType.Expression && expression[1].ValueType == typeof(double)) { result = (double)expression[1].Value * -1; return(DataType.Number); } } if (expression.Count == 1) { Token e = expression[0]; // Check for literals and therefore variables and functions if (e.Type == TokenType.Literal) { if (localScope.TryLookup(e.Name, out Variable v)) { result = v.Value; return(v.Type); } else { Error.Undefined(e, "variable"); result = 0; return(DataType.Undefined); } } else if (e.Type == TokenType.String) { result = e.Value; return(DataType.String); } else { result = e.Value; } switch (e.Value) { case string v: return(DataType.String); case int v1: case long v2: case float v3: case double v4: return(DataType.Number); case bool v: return(DataType.Boolean); default: return(DataType.Undefined); } } result = 0; List <Token> newExpression; Token expressionValue = Token.Empty; for (int i = 0; i < orderOfOperations.Length; i++) { if (expression.Count == 1) { break; } string operation = orderOfOperations[i]; for (int j = 0; j < expression.Count; j++) { Token t = expression[j]; if ((t.Type == TokenType.Expression || t.Type == TokenType.Operator || t.Type == TokenType.Equal || t.Type == TokenType.Or || t.Type == TokenType.And) && t.Value.ToString().Equals(operation)) { if (!(j > 0 && j < expression.Count)) { Error.UnexpectedToken(t, "expressions on both sides of the operator"); return(DataType.Undefined); } int k = 1; int expressionStart = -1; int expressionEnd = -1; int parenthisesDepth = 0; // Get LHS List <Token> LHS = new List <Token>(); Token temp_t = Token.Empty; while (j - k >= 0 && (temp_t.Type == TokenType.Expression || temp_t.Type == TokenType.Operator || temp_t.Type == TokenType.Parenthesis || temp_t.Type == TokenType.Undefined)) { temp_t = expression[j - k]; if (isOperator(temp_t.Value.ToString()) && parenthisesDepth == 0) { k--; break; } else if (temp_t.Type == TokenType.Parenthesis && (char)temp_t.Value == '(') { parenthisesDepth++; if (parenthisesDepth == 0) { k++; continue; } // Do not add token } else if (temp_t.Type == TokenType.Parenthesis && (char)temp_t.Value == ')') { parenthisesDepth--; if (parenthisesDepth == 0 - 1) { k++; continue; } // Do not add token } LHS.Insert(0, temp_t); k++; } expressionStart = (j - k < 0) ? 0 : j - k; // Get RHS k = 1; parenthisesDepth = 0; List <Token> RHS = new List <Token>(); temp_t = Token.Empty; while (j + k < expression.Count && (temp_t.Type == TokenType.Expression || temp_t.Type == TokenType.Operator || temp_t.Type == TokenType.Parenthesis || temp_t.Type == TokenType.Literal || temp_t.Type == TokenType.Undefined)) { temp_t = expression[j + k]; if (isOperator(temp_t.Value.ToString()) && parenthisesDepth == 0) { k--; break; } else if (temp_t.Type == TokenType.Parenthesis && (char)temp_t.Value == '(') { parenthisesDepth++; } else if (temp_t.Type == TokenType.Parenthesis && (char)temp_t.Value == ')') { parenthisesDepth--; } RHS.Add(temp_t); k++; } expressionEnd = j + k; object LHS_Value; DataType LHS_TYPE = EvaluateExpression(LHS, localScope, out LHS_Value); object RHS_Value; DataType RHS_TYPE = EvaluateExpression(RHS, localScope, out RHS_Value); bool insureType(DataType value, DataType expected, string side, bool throwError) { if (value != expected) { if (throwError) { Error.WrongType(t, $"the {side} side of the operation sign was not evaluated to a {expected}"); } return(false); } return(true); } bool insureTypes(DataType left, DataType right) => insureType(LHS_TYPE, left, "left", true) && insureType(RHS_TYPE, right, "right", true); bool testTypes(DataType left, DataType right) => insureType(LHS_TYPE, left, "left", false) && insureType(RHS_TYPE, right, "right", false); switch (operation) { // Aritmetic expressions case "/": if (insureTypes(DataType.Number, DataType.Number)) { expressionValue = new Token("EXPR_DIV", TokenType.Expression, (double)LHS_Value / (double)RHS_Value, typeof(double), t.Line, t.Column); } else { return(DataType.Undefined); } break; case "*": if (insureTypes(DataType.Number, DataType.Number)) { expressionValue = new Token("EXPR_MUL", TokenType.Expression, (double)LHS_Value * (double)RHS_Value, typeof(double), t.Line, t.Column); } else { return(DataType.Undefined); } break; case "+": if (testTypes(DataType.Number, DataType.Number)) { expressionValue = new Token("EXPR_ADD_NUM", TokenType.Expression, (double)LHS_Value + (double)RHS_Value, typeof(double), t.Line, t.Column); } else { expressionValue = new Token("EXPR_ADD_STR", TokenType.Expression, LHS_Value.ToString() + RHS_Value.ToString(), typeof(string), t.Line, t.Column); } break; case "-": if (insureTypes(DataType.Number, DataType.Number)) { expressionValue = new Token("EXPR_SUB", TokenType.Expression, (double)LHS_Value - (double)RHS_Value, typeof(double), t.Line, t.Column); } else { return(DataType.Undefined); } break; case "^": if (insureTypes(DataType.Number, DataType.Number)) { expressionValue = new Token("EXPR_POW", TokenType.Expression, Math.Pow((double)LHS_Value, (double)RHS_Value), typeof(double), t.Line, t.Column); } else { return(DataType.Undefined); } break; case "&": if (insureTypes(DataType.Number, DataType.Number)) { expressionValue = new Token("EXPR_BIT_AND", TokenType.Expression, (long)LHS_Value & (long)RHS_Value, typeof(long), t.Line, t.Column); } else { return(DataType.Undefined); } break; // Boolean expressions case "=": expressionValue = new Token("EXPR_EQ", TokenType.Boolean, LHS_Value.Equals(RHS_Value), typeof(bool), t.Line, t.Column); break; case "==": expressionValue = new Token("EXPR_STRICT_EQ", TokenType.Boolean, insureType(RHS_TYPE, LHS_TYPE, "right", false) && LHS_Value.Equals(RHS_Value), typeof(bool), t.Line, t.Column); break; case "&&": if (insureTypes(DataType.Boolean, DataType.Boolean)) { expressionValue = new Token("EXPR_LOGIC_AND", TokenType.Expression, (bool)LHS_Value && (bool)RHS_Value, typeof(long), t.Line, t.Column); } else { return(DataType.Undefined); } break; case "||": if (insureTypes(DataType.Boolean, DataType.Boolean)) { expressionValue = new Token("EXPR_LOGIC_OR", TokenType.Expression, (bool)LHS_Value || (bool)RHS_Value, typeof(long), t.Line, t.Column); } else { return(DataType.Undefined); } break; default: Error.UnexpectedToken(new Token(operation, TokenType.Expression, t.Value, t.ValueType, t.Line, t.Column), "valid operation"); return(DataType.Undefined); } newExpression = new List <Token>(); for (int l = 0; l < expression.Count; l++) { if (l == expressionStart) { newExpression.Add(expressionValue); } else if (l > expressionStart && l <= expressionEnd) { continue; } else { newExpression.Add(expression[l]); } } expression = newExpression; } } } // Eval multiplication and division result = expressionValue.Value; switch (expressionValue.Value) { case string v: return(DataType.String); case int v1: case long v2: case float v3: case double v4: return(DataType.Number); case bool v: return(DataType.Boolean); default: return(DataType.Undefined); } }
private ExitFlag Execute(List <Token> tokens, BoundScope parentScope, bool debug, bool title) { BoundScope localScope = new BoundScope(parentScope); #region Local Functions int i = 0; Token nextToken(bool ignoreWhitespace = true) { if (i < tokens.Count) { Token t = tokens[i++]; if (t.Type == TokenType.Comment || (ignoreWhitespace && t.Type == TokenType.WhiteSpace)) { return(nextToken(ignoreWhitespace)); } else { return(t); } } return(null); } Token peekToken(int j = 0) // j is the offset { if (i < tokens.Count) { Token t = tokens[i + j]; if (t.Type == TokenType.Comment) { return(peekToken(++j)); } else { return(t); } } return(null); } List <Token> getExpression() { List <Token> expressions = new List <Token>(); Token t = nextToken(); while (t != null && (t.Type == TokenType.Expression || t.Type == TokenType.Operator || t.Type == TokenType.Boolean || t.Type == TokenType.Literal || t.Type == TokenType.String || t.Type == TokenType.Parenthesis)) { expressions.Add(t); t = nextToken(); } i--; if (expressions.Count == 0) { Error.UnexpectedToken(tokens[i], "Expression"); return(null); } return(expressions); } List <Token> getStatement() { List <Token> statement = new List <Token>(); Token t = nextToken(); while (t.Type == TokenType.Expression || t.Type == TokenType.Operator || t.Type == TokenType.Boolean || t.Type == TokenType.Literal || t.Type == TokenType.String || t.Type == TokenType.Parenthesis || t.Type == TokenType.Separator || t.Type == TokenType.Is || t.Type == TokenType.And || t.Type == TokenType.Or || t.Type == TokenType.Equal) { statement.Add(t); t = nextToken(); } i--; if (statement.Count == 0) { Error.UnexpectedToken(tokens[i], "påstående"); return(null); } return(statement); } Branch getBranch() { List <Token> block = new List <Token>(); int scope = 0; Token t = nextToken(); if (t.Type != TokenType.Then) { Error.UnexpectedToken(tokens[i], "start of code block"); return(null); } t = nextToken(); // Börja med nästa token innanför kodblocket while (t != null) { if (t.Type == TokenType.Done && scope == 0) { break; } else if (t.Type == TokenType.Then) { scope++; } else if (t.Type == TokenType.Done) { scope--; } if (t.Type != TokenType.WhiteSpace && (t.Type != TokenType.NewLine || (t.Type == TokenType.NewLine && block.Count > 0))) { block.Add(t); } t = nextToken(); } if (block.Count == 0) { Error.UnexpectedToken(tokens[i], "Non-empty code block"); return(null); } if (new[] { TokenType.WhiteSpace, TokenType.NewLine }.Contains(block.Last().Type)) { block.RemoveAt(block.Count - 1); } return(new Branch(block)); } #endregion if (debug) { Console.WriteLine(); if (title) { Functions.WriteTitle(ConsoleColor.Green, ConsoleColor.DarkGreen, "Execution Debugging"); Functions.WriteTableTitles(ConsoleColor.Green, ConsoleColor.DarkGreen, "Row:Col", "Action"); } } Token ct = Token.Empty; object result = null; DataType dataType = DataType.Undefined; while (ct != null) { ct = nextToken(); if (ct == null) { break; } else if (new[] { TokenType.WhiteSpace, TokenType.NewLine, TokenType.And }.Contains(ct.Type)) { continue; // Should and be skipped? } else if (ct.Type == TokenType.Literal) { // functionName param1 param2 = // ... // # or // variable = ... // variable == variable() Token literal = ct; List <Token> rawParameters = new List <Token>(); Token nxt = nextToken(); if (nxt != null) { while (!new[] { TokenType.Equal, TokenType.And, TokenType.NewLine }.Contains(nxt.Type)) { rawParameters.Add(nxt); nxt = nextToken(); if (nxt == null) { nxt = new Token("Newline", TokenType.NewLine, null, null, literal.Line, literal.Column); } } } switch (nxt.Type) { case TokenType.And: case TokenType.NewLine: // Function call: literal(...parameters) List <Token> statement = getStatement(); if (localScope.TryInvoke(literal, rawParameters, (Function f) => { if (debug) { Functions.WriteMessage(literal.Line, literal.Column, "Invokation", "Calling Function " + f); } Execute(f.Block, localScope, debug, false); }, debug) && debug) { Functions.WriteMessage(literal.Line, literal.Column, "Invokation", "Function was successfully invoked!"); } else { if (debug) { Error.Undefined(literal, $"could not find function "); } return(ExitFlag.FatalError); } break; case TokenType.Equal: // nxt is an equal sign. if (rawParameters.Count > 0) { // Function declaration } else { // A parameterless function or variable initialization. Variables can be invoked as parameterless functions to return its value, but this is unrecommended and is assumed by the compiler. List <Token> expression = getExpression(); dataType = EvaluateExpression(expression, localScope, out result); if (dataType != DataType.Undefined) { Variable v = new Variable(literal.Name, result, dataType); if (parentScope.TryDeclare(v)) { if (debug) { Functions.WriteLineVariableMessage(ct.Line, ct.Column, "Variable Initialization", v, ConsoleColor.Cyan, ConsoleColor.Yellow); } } else { if (parentScope.TryReassign(v)) { if (debug) { Functions.WriteLineVariableMessage(ct.Line, ct.Column, "Variable Re-assignment", v, ConsoleColor.Cyan, ConsoleColor.Yellow); } } else { Error.FailedToDeclare(literal); return(ExitFlag.SyntaxError); } } } else { Error.UnexpectedToken(literal, "definable value"); return(ExitFlag.SyntaxError); } } break; } } else if (ct.Type == TokenType.If) { List <Token> statement = getStatement(); Branch branch = getBranch(); dataType = EvaluateExpression(statement, localScope, out result); if (dataType != DataType.Undefined) { if ((dataType == DataType.Number && (double)result != 0) || (dataType == DataType.String) || (dataType == DataType.Boolean && (bool)result)) { if (debug) { Functions.WriteMessage(ct.Line, ct.Column, "Branching", $"Entering {branch}. '" + Functions.TokenListToString(statement) + "' was true.", ConsoleColor.Yellow); } Execute(branch.Block, localScope, debug, false); } else if (debug) { Functions.WriteMessage(ct.Line, ct.Column, "Branching", $"Skipping {branch}. '" + Functions.TokenListToString(statement) + "' was false.", ConsoleColor.Yellow); } } else { Error.WithExpected("Invalid statement: " + Functions.TokenListToString(statement), "calculable truth value"); return(ExitFlag.SyntaxError); } } else { Error.UnexpectedToken(ct, "instruction with context"); return(ExitFlag.SyntaxError); } } return(ExitFlag.Successfull); }