diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 726ebde..7ce4e4c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 5.2.5 dope2: specifier: git+https://deemz.org/git/joeri/dope2.git - version: git+https://deemz.org/git/joeri/dope2.git#1fe40858444cc4d0f9e4ba4223b280aef0ea4fb2 + version: git+https://deemz.org/git/joeri/dope2.git#70fb80a9fc8438a588d1fba957706a322d0900d0 react: specifier: ^19.1.0 version: 19.1.0 @@ -597,8 +597,8 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dope2@git+https://deemz.org/git/joeri/dope2.git#1fe40858444cc4d0f9e4ba4223b280aef0ea4fb2: - resolution: {commit: 1fe40858444cc4d0f9e4ba4223b280aef0ea4fb2, repo: https://deemz.org/git/joeri/dope2.git, type: git} + dope2@git+https://deemz.org/git/joeri/dope2.git#70fb80a9fc8438a588d1fba957706a322d0900d0: + resolution: {commit: 70fb80a9fc8438a588d1fba957706a322d0900d0, repo: https://deemz.org/git/joeri/dope2.git, type: git} version: 0.0.1 esbuild@0.25.4: @@ -1431,7 +1431,7 @@ snapshots: deep-is@0.1.4: {} - dope2@git+https://deemz.org/git/joeri/dope2.git#1fe40858444cc4d0f9e4ba4223b280aef0ea4fb2: + dope2@git+https://deemz.org/git/joeri/dope2.git#70fb80a9fc8438a588d1fba957706a322d0900d0: dependencies: functional-red-black-tree: 1.0.1 diff --git a/src/InputBlock.tsx b/src/InputBlock.tsx index 8151a9f..1a230e9 100644 --- a/src/InputBlock.tsx +++ b/src/InputBlock.tsx @@ -53,7 +53,7 @@ const computeSuggestions = (text, env, suggestionPriority: (s: ResolvedType) => kind: type.kind || "value", }]), ] - return []; // <-- uncomment to disable suggestions (useful for debugging) + // return []; // <-- uncomment to disable suggestions (useful for debugging) return ls .map(suggestion => [suggestionPriority(suggestion[2]), ...suggestion] as PrioritizedSuggestionType) .sort(([priorityA], [priorityB]) => priorityB - priorityA) @@ -88,7 +88,12 @@ export function InputBlock({ state, setState, suggestionPriority, onCancel }: In } const onTextChange = newText => { - setState(state => ({...state, text: newText})); + setState(state => ({...state, + text: newText, + value: (trie.get(env.names)(newText) ? { + kind: "name", + } : state.value), + })); } // fired before onInput diff --git a/src/Value.tsx b/src/Value.tsx index cf1b1f7..47db1dd 100644 --- a/src/Value.tsx +++ b/src/Value.tsx @@ -38,6 +38,7 @@ export function Value({dynamic}) { case symbolUUID: return default: + console.log("don't know how to show value:", dynamic); return <>don't know how to show value; } } diff --git a/src/configurations.ts b/src/configurations.ts index 0ec9113..05bff68 100644 --- a/src/configurations.ts +++ b/src/configurations.ts @@ -75,184 +75,7 @@ export const tripleFunctionCallEditorState: ExprBlockState = { }, }; -export const biggerExample: ExprBlockState = { - "kind": "let", - "inner": { - "kind": "let", - "inner": { - "kind": "let", - "inner": { - "kind": "let", - "inner": { - "kind": "input", - "text": "", - "value": { - "kind": "text" - }, - "focus": false - }, - "name": "myListInc", - "value": { - "kind": "call", - "fn": { - "kind": "call", - "fn": { - "kind": "input", - "text": "list.map", - "value": { - "kind": "name" - }, - "focus": false - }, - "input": { - "kind": "input", - "text": "myList", - "value": { - "kind": "name" - }, - "focus": false - } - }, - "input": { - "kind": "input", - "text": "inc", - "value": { - "kind": "name" - }, - "focus": false - } - } - }, - "name": "myList", - "value": { - "kind": "call", - "fn": { - "kind": "call", - "fn": { - "kind": "input", - "text": "list.push", - "value": { - "kind": "name" - }, - "focus": false - }, - "input": { - "kind": "call", - "fn": { - "kind": "call", - "fn": { - "kind": "input", - "text": "list.push", - "value": { - "kind": "name" - }, - "focus": false - }, - "input": { - "kind": "call", - "fn": { - "kind": "call", - "fn": { - "kind": "input", - "text": "list.push", - "value": { - "kind": "name" - }, - "focus": false - }, - "input": { - "kind": "input", - "text": "list.emptyList", - "value": { - "kind": "name" - }, - "focus": false - } - }, - "input": { - "kind": "input", - "text": "1", - "value": { - "kind": "literal", - "type": "Int" - }, - "focus": false - } - } - }, - "input": { - "kind": "input", - "text": "2", - "value": { - "kind": "literal", - "type": "Int" - }, - "focus": false - } - } - }, - "input": { - "kind": "input", - "text": "3", - "value": { - "kind": "literal", - "type": "Int" - }, - "focus": false - } - } - }, - "name": "id", - "value": { - "kind": "lambda", - "paramName": "x", - "expr": { - "kind": "input", - "text": "x", - "value": { - "kind": "name" - }, - "focus": false - } - } - }, - "name": "inc", - "value": { - "kind": "lambda", - "paramName": "x", - "expr": { - "kind": "call", - "fn": { - "kind": "call", - "fn": { - "kind": "input", - "text": "addInt", - "value": { - "kind": "name" - }, - "focus": false - }, - "input": { - "kind": "input", - "text": "x", - "value": { - "kind": "name" - }, - "focus": false - } - }, - "input": { - "kind": "input", - "text": "1", - "value": { - "kind": "literal", - "type": "Int" - }, - "focus": true - } - } - } -}; +export const biggerExample: ExprBlockState = {"kind":"let","inner":{"kind":"let","inner":{"kind":"let","inner":{"kind":"let","inner":{"kind":"input","text":"","value":{"kind":"text"},"focus":false},"name":"myListInc","value":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.map","value":{"kind":"name"},"focus":false},"input":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.map","value":{"kind":"name"},"focus":false},"input":{"kind":"input","text":"myList","value":{"kind":"name"},"focus":false}},"input":{"kind":"input","text":"inc","value":{"kind":"name"},"focus":false}}},"input":{"kind":"input","text":"id","value":{"kind":"name"},"focus":true}}},"name":"myList","value":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.push","value":{"kind":"name"},"focus":false},"input":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.push","value":{"kind":"name"},"focus":false},"input":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.push","value":{"kind":"name"},"focus":false},"input":{"kind":"input","text":"list.emptyList","value":{"kind":"name"},"focus":false}},"input":{"kind":"input","text":"1","value":{"kind":"literal","type":"Int"},"focus":false}}},"input":{"kind":"input","text":"2","value":{"kind":"literal","type":"Int"},"focus":false}}},"input":{"kind":"input","text":"3","value":{"kind":"literal","type":"Int"},"focus":false}}},"name":"id","value":{"kind":"lambda","paramName":"x","expr":{"kind":"input","text":"x","value":{"kind":"name"},"focus":false}}},"name":"inc","value":{"kind":"lambda","paramName":"x","expr":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"addInt","value":{"kind":"name"},"focus":false},"input":{"kind":"input","text":"x","value":{"kind":"name"},"focus":false}},"input":{"kind":"input","text":"1","value":{"kind":"literal","type":"Int"},"focus":true}}}}; export const lambda2Params: ExprBlockState = { "kind": "let", diff --git a/src/eval.ts b/src/eval.ts index 0bef1fe..c1af9f4 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -1,8 +1,10 @@ -import { dict, Double, fnType, getHumanReadableName, getSymbol, Int, mergeUnifications, NotAFunctionError, occurring, prettyT, prettyU, recomputeTypeVars, reduceUnification, substitute, symbolFunction, trie, TYPE_VARS, UNBOUND_SYMBOLS, UnifyError, unifyLL } from "dope2"; +import { Double, fnType, getHumanReadableName, getSymbol, Int, mergeUnifications, NotAFunctionError, occurring, prettyT, prettyU, recomputeTypeVars, reduceUnification, substitute, symbolFunction, trie, TYPE_VARS, UNBOUND_SYMBOLS, UnifyError, unifyLL, transitivelyGrow } from "dope2"; import type { ExprBlockState } from "./ExprBlock"; import type { InputValueType } from "./InputBlock"; +const IS_DEV = (import.meta.env.MODE === "development"); + export interface Environment { names: any; nextFreeTypeVar: number; @@ -88,30 +90,38 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved try { // fn is a function... const [rewrittenFnType] = recomputeTypeVars([fnResolved.t], env.nextFreeTypeVar); - const unification = unifyLL(rewrittenFnType.params[0](rewrittenFnType), inputResolved.t); + const unification = (unifyLL(rewrittenFnType.params[0](rewrittenFnType), inputResolved.t)); const inputTypeVars = occurring(inputResolved.t); + const fnTypeVars = occurring(fnResolved.t); const subsetOfUnification = new Map([...unification].filter(([typeVar]) => inputTypeVars.has(typeVar))); + const otherSubSetOfUnification = new Map([...unification].filter(([typeVar]) => fnTypeVars.has(typeVar))); const outType = substitute( rewrittenFnType.params[1](rewrittenFnType), - reduceUnification(subsetOfUnification), + reduceUnification(unification), []); // <- not important - console.log('========= evalCallBlock2 =========') - console.log('fnType :', prettyT(fnResolved.t)); - console.log('rewrittenFnType :', prettyT(rewrittenFnType)); - console.log('inputType :', prettyT(inputResolved.t)); - console.log('outType :', prettyT(outType)); - console.log('unification :', prettyU(unification)); - console.log('inputTypeVars :', [...inputTypeVars].map(getHumanReadableName)); - console.log('fn.unification :', prettyU(fnResolved.unification)); - console.log('input.unification :', prettyU(inputResolved.unification)); - console.log('subsetOfUnification:', prettyU(subsetOfUnification)); - console.log('==================================') - const grandUnification = [fnResolved.unification, inputResolved.unification] - .reduce(mergeUnifications, subsetOfUnification); + .reduce(mergeUnifications, unification); + + if (IS_DEV) { + console.log('========= evalCallBlock2 =========') + console.log('fnType :', prettyT(fnResolved.t)); + console.log('rewrittenFnType :', prettyT(rewrittenFnType)); + console.log('inputType :', prettyT(inputResolved.t)); + console.log('unification :', prettyU(unification)); + console.log('subsetOfUnification :', prettyU(subsetOfUnification)); + console.log('otherSubSetOfUnification:', prettyU(otherSubSetOfUnification)); + console.log('outType :', prettyT(outType)); + // console.log('inputTypeVars :', `{${[...inputTypeVars].map(getHumanReadableName).join(', ')}}`); + // console.log('fnTypeVars :', `{${[...fnTypeVars].map(getHumanReadableName).join(', ')}}`); + console.log('fn.unification :', prettyU(fnResolved.unification)); + console.log('input.unification :', prettyU(inputResolved.unification)); + console.log('grandUnification :', prettyU(grandUnification)); + console.log('==================================') + } + if (inputResolved.kind === "error") { return { @@ -155,17 +165,25 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved if ((e instanceof UnifyError)) { // even though fn was incompatible with the given parameter, we can still suppose that our output-type will be that of fn...? const outType = fnResolved.t.params[1](fnResolved.t); - return { - kind: "error", - e, - depth: 0, - t: outType, - unification: mergeUnifications(fnResolved.unification, inputResolved.unification), - }; + try { + return { + kind: "error", + e, + depth: 0, + t: outType, + unification: mergeUnifications(fnResolved.unification, inputResolved.unification), // may throw! + }; + } + catch (e) { + if ((e instanceof UnifyError)) { + return makeError(env, e); + } + throw e; + } } throw e; } -} +}; export function evalCallBlock(fn: ExprBlockState, input: ExprBlockState, env): ResolvedType { const fnResolved = evalEditorBlock(fn, env); @@ -190,12 +208,14 @@ export function evalLambdaBlock(paramName: string, expr: ExprBlockState, env): R reduceUnification(exprResolved.unification), []); // <- not important - console.log('========= evalLambdaBlock =========') - console.log('paramType :', prettyT(paramType)); - console.log('exprType :', prettyT(exprResolved.t)); - console.log('lambdaType :', prettyT(lambdaT)); - console.log('lambdaTypeSubsituted:', prettyT(lambdaTSubstituted)); - console.log('===================================') + if (IS_DEV) { + console.log('========= evalLambdaBlock =========') + console.log('paramType :', prettyT(paramType)); + console.log('exprType :', prettyT(exprResolved.t)); + console.log('lambdaType :', prettyT(lambdaT)); + console.log('lambdaTypeSubsituted:', prettyT(lambdaTSubstituted)); + console.log('===================================') + } // console.log('inner kind', exprResolved.kind, paramName); if (exprResolved.kind === "error") {