public bool FindErrorRecoveryState() { // pop states until one found that accepts error token while (true) { // shift int action; if (_currentState.Actions != null && _currentState.Actions.TryGetValue(_errorToken, out action) && action > 0) { return true; } // LogState("Error, popping state", _stateStack.Peek(1)); _stack.Pop(); if (_stack.IsEmpty) { // Log("Aborting: didn't find a state that accepts error token"); return false; } else { _currentState = _stack.PeekState(1); } } }
private void Shift(int stateId) { _currentState = _states[stateId]; _stack.Push(_currentState, GetTokenValue(), GetTokenSpan()); if (_recovering) { if (_nextToken != _errorToken) { _tokensSinceLastError++; } if (_tokensSinceLastError > 5) { _recovering = false; } } if (_nextToken != _eofToken) { _nextToken = 0; } }
private void Reduce(int ruleId) { int ruleDef = _rules[ruleId]; int rhsLength = GetRuleRhsLength(ruleDef); LogBeforeReduction(ruleId, rhsLength); if (rhsLength == 0) { // The location span for an empty production will start with the // beginning of the next lexeme, and end with the finish of the // previous lexeme. This gives the correct behaviour when this // nonsense value is used in later Merge operations. yyloc = MergeLocations(_lastTokenSpan, GetTokenSpan()); } else if (rhsLength == 1) { yyloc = _stack.PeekLocation(1); } else { TLocation at1 = GetLocation(rhsLength); TLocation atN = GetLocation(1); yyloc = MergeLocations(at1, atN); } DoAction(ruleId); _stack.Pop(rhsLength); var currentState = _stack.PeekState(1); int gotoState; if (currentState.GotoStates.TryGetValue(GetRuleLhsNonterminal(ruleDef), out gotoState)) { LogBeforeGoto(gotoState, ruleId); currentState = _states[gotoState]; } _stack.Push(currentState, yyval, yyloc); _currentState = currentState; }
private bool Parse() { _nextToken = 0; _currentState = _states[0]; _lastTokenSpan = GetTokenSpan(); _stack.Push(_currentState, yyval, yyloc); while (true) { LogStateEntered(); int action = _currentState.DefaultAction; if (_currentState.Actions != null) { if (_nextToken == 0) { // We save the last token span, so that the location span // of production right hand sides that begin or end with a // nullable production will be correct. _lastTokenSpan = GetTokenSpan(); _nextToken = GetNextToken(); } LogNextToken(_nextToken); _currentState.Actions.TryGetValue(_nextToken, out action); } if (action > 0) { LogBeforeShift(action, _nextToken, false); Shift(action); } else if (action < 0) { Reduce(-action - 1); // accept if (action == -1) { return true; } } else if (action == 0) { // error if (!ErrorRecovery()) { return false; } } } }
// TODO: possible optimization: build a single dictionary mapping all goto and actions for all states. // This (custom) dict might be precomputed by generator and allocated in a single array. // This would safe rellocation of ~650kB of Dictionary.Entry[] since the array would be considered a large object. private State[]/*!*/ BuildStates(short[]/*!*/ data) { Debug.Assert(data != null && data.Length > 0); // // serialized structure: // // length, // ( // (action_count: positive short, goto_count: positive short) | (action_count: negative short), // (key: short, value: short){action_count} | (defaultAction: short), // (key: short, value: short){goto_count} // ){length} // // where action_count is // > 0 ... a number of items in actions hashtable // == 0 ... there is no action hashtable, but there is a single integer default action id // < 0 ... there is no action hashtable and no goto table, the value is default action id // goto_count is a number of items in gotos hashtable, // zero means there is no goto hashtable // int offset = 0; State[] states = new State[data[offset++]]; for (int i = 0; i < states.Length; i++) { int actionCount = data[offset++]; Dictionary<int, int> actions = null; Dictionary<int, int> gotos = null; int defaultAction = 0; if (actionCount >= 0) { int gotoCount = data[offset++]; Debug.Assert(gotoCount >= 0); if (actionCount > 0) { actions = new Dictionary<int, int>(actionCount); for (int j = 0; j < actionCount; j++) { actions.Add(data[offset++], data[offset++]); } } else { defaultAction = data[offset++]; } if (gotoCount > 0) { gotos = new Dictionary<int, int>(gotoCount); for (int j = 0; j < gotoCount; j++) { Debug.Assert(data[offset] < 0); gotos.Add(-data[offset++], data[offset++]); } } } else { defaultAction = actionCount; } states[i] = new State(actions, gotos, defaultAction); #if DEBUG states[i].Id = i; #endif } return states; }
internal void InitializeMembersFrom(RubyModule/*!*/ module) { ContractUtils.RequiresNotNull(module, "module"); #if !SILVERLIGHT // missing Clone on Delegate if (module.DeclaresGlobalConstants || module._clrConstants != null && _constants == null) { #endif EnsureInitialized(); module.EnsureInitialized(); #if !SILVERLIGHT } else { _state = module._state; _initializer = (module._initializer != null) ? (Action<RubyModule>)module._initializer.Clone() : null; } #endif if (module.DeclaresGlobalConstants) { Debug.Assert(module._constants == null && module._clrConstants == null); Debug.Assert(_constants != null); _constants.Clear(); foreach (KeyValuePair<SymbolId, object> constant in _context.TopGlobalScope.Items) { _constants.Add(SymbolTable.IdToString(constant.Key), constant.Value); } } else { _constants = (module._constants != null) ? new Dictionary<string, object>(module._constants) : null; // copy namespace members: if (module._clrConstants != null) { Debug.Assert(_constants != null); foreach (KeyValuePair<SymbolId, object> constant in module._clrConstants.SymbolAttributes) { _constants.Add(SymbolTable.IdToString(constant.Key), constant.Value); } } } _methods = (module._methods != null) ? new Dictionary<string, RubyMemberInfo>(module._methods) : null; _classVariables = (module._classVariables != null) ? new Dictionary<string, object>(module._classVariables) : null; _mixins = ArrayUtils.Copy(module._mixins); // dependentModules - skip // tracker - skip, .NET members not copied Updated("InitializeFrom"); }
private void InitializeMembers() { Debug.Assert(_state == State.Uninitialized); Debug.Assert(_constants == null && _methods == null, "Tables are null until initialized"); Debug.Assert(_context.ObjectClass != null, "ObjectClass should already be initialized"); if (DeclaresGlobalConstants) { _constants = null; } else { _constants = new Dictionary<string, object>(); } _methods = new Dictionary<string, RubyMemberInfo>(); Utils.Log(_name ?? "<anonymous>", "INITED"); _state = State.Initializing; try { if (_initializer != null) { _initializer(this); } } finally { _initializer = null; _state = State.Initialized; } }
internal RubyModule(RubyContext/*!*/ context, string name, Action<RubyModule> initializer, IAttributesCollection clrConstants, TypeTracker tracker) { Assert.NotNull(context); _context = context; _name = name; _state = State.Uninitialized; _mixins = EmptyArray; _initializer = initializer; _version = Interlocked.Increment(ref _globalVersion); _clrConstants = clrConstants; _tracker = tracker; }