using System;
using Bridge;
using Bridge.Html5;
namespace WebMrbc
{
public class SwitchCaseNumberBlock : Block
{
public const string type_name = "switch_case_number";
internal Tuple[] cases_;
internal int defaultCount_;
public SwitchCaseNumberBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setHelpUrl("http://www.example.com/");
setColour(210);
appendValueInput("SWITCH")
.appendField("右の値が");
setPreviousStatement(true);
setNextStatement(true);
setMutator(new Mutator(new[] {
SwitchCaseNumberConstBlock.type_name,
SwitchCaseNumberRangeBlock.type_name,
SwitchCaseNumberDefaultBlock.type_name }));
setTooltip(new Func(() => {
if ((cases_.Length == 0) && (defaultCount_ == 0)) {
return "条件に合うブロックを実行";
}
else if ((cases_.Length == 0) && (defaultCount_ != 0)) {
return "条件に合うブロックを実行、合うものがなければ最後のブロックを実行";
}
else if ((cases_.Length != 0) && (defaultCount_ == 0)) {
return "条件に合うブロックを実行";
}
else if ((cases_.Length != 0) && (defaultCount_ != 0)) {
return "条件に合うブロックを実行、合うものがなければ最後のブロックを実行";
}
return "";
}));
cases_ = new Tuple[] { new Tuple("0", null) };
defaultCount_ = 0;
updateShape_();
}
///
/// Create XML to represent the number of else-if and else inputs.
///
/// XML storage element.
public Element mutationToDom(bool opt_caseIds)
{
if ((cases_.Length == 0) && (defaultCount_ == 0)) {
return null;
}
var container = Document.CreateElement("mutation");
for (var i = 0; i < cases_.Length; i++) {
Element caseInfo;
var value = getFieldValue("CONST" + i);
if (value != null) {
caseInfo = Document.CreateElement("case");
caseInfo.SetAttribute("value", value);
}
else {
var min = getFieldValue("RANGE_MIN" + i);
var max = getFieldValue("RANGE_MAX" + i);
if (min != null && max != null) {
caseInfo = Document.CreateElement("case");
caseInfo.SetAttribute("value", min + ".." + max);
}
else
continue;
}
container.AppendChild(caseInfo);
}
container.SetAttribute("default", defaultCount_.ToString());
return container;
}
///
/// Parse XML to restore the else-if and else inputs.
///
/// XML storage element.
public void domToMutation(Element xmlElement)
{
cases_ = new Tuple[0];
Element childNode;
for (var i = 0; (childNode = (dynamic)xmlElement.ChildNodes[i]) != null; i++) {
if (childNode.NodeName.ToLower() == "case") {
var value = childNode.GetAttribute("value");
if (value != null)
cases_.Push(new Tuple(value, null));
else {
var min = childNode.GetAttribute("minimum");
var max = childNode.GetAttribute("maximum");
if ((min != null) && (max != null)) {
cases_.Push(new Tuple(min, max));
}
}
}
}
var count = xmlElement.GetAttribute("default");
defaultCount_ = count == null ? 0 : Bridge.Script.ParseInt(count, 10);
updateShape_();
}
///
/// Populate the mutator's dialog with this block's components.
///
/// Mutator's workspace.
/// Root block in mutator.
public Block decompose(Workspace workspace)
{
var containerBlock = workspace.newBlock(SwitchCaseNumberContainerBlock.type_name);
containerBlock.initSvg();
var connection = containerBlock.getInput("STACK").connection;
for (var i = 0; i < cases_.Length; i++) {
Block caseBlock;
var value = getFieldValue("CONST" + i);
if (value != null) {
caseBlock = workspace.newBlock(SwitchCaseNumberConstBlock.type_name);
caseBlock.setFieldValue(value, "CONST");
}
else {
var min = getFieldValue("RANGE_MIN" + i);
var max = getFieldValue("RANGE_MAX" + i);
if ((min != null) && (max != null)) {
caseBlock = workspace.newBlock(SwitchCaseNumberRangeBlock.type_name);
caseBlock.setFieldValue(min, "RANGE_MIN");
caseBlock.setFieldValue(max, "RANGE_MAX");
}
else
continue;
}
caseBlock.initSvg();
connection.connect(caseBlock.previousConnection);
connection = caseBlock.nextConnection;
}
if (defaultCount_ != 0) {
var defaultBlock = workspace.newBlock(SwitchCaseNumberDefaultBlock.type_name);
defaultBlock.initSvg();
connection.connect(defaultBlock.previousConnection);
}
return containerBlock;
}
///
/// Reconfigure this block based on the mutator dialog's components.
///
/// Root block in mutator.
public void compose(Block containerBlock)
{
var clauseBlock = containerBlock.getInputTargetBlock("STACK");
// Count number of inputs.
cases_ = new Tuple[0];
defaultCount_ = 0;
var statementConnections = new Connection[0];
Connection defaultStatementConnection = null;
while (clauseBlock != null) {
switch (clauseBlock.type) {
case SwitchCaseNumberConstBlock.type_name: {
var value = clauseBlock.getFieldValue("CONST");
cases_.Push(new Tuple(value, null));
statementConnections.Push(((SwitchCaseNumberConstBlock)clauseBlock).statementConnection_);
}
break;
case SwitchCaseNumberRangeBlock.type_name: {
var range_min = clauseBlock.getFieldValue("RANGE_MIN");
var range_max = clauseBlock.getFieldValue("RANGE_MAX");
cases_.Push(new Tuple(range_min, range_max));
statementConnections.Push(((SwitchCaseNumberRangeBlock)clauseBlock).statementConnection_);
}
break;
case SwitchCaseNumberDefaultBlock.type_name: {
defaultCount_++;
defaultStatementConnection = ((SwitchCaseNumberDefaultBlock)clauseBlock).statementConnection_;
}
break;
default:
throw new Exception("Unknown block type.");
}
clauseBlock = (clauseBlock.nextConnection != null) ?
clauseBlock.nextConnection.targetBlock() : null;
}
updateShape_();
// Reconnect any child blocks.
for (var i = 0; i < cases_.Length; i++) {
Mutator.reconnect(statementConnections[i], this, "DO" + i);
}
Mutator.reconnect(defaultStatementConnection, this, "DEFAULT_DO");
}
///
/// Store pointers to any connected child blocks.
///
/// Root block in mutator.
public void saveConnections(Block containerBlock)
{
var clauseBlock = containerBlock.getInputTargetBlock("STACK");
var i = 0;
while (clauseBlock != null) {
switch (clauseBlock.type) {
case SwitchCaseNumberConstBlock.type_name: {
var inputDo = getInput("DO" + i);
((SwitchCaseNumberConstBlock)clauseBlock).statementConnection_ =
(inputDo != null) ? inputDo.connection.targetConnection : null;
i++;
}
break;
case SwitchCaseNumberRangeBlock.type_name: {
var inputDo = getInput("DO" + i);
((SwitchCaseNumberRangeBlock)clauseBlock).statementConnection_ =
(inputDo != null) ? inputDo.connection.targetConnection : null;
i++;
}
break;
case SwitchCaseNumberDefaultBlock.type_name: {
var inputDo = getInput("DEFAULT_DO");
((SwitchCaseNumberDefaultBlock)clauseBlock).statementConnection_ =
(inputDo != null) ? inputDo.connection.targetConnection : null;
}
break;
default:
throw new Exception("Unknown block type.");
}
clauseBlock = (clauseBlock.nextConnection != null) ?
clauseBlock.nextConnection.targetBlock() : null;
}
}
///
/// Modify this block to have the correct number of inputs.
///
private void updateShape_()
{
// Delete everything.
if (getInput("DEFAULT") != null) {
removeInput("DEFAULT");
removeInput("DEFAULT_DO");
}
var i = 0;
while (getInput("CASE" + i) != null) {
removeInput("CASE" + i);
removeInput("DO" + i);
i++;
}
// Rebuild block.
i = 0;
foreach (var c in cases_) {
if (c.Item2 == null) {
appendDummyInput("CASE" + i)
.appendField(new FieldNumber(c.Item1, "-Infinity", "Infinity", 0), "CONST" + i)
.appendField("の");
}
else {
appendDummyInput("CASE" + i)
.appendField(new FieldNumber(c.Item1, "-Infinity", "Infinity", 0), "RANGE_MIN" + i)
.appendField("から")
.appendField(new FieldNumber(c.Item2, "-Infinity", "Infinity", 0), "RANGE_MAX" + i)
.appendField("の");
}
appendStatementInput("DO" + i)
.appendField("とき");
i++;
}
if (defaultCount_ != 0) {
appendDummyInput("DEFAULT")
.appendField("その他の");
appendStatementInput("DEFAULT_DO")
.appendField("とき");
}
}
}
public class SwitchCaseNumberContainerBlock : Block
{
public const string type_name = "switch_case_number_container";
public SwitchCaseNumberContainerBlock()
: base(type_name)
{
}
public void init()
{
appendDummyInput()
.appendField("条件");
appendStatementInput("STACK");
setColour(210);
setTooltip("");
contextMenu = false;
}
}
public class SwitchCaseNumberConstBlock : Block
{
public const string type_name = "switch_case_number_const";
public Connection statementConnection_;
public SwitchCaseNumberConstBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setColour(210);
appendDummyInput()
.appendField("固定値")
.appendField("0", "CONST");
setPreviousStatement(true);
setNextStatement(true);
setTooltip("固定値の条件");
contextMenu = false;
}
}
public class SwitchCaseNumberRangeBlock : Block
{
public const string type_name = "switch_case_number_range";
public Connection statementConnection_;
public SwitchCaseNumberRangeBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setColour(210);
appendDummyInput()
.appendField("範囲")
.appendField("1", "RANGE_MIN")
.appendField("から")
.appendField("2", "RANGE_MAX");
setPreviousStatement(true);
setNextStatement(true);
setTooltip("範囲の条件");
contextMenu = false;
}
}
public class SwitchCaseNumberDefaultBlock : Block
{
public const string type_name = "switch_case_number_default";
public Connection statementConnection_;
public SwitchCaseNumberDefaultBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setColour(210);
appendDummyInput()
.appendField("その他");
setPreviousStatement(true);
setTooltip("条件に当てはまらなかった場合");
contextMenu = false;
}
}
public class SwitchCaseTextBlock : Block
{
public const string type_name = "switch_case_text";
internal Tuple[] cases_;
internal int defaultCount_;
public SwitchCaseTextBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setHelpUrl("http://www.example.com/");
setColour(210);
appendValueInput("SWITCH")
.appendField("右の値が");
setPreviousStatement(true);
setNextStatement(true);
setMutator(new Mutator(new[] {
SwitchCaseTextConstBlock.type_name,
SwitchCaseTextRangeBlock.type_name,
SwitchCaseTextDefaultBlock.type_name }));
setTooltip(new Func(() => {
if ((cases_.Length == 0) && (defaultCount_ == 0)) {
return "条件に合うブロックを実行";
}
else if ((cases_.Length == 0) && (defaultCount_ != 0)) {
return "条件に合うブロックを実行、合うものがなければ最後のブロックを実行";
}
else if ((cases_.Length != 0) && (defaultCount_ == 0)) {
return "条件に合うブロックを実行";
}
else if ((cases_.Length != 0) && (defaultCount_ != 0)) {
return "条件に合うブロックを実行、合うものがなければ最後のブロックを実行";
}
return "";
}));
cases_ = new Tuple[] { new Tuple("0", null) };
defaultCount_ = 0;
updateShape_();
}
///
/// Create XML to represent the text of else-if and else inputs.
///
/// XML storage element.
public Element mutationToDom(bool opt_caseIds)
{
if ((cases_.Length == 0) && (defaultCount_ == 0)) {
return null;
}
var container = Document.CreateElement("mutation");
for (var i = 0; i < cases_.Length; i++) {
Element caseInfo;
var value = getFieldValue("CONST" + i);
if (value != null) {
caseInfo = Document.CreateElement("case");
caseInfo.SetAttribute("value", value);
}
else {
var min = getFieldValue("RANGE_MIN" + i);
var max = getFieldValue("RANGE_MAX" + i);
if (min != null && max != null) {
caseInfo = Document.CreateElement("case");
caseInfo.SetAttribute("value", min + ".." + max);
}
else
continue;
}
container.AppendChild(caseInfo);
}
container.SetAttribute("default", defaultCount_.ToString());
return container;
}
///
/// Parse XML to restore the else-if and else inputs.
///
/// XML storage element.
public void domToMutation(Element xmlElement)
{
cases_ = new Tuple[0];
Element childNode;
for (var i = 0; (childNode = (dynamic)xmlElement.ChildNodes[i]) != null; i++) {
if (childNode.NodeName.ToLower() == "case") {
var value = childNode.GetAttribute("value");
if (value != null)
cases_.Push(new Tuple(value, null));
else {
var min = childNode.GetAttribute("minimum");
var max = childNode.GetAttribute("maximum");
if ((min != null) && (max != null))
cases_.Push(new Tuple(min, max));
}
}
}
var count = xmlElement.GetAttribute("default");
defaultCount_ = count == null ? 0 : Bridge.Script.ParseInt(count, 10);
updateShape_();
}
///
/// Populate the mutator's dialog with this block's components.
///
/// Mutator's workspace.
/// Root block in mutator.
public Block decompose(Workspace workspace)
{
var containerBlock = workspace.newBlock(SwitchCaseTextContainerBlock.type_name);
containerBlock.initSvg();
var connection = containerBlock.getInput("STACK").connection;
for (var i = 0; i < cases_.Length; i++) {
Block caseBlock;
var value = getFieldValue("CONST" + i);
if (value != null) {
caseBlock = workspace.newBlock(SwitchCaseTextConstBlock.type_name);
caseBlock.setFieldValue(value, "CONST");
}
else {
var min = getFieldValue("RANGE_MIN" + i);
var max = getFieldValue("RANGE_MAX" + i);
if ((min != null) && (max != null)) {
caseBlock = workspace.newBlock(SwitchCaseTextRangeBlock.type_name);
caseBlock.setFieldValue(min, "RANGE_MIN");
caseBlock.setFieldValue(max, "RANGE_MAX");
}
else
continue;
}
caseBlock.initSvg();
connection.connect(caseBlock.previousConnection);
connection = caseBlock.nextConnection;
}
if (defaultCount_ != 0) {
var defaultBlock = workspace.newBlock(SwitchCaseTextDefaultBlock.type_name);
defaultBlock.initSvg();
connection.connect(defaultBlock.previousConnection);
}
return containerBlock;
}
///
/// Reconfigure this block based on the mutator dialog's components.
///
/// Root block in mutator.
public void compose(Block containerBlock)
{
var clauseBlock = containerBlock.getInputTargetBlock("STACK");
// Count text of inputs.
cases_ = new Tuple[0];
defaultCount_ = 0;
var statementConnections = new Connection[0];
Connection defaultStatementConnection = null;
while (clauseBlock != null) {
switch (clauseBlock.type) {
case SwitchCaseTextConstBlock.type_name: {
var value = clauseBlock.getFieldValue("CONST");
cases_.Push(new Tuple(value, null));
statementConnections.Push(((SwitchCaseTextConstBlock)clauseBlock).statementConnection_);
}
break;
case SwitchCaseTextRangeBlock.type_name: {
var range_min = clauseBlock.getFieldValue("RANGE_MIN");
var range_max = clauseBlock.getFieldValue("RANGE_MAX");
cases_.Push(new Tuple(range_min, range_max));
statementConnections.Push(((SwitchCaseTextRangeBlock)clauseBlock).statementConnection_);
}
break;
case SwitchCaseTextDefaultBlock.type_name: {
defaultCount_++;
defaultStatementConnection = ((SwitchCaseTextDefaultBlock)clauseBlock).statementConnection_;
}
break;
default:
throw new Exception("Unknown block type.");
}
clauseBlock = (clauseBlock.nextConnection != null) ?
clauseBlock.nextConnection.targetBlock() : null;
}
updateShape_();
// Reconnect any child blocks.
for (var i = 0; i <= cases_.Length; i++) {
Mutator.reconnect(statementConnections[i], this, "DO" + i);
}
Mutator.reconnect(defaultStatementConnection, this, "DEFAULT_DO");
}
///
/// Store pointers to any connected child blocks.
///
/// Root block in mutator.
public void saveConnections(Block containerBlock)
{
var clauseBlock = containerBlock.getInputTargetBlock("STACK");
var i = 0;
while (clauseBlock != null) {
switch (clauseBlock.type) {
case SwitchCaseTextConstBlock.type_name: {
var inputDo = getInput("DO" + i);
((SwitchCaseTextConstBlock)clauseBlock).statementConnection_ =
(inputDo != null) ? inputDo.connection.targetConnection : null;
i++;
}
break;
case SwitchCaseTextRangeBlock.type_name: {
var inputDo = getInput("DO" + i);
((SwitchCaseTextRangeBlock)clauseBlock).statementConnection_ =
(inputDo != null) ? inputDo.connection.targetConnection : null;
i++;
}
break;
case SwitchCaseTextDefaultBlock.type_name: {
var inputDo = getInput("DEFAULT_DO");
((SwitchCaseTextDefaultBlock)clauseBlock).statementConnection_ =
(inputDo != null) ? inputDo.connection.targetConnection : null;
}
break;
default:
throw new Exception("Unknown block type.");
}
clauseBlock = (clauseBlock.nextConnection != null) ?
clauseBlock.nextConnection.targetBlock() : null;
}
}
///
/// Modify this block to have the correct text of inputs.
///
private void updateShape_()
{
// Delete everything.
if (getInput("DEFAULT") != null) {
removeInput("DEFAULT");
removeInput("DEFAULT_DO");
}
var i = 0;
while (getInput("CASE" + i) != null) {
removeInput("CASE" + i);
removeInput("DO" + i);
i++;
}
// Rebuild block.
i = 0;
foreach (var c in cases_) {
if (c.Item2 == null) {
appendDummyInput("CASE" + i)
.appendField(new FieldTextInput(c.Item1), "CONST" + i)
.appendField("の");
}
else {
appendDummyInput("CASE" + i)
.appendField(new FieldTextInput(c.Item1), "RANGE_MIN" + i)
.appendField("から")
.appendField(new FieldTextInput(c.Item2), "RANGE_MAX" + i)
.appendField("の");
}
appendStatementInput("DO" + i)
.appendField("とき");
i++;
}
if (defaultCount_ != 0) {
appendDummyInput("DEFAULT")
.appendField("その他の");
appendStatementInput("DEFAULT_DO")
.appendField("とき");
}
}
}
public class SwitchCaseTextContainerBlock : Block
{
public const string type_name = "switch_case_text_container";
public SwitchCaseTextContainerBlock()
: base(type_name)
{
}
public void init()
{
appendDummyInput()
.appendField("条件");
appendStatementInput("STACK");
setColour(210);
setTooltip("");
contextMenu = false;
}
}
public class SwitchCaseTextConstBlock : Block
{
public const string type_name = "switch_case_text_const";
public Connection statementConnection_;
public SwitchCaseTextConstBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setColour(210);
appendDummyInput()
.appendField("固定値")
.appendField("0", "CONST");
setPreviousStatement(true);
setNextStatement(true);
setTooltip("固定値の条件");
contextMenu = false;
}
}
public class SwitchCaseTextRangeBlock : Block
{
public const string type_name = "switch_case_text_range";
public Connection statementConnection_;
public SwitchCaseTextRangeBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setColour(210);
appendDummyInput()
.appendField("範囲")
.appendField("a", "RANGE_MIN")
.appendField("から")
.appendField("b", "RANGE_MAX");
setPreviousStatement(true);
setNextStatement(true);
setTooltip("範囲の条件");
contextMenu = false;
}
}
public class SwitchCaseTextDefaultBlock : Block
{
public const string type_name = "switch_case_text_default";
public Connection statementConnection_;
public SwitchCaseTextDefaultBlock()
: base(type_name)
{
}
///
/// Block for swicth/case/default condition.
///
public void init()
{
setColour(210);
appendDummyInput()
.appendField("その他");
setPreviousStatement(true);
setTooltip("条件に当てはまらなかった場合");
contextMenu = false;
}
}
partial class Ruby
{
public node switch_case_number(SwitchCaseNumberBlock block)
{
// case/when/else condition.
var argument0 = valueToCode(block, "SWITCH");
if (argument0 == null) argument0 = new int_node(this, -1);
case_node.when_t[] code = new case_node.when_t[0];
for (int n = 0; n <= block.cases_.Length; n++) {
var branch = statementToCode(block, "DO" + n);
var argument1 = block.getFieldValue("CONST" + n);
if (argument1 != null) {
var when = new case_node.when_t() { body = branch };
when.value.Push(new int_node(this, argument1 == null ? 0 : Bridge.Script.ParseInt(argument1, 10)));
code.Push(when);
}
else {
var min = block.getFieldValue("RANGE_MIN" + n);
var max = block.getFieldValue("RANGE_MAX" + n);
if ((min != null) && (max != null)) {
var when = new case_node.when_t() { body = branch };
when.value.Push(new dot2_node(this,
new int_node(this, min == null ? 0 : Bridge.Script.ParseInt(min, 10)),
new int_node(this, max == null ? 0 : Bridge.Script.ParseInt(max, 10))));
code.Push(when);
}
}
}
if (block.defaultCount_ != 0) {
var branch = statementToCode(block, "DEFAULT_DO");
if (branch != null) {
var when = new case_node.when_t() { body = branch };
code.Push(when);
}
}
return new case_node(this, argument0, code);
}
public node switch_case_text(SwitchCaseTextBlock block)
{
// case/when/else condition.
var argument0 = valueToCode(block, "SWITCH");
if (argument0 == null) argument0 = new str_node(this, "");
case_node.when_t[] code = new case_node.when_t[0];
for (int n = 0; n <= block.cases_.Length; n++) {
var branch = statementToCode(block, "DO" + n);
var argument1 = block.getFieldValue("CONST" + n);
if (argument1 != null) {
var when = new case_node.when_t() { body = branch };
when.value.Push(new str_node(this, argument1));
code.Push(when);
}
else {
var min = block.getFieldValue("RANGE_MIN" + n);
var max = block.getFieldValue("RANGE_MAX" + n);
if ((min != null) && (max != null)) {
var when = new case_node.when_t() { body = branch };
when.value.Push(new dot2_node(this, new str_node(this, min), new str_node(this, max)));
code.Push(when);
}
}
}
if (block.defaultCount_ != 0) {
var branch = statementToCode(block, "DEFAULT_DO");
if (branch != null) {
var when = new case_node.when_t() { body = branch };
code.Push(when);
}
}
return new case_node(this, argument0, code);
}
}
}