Skip to content

Commit

Permalink
Minor additions
Browse files Browse the repository at this point in the history
  • Loading branch information
tildeman committed May 1, 2023
1 parent 555d6d3 commit bdd9ee8
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 75 deletions.
45 changes: 40 additions & 5 deletions blocks/datatypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ import * as Blockly from "blockly"
import { removeType, identifyModelParams, findLegalName, rename } from "../categories/types.ts"

const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
{
"type": "types_cast",
"message0": "cast %1 to %2",
"args0": [
{
"type": "input_value",
"name": "VALUE"
},
{
"type": "input_value",
"name": "TYPE",
"check": "Type"
}
],
"output": null,
"style": "loop_blocks",
"tooltip": "Cast a value into a type.",
"inputsInline": true,
"helpUrl": ""
},
{
"type": "types_list",
"message0": "List of %1",
Expand Down Expand Up @@ -59,14 +79,14 @@ const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
"Integer",
"Int"
],
[
"Decimal",
"Float"
],
[
"Big decimal",
"Double"
],
[
"Decimal",
"Float"
],
[
"Character",
"Char"
Expand All @@ -80,7 +100,9 @@ const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
],
"output": "Type",
"style": "loop_blocks",
"tooltip": "A primitive data type.",
"extensions": [
"types_tooltip"
],
"helpUrl": ""
},
{
Expand Down Expand Up @@ -173,6 +195,19 @@ const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
},
])

const TOOLTIPS_BY_TYPE = {
"Integer": "An integer without constraints.",
"Int": "An integer from approximately -10^18 to 10^18.",
"Float": "A rough representation of decimals from -3*10^38 to 3*10^38.",
"Double": "A finer representation of decimals from -2*10^308 to 2*10^308.",
"Char": "A Unicode character.",
"Bool": "A truth value representing true or false."
}
Blockly.Extensions.register(
"types_tooltip",
Blockly.Extensions.buildTooltipForDropdown("TYPE", TOOLTIPS_BY_TYPE)
)

const productTypeMutator = {
itemCount_: 2,

Expand Down
7 changes: 6 additions & 1 deletion blocks/logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import * as Blockly from "blockly"
const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
{
"type": "logic_patternmatch",
"message0": "case %1 run %2",
"message0": "match %1 case %2 run %3",
"args0": [
{
"type": "input_value",
"name": "PATTERN",
"align": "RIGHT"
},
{
"type": "input_value",
"name": "CASE0",
Expand Down
79 changes: 59 additions & 20 deletions blocks/text.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
import * as Blockly from "blockly"

const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
{
"type": "math_cast",
"message0": "cast %1 to %2",
"args0": [
{
"type": "input_value",
"name": "VALUE"
},
{
"type": "input_value",
"name": "TYPE",
"check": "Type"
}
],
"output": "Number",
"style": "math_blocks",
"tooltip": "Convert a parsed value into a number of given type.",
"inputsInline": true,
"helpUrl": ""
},
{
"type": "text_parse",
"message0": "parse %1",
Expand Down Expand Up @@ -52,7 +32,66 @@ const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([
"style": "text_blocks",
"tooltip": "Converts a number to a string.",
"helpUrl": ""
},
{
"type": "text_charops",
"message0": "%1 of %2",
"args0": [
{
"type": "field_dropdown",
"name": "ACTION",
"options": [
[
"order",
"ORD"
],
[
"character",
"CHR"
]
]
},
{
"type": "input_value",
"name": "VALUE"
}
],
"output": null,
"extensions": [
"character_operations",
"character_validator_helper"
],
"style": "text_blocks",
"tooltip": "",
"helpUrl": ""
}
])

const characterOperations = {
validator_: function(name) {
const block = this.getSourceBlock()
if (name === "ORD") {
block.getInput("VALUE").setCheck("String")
block.setOutput(true, "Number")
}
else if (name === "CHR") {
block.getInput("VALUE").setCheck("Number")
block.setOutput(true, "String")
}
return name
}
}
Blockly.Extensions.registerMixin(
"character_operations",
characterOperations
)

function characterOperationsValidatorHelper() {
this.getField("ACTION").setValidator(this.validator_)
}
Blockly.Extensions.register(
"character_validator_helper",
characterOperationsValidatorHelper
)

Blockly.common.defineBlocks(blocks)
86 changes: 58 additions & 28 deletions categories/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ type TypeBlock = Blockly.BlockSvg & {

type DataConstructorBlock = Blockly.BlockSvg & {
isolate: () => void,
updateShape_: () => void
updateShape_: () => void,
renameDataConstructor: () => void
}

type DataConstructorGetBlock = Blockly.BlockSvg & {
Expand All @@ -32,25 +33,50 @@ type DataConstructorGetBlock = Blockly.BlockSvg & {
updateShape_: () => void
}

// The workspace is the most important thing here. Ignore actual button things.
type FlyoutButtonWithWorkspace = {
workspace: Blockly.Workspace
}

var callback_idempotence = false

// Let's start, shall we?

function typeFlyoutBlocks(workspace: TypeWorkspace): any[] {
const jsonList: any[] = [
function typeFlyoutBlocks(
workspace: TypeWorkspace): Blockly.utils.toolbox.FlyoutDefinition {
let jsonList: any[] = [
{
"kind": "block",
"type": "types_primitive"
},
{
"kind": "block",
"type": "types_primitive",
"fields": {
"TYPE": "Double"
}
},
{
"kind": "block",
"type": "types_primitive",
"fields": {
"TYPE": "Bool"
}
},
{
"kind": "block",
"type": "types_list"
},
{
"kind": "block",
"type": "types_list",
"inputs": {
"SUBTYPE": {
"block": {
"kind": "block",
"type": "types_primitive",
"fields": {
"TYPE": "Char"
}
}
}
}
},
{
"kind": "block",
"type": "types_tuple"
Expand All @@ -62,6 +88,10 @@ function typeFlyoutBlocks(workspace: TypeWorkspace): any[] {
"itemCount": 0
}
},
{
"kind": "block",
"type": "types_cast"
},
{
"kind": "block",
"type": "types_placeholder"
Expand Down Expand Up @@ -121,8 +151,9 @@ function typeFlyoutBlocks(workspace: TypeWorkspace): any[] {
return jsonList
}

function updateDynamicCategory(workspace: TypeWorkspace): any[] {
let toolbox = []
function updateDynamicCategory(
workspace: TypeWorkspace): Blockly.utils.toolbox.FlyoutDefinition {
let toolbox = []
const button = {
"kind": "button",
"text": "Create type...",
Expand All @@ -137,25 +168,23 @@ function updateDynamicCategory(workspace: TypeWorkspace): any[] {
}

function addTypeCallback(bflyout: Blockly.FlyoutButton): void {
const targetwsp = bflyout.getTargetWorkspace() as TypeWorkspace
// Modern problems require modern solutions
const workspace =
(bflyout as unknown as FlyoutButtonWithWorkspace).workspace as TypeWorkspace
const workspace = bflyout.getTargetWorkspace() as TypeWorkspace
const flyoutwsp = workspace.getFlyout().getWorkspace() as TypeWorkspace
if (!callback_idempotence){
targetwsp.typeMap = workspace.typeMap = {
flyoutwsp.typeMap = workspace.typeMap = {
types: {},
dataConstructors: {},
}
targetwsp.getTypeMap = workspace.getTypeMap = function(){
flyoutwsp.getTypeMap = workspace.getTypeMap = function(){
return this.typeMap.types
}
targetwsp.setTypeMap = workspace.setTypeMap = function(typename, value){
flyoutwsp.setTypeMap = workspace.setTypeMap = function(typename, value){
this.typeMap.types[typename] = value
}
targetwsp.getDataConsMap = workspace.getDataConsMap = function(){
flyoutwsp.getDataConsMap = workspace.getDataConsMap = function(){
return this.typeMap.dataConstructors
}
targetwsp.setDataConsMap = workspace.setDataConsMap = function(typename, value){
flyoutwsp.setDataConsMap = workspace.setDataConsMap = function(typename, value){
this.typeMap.dataConstructors[typename] = value
}
}
Expand Down Expand Up @@ -186,7 +215,7 @@ function addTypeCallback(bflyout: Blockly.FlyoutButton): void {
))

// Update the dynamic category to include the new type
targetwsp.getToolbox().refreshSelection()
workspace.getToolbox().refreshSelection()
}

function generateModelParams(block: Blockly.Block | null): ITypeModel {
Expand Down Expand Up @@ -275,9 +304,9 @@ function generateModelParams(block: Blockly.Block | null): ITypeModel {

export function identifyModelParams(model: ITypeModel | null) : (string | string[] | null) {
switch (model.kind) {
case 0:
case TypeKind.Placeholder:
return null
case 1:
case TypeKind.Primitive:
switch (model.name) {
case "Int":
case "Integer":
Expand All @@ -291,10 +320,10 @@ export function identifyModelParams(model: ITypeModel | null) : (string | string
case "Bool":
return "Boolean"
}
case 2:
case TypeKind.List:
// Assuming strings are arrays of characters; this is not always the case.
return ["Array", "String"]
case 3:
case TypeKind.Tuple:
// Although there is no 1-tuple in Haskell and the fact that this library
// is primarily designed with Haskell in mind, support for other languages
// such as Python also exists, plus allowing users to define these is
Expand Down Expand Up @@ -389,7 +418,8 @@ export function removeType(workspace: TypeWorkspace, typeName: string): void {
delete workspace.getTypeMap()[typeName]
}

export function typeFlyout(workspace: TypeWorkspace): any[] {
export function typeFlyout(
workspace: TypeWorkspace): Blockly.utils.toolbox.FlyoutDefinition {
workspace.registerButtonCallback(
"DATATYPE",
addTypeCallback
Expand Down Expand Up @@ -474,7 +504,7 @@ export function nameIsUsed(name: string, workspace: TypeWorkspace, opt_exclude?:
}

function nameIsLegal(name: string, workspace: TypeWorkspace, opt_exclude?: Blockly.Block): boolean {
return !nameIsUsed(name, workspace, opt_exclude);
return !nameIsUsed(name, workspace, opt_exclude)
}

export function findLegalName(name: string, block: Blockly.Block): string {
Expand All @@ -485,7 +515,7 @@ export function findLegalName(name: string, block: Blockly.Block): string {
name = name || "Something"
while (!nameIsLegal(name, (block.workspace as TypeWorkspace), block)) {
// Collision with another data constructor.
const r = name.match(/^(.*?)(\d+)$/);
const r = name.match(/^(.*?)(\d+)$/)
if (!r) {
name += "2"
} else {
Expand All @@ -496,7 +526,7 @@ export function findLegalName(name: string, block: Blockly.Block): string {
}

export function rename(this: Blockly.Field, name: string): string {
const block:any = this.getSourceBlock()
const block = this.getSourceBlock() as DataConstructorBlock

// Strip leading and trailing whitespace. Beyond this, all names are legal.
// Later in the code I'd have to enforce the first letter being capitalized.
Expand Down
Loading

0 comments on commit bdd9ee8

Please sign in to comment.