public SwitchStatementUnsafeBlotchy(SwitchStatement switchStatement, bool useExplicitMax, int explicitMax, Executable owner) : base(switchStatement.FirstToken, owner) { this.OriginalSwitchStatement = switchStatement; this.Condition = switchStatement.Condition; this.UsesStrings = switchStatement.UsesStrings; this.UseExplicitMax = useExplicitMax; this.ExplicitMax = explicitMax; if (this.UsesStrings) { this.StringUnsafeToSafeMapping = new Dictionary<string, int>(); } else { this.IntegerUnsafeToSafeMapping = new Dictionary<int, int>(); } this.codeMapping = new Dictionary<int, Executable[]>(); this.tokenMapping = new Dictionary<int, Token>(); this.max = switchStatement.Chunks.Length - 1; for (int i = 0; i < switchStatement.Chunks.Length; ++i) { SwitchStatement.Chunk chunk = switchStatement.Chunks[i]; this.codeMapping[i] = chunk.Code; this.tokenMapping[i] = chunk.CaseOrDefaultToken; foreach (Expression expression in chunk.Cases) { if (expression == null) { this.DefaultCaseId = i; } else { IntegerConstant ic = expression as IntegerConstant; StringConstant sc = expression as StringConstant; if (ic == null && sc == null) throw new Exception("This shouldn't happen."); if (ic != null) { int c = ic.Value; this.IntegerUnsafeToSafeMapping[c] = i; } else { string s = sc.Value; this.StringUnsafeToSafeMapping[s] = i; } } } } if (useExplicitMax) { if (this.UsesStrings) throw new Exception("Cannot use explicit max on string switch statements."); } }
public SwitchStatementContinuousSafe(SwitchStatement switchStatement, Executable owner) : base(switchStatement.FirstToken, owner) { this.OriginalSwitchStatement = switchStatement; this.Condition = switchStatement.Condition; this.codeByCondition = new Dictionary<int, Executable[]>(); foreach (SwitchStatement.Chunk chunk in switchStatement.Chunks) { this.codeByCondition.Add(((IntegerConstant)chunk.Cases[0]).Value, chunk.Code); } }
protected override void TranslateSwitchStatement(List<string> output, SwitchStatement switchStatement) { output.Add(this.CurrentTabIndention); output.Add(this.Shorten("switch (")); this.TranslateExpression(output, switchStatement.Condition); output.Add(this.Shorten(") {") + this.NL); this.CurrentIndention++; foreach (SwitchStatement.Chunk chunk in switchStatement.Chunks) { foreach (Expression caseExpr in chunk.Cases) { output.Add(this.CurrentTabIndention); if (caseExpr == null) { output.Add("default:" + this.NL); } else { output.Add("case "); TranslateExpression(output, caseExpr); output.Add(":" + this.NL); } this.CurrentIndention++; Translate(output, chunk.Code); this.CurrentIndention--; } } this.CurrentIndention--; output.Add(this.CurrentTabIndention); output.Add("}" + this.NL); }
private void TranslateSwitchStatementAsElifChain(List<string> output, SwitchStatement switchStatement, int switchId) { output.Add(this.CurrentTabIndention); output.Add("switch_loopy_" + switchId + " = 1\r\n"); output.Add(this.CurrentTabIndention); output.Add("while switch_loopy_" + switchId + " == 1:\r\n"); this.CurrentIndention++; output.Add(this.CurrentTabIndention); output.Add("switch_loopy_" + switchId + " = 0\r\n"); Expression firstCase = switchStatement.Chunks[0].Cases[0]; if (firstCase == null) { // WAT throw new Exception("This should have been optimized out."); } else if (firstCase is IntegerConstant) { // TODO: do this for real // There are several optimziations that can be done. // if it's a small switch, just use if/elif/else // if it's all positive and condensed and ordered, use a binary search with if/else // if they're sparse, are they super sparse? // if they're chunked not in order, normalize them with a static int-to-int array // if there are any weird breaks that aren't at the end, you need to put the whole thing in a one-time loop. e.g. "for ignored in (1,):" // now I feel sad. Here's a big-ass if/elif/else chain. string varName = "switch_expr_" + switchId; output.Add(this.CurrentTabIndention); output.Add(varName); output.Add(" = "); TranslateExpression(output, switchStatement.Condition); output.Add("\r\n"); /* * This is probably best * _switch_statement_lookup_27 = { * case_expr1: 1, * case_expr2a: 2, * case_expr2b: 2, * case_expr3: 3 * } * ... * _ignored_switch_loopy_thing_27 = 1 * while _ignored_switch_loopy_thing_27 == =1: * _ignored_switch_loopy_thing = 0 * _switch_expr_27 = _switch_statement_lookup_27.get(arbitrary_expression, 4) # 4 is the default case * if _switch_expr_27 < 3: * if _switch_expr_27 < 2: * code for case 1 * else: * code for case 2 * else: * if _switch_expr_27 < 4: * code for case 3 * else: * code for case 4 (default) * * This way you just leave the breaks as they are. * Don't try to use an array instead of a dictionary, though. Because that will cause the switch to crash if a crazy value is passed in. */ // This isn't even right. If a default is first, this will blow up. for (int i = 0; i < switchStatement.Chunks.Length; ++i) { SwitchStatement.Chunk chunk = switchStatement.Chunks[i]; bool conditionRequired = true; output.Add(this.CurrentTabIndention); if (i == 0) { output.Add("if "); } else if (chunk.Cases[chunk.Cases.Length - 1] == null) { output.Add("else:\r\n"); conditionRequired = false; } else { output.Add("elif "); } if (conditionRequired) { bool parens = chunk.Cases.Length > 1; if (parens) { output.Add("("); } for (int j = 0; j < chunk.Cases.Length; ++j) { if (j > 0) { output.Add(") or ("); } output.Add(varName); output.Add(" == "); TranslateExpression(output, chunk.Cases[j]); } if (parens) { output.Add(")"); } output.Add(":\r\n"); this.CurrentIndention++; Translate(output, chunk.Code); if (chunk.Code.Length == 0) { output.Add(this.CurrentTabIndention); output.Add("pass\r\n"); } this.CurrentIndention--; } else { this.CurrentIndention++; Translate(output, chunk.Code); if (chunk.Code.Length == 0) { output.Add(this.CurrentTabIndention); output.Add("pass\r\n"); } this.CurrentIndention--; } } } else if (firstCase is StringConstant) { throw new NotImplementedException("switch on string not implemented yet."); } else { throw new ParserException(firstCase.FirstToken, "Invalid value for a switch statement case."); } this.CurrentIndention--; }
private void TranslateSwitchStatementAsBinaryDecisions(List<string> output, SwitchStatement switchStatement, int switchId, bool doSafeMapping) { }
protected override void TranslateSwitchStatement(List<string> output, SwitchStatement switchStatement) { int switchId = this.GetNextInt(); if (switchStatement.UsesStrings) { throw new NotImplementedException("Create a string dictionary lookup"); } else if (switchStatement.IsSafe && switchStatement.IsContinuous) { this.TranslateSwitchStatementAsBinaryDecisions(output, switchStatement, switchId, false); } else { this.TranslateSwitchStatementAsElifChain(output, switchStatement, switchId); } }
public SwitchStatementUnsafeBlotchy(SwitchStatement switchStatement, bool useExplicitMax, int explicitMax, Executable owner) : base(switchStatement.FirstToken, owner) { this.OriginalSwitchStatement = switchStatement; this.Condition = switchStatement.Condition; this.UsesStrings = switchStatement.UsesStrings; this.UseExplicitMax = useExplicitMax; this.ExplicitMax = explicitMax; if (this.UsesStrings) { this.StringUnsafeToSafeMapping = new Dictionary <string, int>(); } else { this.IntegerUnsafeToSafeMapping = new Dictionary <int, int>(); } this.codeMapping = new Dictionary <int, Executable[]>(); this.tokenMapping = new Dictionary <int, Token>(); this.max = switchStatement.Chunks.Length - 1; for (int i = 0; i < switchStatement.Chunks.Length; ++i) { SwitchStatement.Chunk chunk = switchStatement.Chunks[i]; this.codeMapping[i] = chunk.Code; this.tokenMapping[i] = chunk.CaseOrDefaultToken; foreach (Expression expression in chunk.Cases) { if (expression == null) { this.DefaultCaseId = i; } else { IntegerConstant ic = expression as IntegerConstant; StringConstant sc = expression as StringConstant; if (ic == null && sc == null) { throw new Exception("This shouldn't happen."); } if (ic != null) { int c = ic.Value; this.IntegerUnsafeToSafeMapping[c] = i; } else { string s = sc.Value; this.StringUnsafeToSafeMapping[s] = i; } } } } if (useExplicitMax) { if (this.UsesStrings) { throw new Exception("Cannot use explicit max on string switch statements."); } } }
private void CompileSwitchStatement(Parser parser, ByteBuffer buffer, SwitchStatement switchStatement) { this.CompileExpression(parser, buffer, switchStatement.Condition, true); ByteBuffer chunkBuffer = new ByteBuffer(); Dictionary<int, int> chunkIdsToOffsets = new Dictionary<int, int>(); Dictionary<int, int> integersToChunkIds = new Dictionary<int,int>(); Dictionary<string, int> stringsToChunkIds = new Dictionary<string,int>(); int defaultChunkId = -1; foreach (SwitchStatement.Chunk chunk in switchStatement.Chunks) { int chunkId = chunk.ID; if (chunk.Cases.Length == 1 && chunk.Cases[0] == null) { defaultChunkId = chunkId; } else { foreach (Expression expression in chunk.Cases) { if (switchStatement.UsesIntegers) { integersToChunkIds[((IntegerConstant)expression).Value] = chunkId; } else { stringsToChunkIds[((StringConstant)expression).Value] = chunkId; } } } chunkIdsToOffsets[chunkId] = chunkBuffer.Size; this.Compile(parser, chunkBuffer, chunk.Code); } chunkBuffer.ResolveBreaks(); int switchId = parser.RegisterByteCodeSwitch(switchStatement.FirstToken, chunkIdsToOffsets, integersToChunkIds, stringsToChunkIds, switchStatement.UsesIntegers); int defaultOffsetLength = defaultChunkId == -1 ? chunkBuffer.Size : chunkIdsToOffsets[defaultChunkId]; buffer.Add(switchStatement.FirstToken, switchStatement.UsesIntegers ? OpCode.SWITCH_INT : OpCode.SWITCH_STRING, switchId, defaultOffsetLength); buffer.Concat(chunkBuffer); }
protected abstract void TranslateSwitchStatement(List<string> output, SwitchStatement switchStatement);