Merge remote-tracking branch 'origin/develop' into scoring-cleanup-three
This commit is contained in:
commit
9225710d2d
|
@ -5,14 +5,14 @@
|
|||
"dependencies": {
|
||||
"@headlessui/react": "^1.6.5",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@hookform/resolvers": "^2.9.1",
|
||||
"@hookform/resolvers": "^2.9.3",
|
||||
"@quri/squiggle-lang": "^0.2.8",
|
||||
"@react-hook/size": "^2.1.2",
|
||||
"clsx": "^1.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.1.0",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-hook-form": "^7.32.2",
|
||||
"react-hook-form": "^7.33.0",
|
||||
"react-use": "^17.4.0",
|
||||
"react-vega": "^7.5.1",
|
||||
"vega": "^5.22.1",
|
||||
|
|
|
@ -244,7 +244,28 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
|||
case "module": {
|
||||
return (
|
||||
<VariableBox heading="Module" showTypes={showTypes}>
|
||||
<span className="text-slate-600 font-semibold">Internal Module</span>
|
||||
<div className="space-y-3">
|
||||
{Object.entries(expression.value)
|
||||
.filter(([key, r]) => key !== "Math")
|
||||
.map(([key, r]) => (
|
||||
<div key={key} className="flex space-x-2">
|
||||
<div className="flex-none">
|
||||
<header className="text-slate-500 font-mono">{key}:</header>
|
||||
</div>
|
||||
<div className="px-2 grow bg-gray-50 border border-gray-100 rounded-sm">
|
||||
<SquiggleItem
|
||||
expression={r}
|
||||
width={width !== undefined ? width - 20 : width}
|
||||
height={height / 3}
|
||||
showTypes={showTypes}
|
||||
distributionPlotSettings={distributionPlotSettings}
|
||||
chartSettings={chartSettings}
|
||||
environment={environment}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</VariableBox>
|
||||
);
|
||||
}
|
||||
|
|
1
packages/squiggle-lang/.gitignore
vendored
1
packages/squiggle-lang/.gitignore
vendored
|
@ -22,3 +22,4 @@ _coverage
|
|||
coverage
|
||||
.nyc_output/
|
||||
src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
||||
src/rescript/Reducer/Reducer_Peggy/helpers.js
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
"peggy": "peggy --cache",
|
||||
"rescript": "rescript",
|
||||
"build": "yarn build:peggy && yarn build:rescript && yarn build:typescript",
|
||||
"build:peggy": "find . -type f -name *.peggy -exec yarn peggy {} \\;",
|
||||
"build:peggy:helpers": "tsc --module commonjs --outDir src/rescript/Reducer/Reducer_Peggy/ src/rescript/Reducer/Reducer_Peggy/helpers.ts",
|
||||
"build:peggy": "yarn build:peggy:helpers && find . -type f -name *.peggy -exec yarn peggy {} \\;",
|
||||
"build:rescript": "rescript build -with-deps",
|
||||
"build:typescript": "tsc",
|
||||
"bundle": "webpack",
|
||||
|
@ -41,7 +42,7 @@
|
|||
"@stdlib/stats": "^0.0.13",
|
||||
"jstat": "^1.9.5",
|
||||
"lodash": "^4.17.21",
|
||||
"mathjs": "^10.6.0",
|
||||
"mathjs": "^10.6.3",
|
||||
"pdfast": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -52,7 +53,7 @@
|
|||
"bisect_ppx": "^2.7.1",
|
||||
"chalk": "^5.0.1",
|
||||
"codecov": "^3.8.3",
|
||||
"fast-check": "^3.0.0",
|
||||
"fast-check": "^3.0.1",
|
||||
"gentype": "^4.4.0",
|
||||
"jest": "^27.5.1",
|
||||
"moduleserve": "^0.9.1",
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
evaluatePartialUsingExternalBindings,
|
||||
evaluateUsingOptions,
|
||||
foreignFunctionInterface,
|
||||
parse as parseRescript,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
export {
|
||||
makeSampleSetDist,
|
||||
|
@ -32,12 +31,14 @@ import {
|
|||
convertRawToTypescript,
|
||||
lambdaValue,
|
||||
} from "./rescript_interop";
|
||||
import { Ok, result, resultMap, tag, tagged } from "./types";
|
||||
import { result, resultMap, tag, tagged } from "./types";
|
||||
import { Distribution, shape } from "./distribution";
|
||||
|
||||
export { Distribution, resultMap, defaultEnvironment };
|
||||
export type { result, shape, environment, lambdaValue, squiggleExpression };
|
||||
|
||||
export { parse } from "./parse";
|
||||
|
||||
export let defaultSamplingInputs: environment = {
|
||||
sampleCount: 10000,
|
||||
xyPointLength: 10000,
|
||||
|
@ -59,23 +60,6 @@ export function run(
|
|||
return resultMap(res, (x) => createTsExport(x, e));
|
||||
}
|
||||
|
||||
export function parse(
|
||||
squiggleString: string
|
||||
): result<null, Extract<errorValue, { tag: "RESyntaxError" }>> {
|
||||
const maybeExpression = parseRescript(squiggleString);
|
||||
if (maybeExpression.tag === "Ok") {
|
||||
return Ok(null); // TODO - return AST
|
||||
} else {
|
||||
if (
|
||||
typeof maybeExpression.value !== "object" ||
|
||||
maybeExpression.value.tag !== "RESyntaxError"
|
||||
) {
|
||||
throw new Error("Expected syntax error");
|
||||
}
|
||||
return { tag: "Error", value: maybeExpression.value };
|
||||
}
|
||||
}
|
||||
|
||||
// Run Partial. A partial is a block of code that doesn't return a value
|
||||
export function runPartial(
|
||||
squiggleString: string,
|
||||
|
|
23
packages/squiggle-lang/src/js/parse.ts
Normal file
23
packages/squiggle-lang/src/js/parse.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
errorValue,
|
||||
parse as parseRescript,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
import { result } from "./types";
|
||||
import { AnyPeggyNode } from "../rescript/Reducer/Reducer_Peggy/helpers";
|
||||
|
||||
export function parse(
|
||||
squiggleString: string
|
||||
): result<AnyPeggyNode, Extract<errorValue, { tag: "RESyntaxError" }>> {
|
||||
const maybeExpression = parseRescript(squiggleString);
|
||||
if (maybeExpression.tag === "Ok") {
|
||||
return { tag: "Ok", value: maybeExpression.value as AnyPeggyNode };
|
||||
} else {
|
||||
if (
|
||||
typeof maybeExpression.value !== "object" ||
|
||||
maybeExpression.value.tag !== "RESyntaxError"
|
||||
) {
|
||||
throw new Error("Expected syntax error");
|
||||
}
|
||||
return { tag: "Error", value: maybeExpression.value };
|
||||
}
|
||||
}
|
|
@ -1,74 +1,7 @@
|
|||
// Try in https://peggyjs.org/online
|
||||
|
||||
{{
|
||||
var toFunction = {
|
||||
'-': 'subtract',
|
||||
'->': 'pipe',
|
||||
'!=': 'unequal',
|
||||
'.-': 'dotSubtract',
|
||||
'.*': 'dotMultiply',
|
||||
'./': 'dotDivide',
|
||||
'.^': 'dotPow',
|
||||
'.+': 'dotAdd',
|
||||
'*': 'multiply',
|
||||
'/': 'divide',
|
||||
'&&': 'and',
|
||||
'^': 'pow', // or xor
|
||||
'+': 'add',
|
||||
'<': 'smaller',
|
||||
'<=': 'smallerEq',
|
||||
'==': 'equal',
|
||||
'>': 'larger',
|
||||
'>=': 'largerEq',
|
||||
'||': 'or',
|
||||
'to': 'credibleIntervalToDistribution',
|
||||
}
|
||||
|
||||
var unaryToFunction = {
|
||||
'-': 'unaryMinus',
|
||||
'!': 'not',
|
||||
'.-': 'unaryDotMinus',
|
||||
}
|
||||
|
||||
var postOperatorToFunction = {
|
||||
'.': '$_atIndex_$',
|
||||
'()': '$$_applyAll_$$',
|
||||
'[]': '$_atIndex_$',
|
||||
}
|
||||
|
||||
function makeFunctionCall(fn, args) {
|
||||
if (fn === '$$_applyAll_$$') {
|
||||
// Any list of values is applied from left to right anyway.
|
||||
// Like in Haskell and Lisp.
|
||||
// So we remove the redundant $$_applyAll_$$.
|
||||
if (args[0].type === "Identifier") {args[0].type = "CallIdentifier"}
|
||||
return nodeExpression(args)
|
||||
} else {
|
||||
return nodeExpression([nodeCallIndentifier(fn), ...args])
|
||||
}
|
||||
}
|
||||
|
||||
function apply(fn, arg) { return makeFunctionCall(fn, [arg]); }
|
||||
function constructArray(elems) { return apply('$_constructArray_$', nodeExpression(elems)); }
|
||||
function constructRecord(elems) { return apply('$_constructRecord_$', nodeExpression(elems)); }
|
||||
|
||||
function nodeBlock(statements) {return{type: 'Block', statements: statements}}
|
||||
function nodeBoolean(value) {return {type: 'Boolean', value: value}}
|
||||
function nodeCallIndentifier(value) {return {type: 'CallIdentifier', value: value}}
|
||||
function nodeExpression(args) {return {type: 'Expression', nodes: args}}
|
||||
function nodeFloat(value) {return {type: 'Float', value: value}}
|
||||
function nodeIdentifier(value) {return {type: 'Identifier', value: value}}
|
||||
function nodeInteger(value) {return {type: 'Integer', value: value}}
|
||||
function nodeKeyValue(key, value) {
|
||||
if (key.type === 'Identifier') {key.type = 'String'}
|
||||
return {type: 'KeyValue', key: key, value: value}}
|
||||
function nodeLambda(args, body) {return {type: 'Lambda', args: args, body: body}}
|
||||
function nodeLetStatment(variable, value) {return {type: 'LetStatement', variable: variable, value: value}}
|
||||
function nodeModuleIdentifier(value) {return {type: 'ModuleIdentifier', value: value}}
|
||||
function nodeString(value) {return {type: 'String', value: value}}
|
||||
function nodeTernary(condition, trueExpression, falseExpression) {return {type: 'Ternary', condition: condition, trueExpression: trueExpression, falseExpression: falseExpression}}
|
||||
|
||||
function nodeTypeIdentifier(typeValue) {return {type: 'TypeIdentifier', value: typeValue}}
|
||||
const h = require('./helpers');
|
||||
}}
|
||||
|
||||
start
|
||||
|
@ -80,21 +13,21 @@ zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
|
|||
outerBlock
|
||||
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
||||
{ if (finalExpression != null) { statements.push(finalExpression) }
|
||||
return nodeBlock(statements) }
|
||||
return h.nodeBlock(statements) }
|
||||
/ finalExpression: expression
|
||||
{ return nodeBlock([finalExpression])}
|
||||
{ return h.nodeBlock([finalExpression])}
|
||||
|
||||
innerBlockOrExpression
|
||||
= quotedInnerBlock
|
||||
/ finalExpression: expression
|
||||
{ return nodeBlock([finalExpression])}
|
||||
{ return h.nodeBlock([finalExpression])}
|
||||
|
||||
quotedInnerBlock
|
||||
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
||||
{ statements.push(finalExpression)
|
||||
return nodeBlock(statements) }
|
||||
return h.nodeBlock(statements) }
|
||||
/ '{' _nl finalExpression: expression _nl '}'
|
||||
{ return nodeBlock([finalExpression]) }
|
||||
{ return h.nodeBlock([finalExpression]) }
|
||||
|
||||
array_statements
|
||||
= head:statement tail:(statementSeparator @array_statements )
|
||||
|
@ -109,12 +42,12 @@ statement
|
|||
|
||||
letStatement
|
||||
= variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
|
||||
{ return nodeLetStatment(variable, value) }
|
||||
{ return h.nodeLetStatement(variable, value) }
|
||||
|
||||
defunStatement
|
||||
= variable:identifier '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression
|
||||
{ var value = nodeLambda(args, body)
|
||||
return nodeLetStatment(variable, value) }
|
||||
{ var value = h.nodeLambda(args, body)
|
||||
return h.nodeLetStatement(variable, value) }
|
||||
|
||||
assignmentOp "assignment" = '='
|
||||
|
||||
|
@ -128,16 +61,16 @@ ifthenelse
|
|||
= 'if' __nl condition:logicalAdditive
|
||||
__nl 'then' __nl trueExpression:innerBlockOrExpression
|
||||
__nl 'else' __nl falseExpression:(ifthenelse/innerBlockOrExpression)
|
||||
{ return nodeTernary(condition, trueExpression, falseExpression) }
|
||||
{ return h.nodeTernary(condition, trueExpression, falseExpression) }
|
||||
|
||||
ternary
|
||||
= condition:logicalAdditive _ '?' _nl trueExpression:logicalAdditive _ ':' _nl falseExpression:(ternary/logicalAdditive)
|
||||
{ return nodeTernary(condition, trueExpression, falseExpression) }
|
||||
{ return h.nodeTernary(condition, trueExpression, falseExpression) }
|
||||
|
||||
logicalAdditive
|
||||
= head:logicalMultiplicative tail:(_ operator:logicalAdditiveOp _nl arg:logicalMultiplicative {return {operator: operator, right: arg}})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(toFunction[element.operator], [result, element.right])
|
||||
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
||||
}, head)}
|
||||
|
||||
logicalAdditiveOp "operator" = '||'
|
||||
|
@ -146,21 +79,21 @@ logicalAdditive
|
|||
logicalMultiplicative
|
||||
= head:equality tail:(_ operator:logicalMultiplicativeOp _nl arg:equality {return {operator: operator, right: arg}})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(toFunction[element.operator], [result, element.right])
|
||||
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
||||
}, head)}
|
||||
|
||||
logicalMultiplicativeOp "operator" = '&&'
|
||||
|
||||
equality
|
||||
= left:relational _ operator:equalityOp _nl right:relational
|
||||
{ return makeFunctionCall(toFunction[operator], [left, right])}
|
||||
{ return h.makeFunctionCall(h.toFunction[operator], [left, right])}
|
||||
/ relational
|
||||
|
||||
equalityOp "operator" = '=='/'!='
|
||||
|
||||
relational
|
||||
= left:additive _ operator:relationalOp _nl right:additive
|
||||
{ return makeFunctionCall(toFunction[operator], [left, right])}
|
||||
{ return h.makeFunctionCall(h.toFunction[operator], [left, right])}
|
||||
/ additive
|
||||
|
||||
relationalOp "operator" = '<='/'<'/'>='/'>'
|
||||
|
@ -168,7 +101,7 @@ relational
|
|||
additive
|
||||
= head:multiplicative tail:(_ operator:additiveOp _nl arg:multiplicative {return {operator: operator, right: arg}})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(toFunction[element.operator], [result, element.right])
|
||||
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
||||
}, head)}
|
||||
|
||||
additiveOp "operator" = '+' / '-' / '.+' / '.-'
|
||||
|
@ -176,7 +109,7 @@ additive
|
|||
multiplicative
|
||||
= head:power tail:(_ operator:multiplicativeOp _nl arg:power {return {operator: operator, right: arg}})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(toFunction[element.operator], [result, element.right])
|
||||
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
||||
}, head)}
|
||||
|
||||
multiplicativeOp "operator" = '*' / '/' / '.*' / './'
|
||||
|
@ -184,7 +117,7 @@ multiplicative
|
|||
power
|
||||
= head:credibleInterval tail:(_ operator:powerOp _nl arg:credibleInterval {return {operator: operator, right: arg}})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(toFunction[element.operator], [result, element.right])
|
||||
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
||||
}, head)}
|
||||
|
||||
powerOp "operator" = '^' / '.^'
|
||||
|
@ -192,7 +125,7 @@ power
|
|||
credibleInterval
|
||||
= head:chainFunctionCall tail:(__ operator:credibleIntervalOp __nl arg:chainFunctionCall {return {operator: operator, right: arg}})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(toFunction[element.operator], [result, element.right])
|
||||
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
||||
}, head)}
|
||||
|
||||
credibleIntervalOp "operator" = 'to'
|
||||
|
@ -200,7 +133,7 @@ credibleInterval
|
|||
chainFunctionCall
|
||||
= head:unary tail:(_ ('->'/'|>') _nl chained:chainedFunction {return chained})*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(element.fnName, [result, ...element.args])
|
||||
return h.makeFunctionCall(element.fnName, [result, ...element.args])
|
||||
}, head)}
|
||||
|
||||
chainedFunction
|
||||
|
@ -215,7 +148,7 @@ chainFunctionCall
|
|||
|
||||
unary
|
||||
= unaryOperator:unaryOperator _nl right:(unary/postOperator)
|
||||
{ return apply(unaryToFunction[unaryOperator], right)}
|
||||
{ return h.apply(h.unaryToFunction[unaryOperator], right)}
|
||||
/ postOperator
|
||||
|
||||
unaryOperator "unary operator"
|
||||
|
@ -230,12 +163,12 @@ indexedValue
|
|||
collectionElement
|
||||
= head:atom &('['/'('/'.')
|
||||
tail:(
|
||||
_ '[' _nl arg:expression _nl ']' {return {fn: postOperatorToFunction['[]'], args: [arg]}}
|
||||
/ _ '(' _nl args:array_functionArguments _nl ')' {return {fn: postOperatorToFunction['()'], args: args}}
|
||||
/ '.' arg:$dollarIdentifier {return {fn: postOperatorToFunction['[]'], args: [nodeString(arg)]}}
|
||||
_ '[' _nl arg:expression _nl ']' {return {fn: h.postOperatorToFunction['[]'], args: [arg]}}
|
||||
/ _ '(' _nl args:array_functionArguments _nl ')' {return {fn: h.postOperatorToFunction['()'], args: args}}
|
||||
/ '.' arg:$dollarIdentifier {return {fn: h.postOperatorToFunction['[]'], args: [h.nodeString(arg)]}}
|
||||
)*
|
||||
{ return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(element.fn, [result, ...element.args])
|
||||
return h.makeFunctionCall(element.fn, [result, ...element.args])
|
||||
}, head)}
|
||||
|
||||
array_functionArguments
|
||||
|
@ -261,49 +194,49 @@ dollarIdentifierWithModule 'identifier'
|
|||
final:$dollarIdentifier
|
||||
{ tail.push(final);
|
||||
return tail.reduce(function(result, element) {
|
||||
return makeFunctionCall(postOperatorToFunction['[]'], [result, nodeString(element)])
|
||||
return h.makeFunctionCall(h.postOperatorToFunction['[]'], [result, h.nodeString(element)])
|
||||
}, head)}
|
||||
|
||||
identifier 'identifier'
|
||||
= ([_a-z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
|
||||
= ([_a-z]+[_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
||||
|
||||
unitIdentifier 'identifier'
|
||||
= ([_a-zA-Z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
|
||||
= ([_a-zA-Z]+[_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
||||
|
||||
dollarIdentifier '$identifier'
|
||||
= ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())}
|
||||
= ([\$_a-z]+[\$_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
||||
|
||||
moduleIdentifier 'identifier'
|
||||
= ([A-Z]+[_a-z0-9]i*) {return nodeModuleIdentifier(text())}
|
||||
= ([A-Z]+[_a-z0-9]i*) {return h.nodeModuleIdentifier(text())}
|
||||
|
||||
|
||||
string 'string'
|
||||
= characters:("'" @([^'])* "'") {return nodeString(characters.join(''))}
|
||||
/ characters:('"' @([^"])* '"') {return nodeString(characters.join(''))}
|
||||
= characters:("'" @([^'])* "'") {return h.nodeString(characters.join(''))}
|
||||
/ characters:('"' @([^"])* '"') {return h.nodeString(characters.join(''))}
|
||||
|
||||
number = number:(float / integer) unit:unitIdentifier?
|
||||
{
|
||||
if (unit === null)
|
||||
{ return number }
|
||||
else
|
||||
{ return apply('fromUnit_'+unit.value, number)
|
||||
{ return h.apply('fromUnit_'+unit.value, number)
|
||||
}
|
||||
}
|
||||
|
||||
integer 'integer'
|
||||
= d+ !"\." ![e]i
|
||||
{ return nodeInteger(parseInt(text()))}
|
||||
{ return h.nodeInteger(parseInt(text()))}
|
||||
|
||||
float 'float'
|
||||
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
|
||||
{ return nodeFloat(parseFloat(text()))}
|
||||
{ return h.nodeFloat(parseFloat(text()))}
|
||||
|
||||
floatExponent = [e]i '-'? d+
|
||||
d = [0-9]
|
||||
|
||||
boolean 'boolean'
|
||||
= ('true'/'false')
|
||||
{ return nodeBoolean(text() === 'true')}
|
||||
{ return h.nodeBoolean(text() === 'true')}
|
||||
|
||||
valueConstructor
|
||||
= recordConstructor
|
||||
|
@ -314,15 +247,15 @@ valueConstructor
|
|||
lambda
|
||||
= '{' _nl '|' _nl args:array_parameters _nl '|' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
||||
{ statements.push(finalExpression)
|
||||
return nodeLambda(args, nodeBlock(statements)) }
|
||||
return h.nodeLambda(args, h.nodeBlock(statements)) }
|
||||
/ '{' _nl '|' _nl args:array_parameters _nl '|' _nl finalExpression: expression _nl '}'
|
||||
{ return nodeLambda(args, nodeBlock([finalExpression])) }
|
||||
{ return h.nodeLambda(args, h.nodeBlock([finalExpression])) }
|
||||
|
||||
arrayConstructor 'array'
|
||||
= '[' _nl ']'
|
||||
{ return constructArray([]); }
|
||||
{ return h.constructArray([]); }
|
||||
/ '[' _nl args:array_elements _nl ']'
|
||||
{ return constructArray(args); }
|
||||
{ return h.constructArray(args); }
|
||||
|
||||
array_elements
|
||||
= head:expression tail:(_ ',' _nl @expression)*
|
||||
|
@ -330,7 +263,7 @@ arrayConstructor 'array'
|
|||
|
||||
recordConstructor 'record'
|
||||
= '{' _nl args:array_recordArguments _nl '}'
|
||||
{ return constructRecord(args); }
|
||||
{ return h.constructRecord(args); }
|
||||
|
||||
array_recordArguments
|
||||
= head:keyValuePair tail:(_ ',' _nl @keyValuePair)*
|
||||
|
@ -338,7 +271,7 @@ recordConstructor 'record'
|
|||
|
||||
keyValuePair
|
||||
= key:expression _ ':' _nl value:expression
|
||||
{ return nodeKeyValue(key, value)}
|
||||
{ return h.nodeKeyValue(key, value)}
|
||||
|
||||
// Separators
|
||||
|
||||
|
@ -377,30 +310,30 @@ statementSeparator 'statement separator'
|
|||
noArguments = ('(' _nl ')' )?
|
||||
|
||||
typeIdentifier 'type identifier'
|
||||
= ([a-z]+[_a-z0-9]i*) {return nodeTypeIdentifier(text())}
|
||||
= ([a-z]+[_a-z0-9]i*) {return h.nodeTypeIdentifier(text())}
|
||||
|
||||
typeConstructorIdentifier 'type constructor identifier'
|
||||
= ([A-Z]+[_a-z0-9]i*) {return nodeTypeIdentifier(text())}
|
||||
= ([A-Z]+[_a-z0-9]i*) {return h.nodeTypeIdentifier(text())}
|
||||
|
||||
typeExpression = typePostModifierExpression
|
||||
|
||||
typePostModifierExpression = head:typeOr tail:(_ '$' _nl @typeModifier)*
|
||||
{
|
||||
return tail.reduce((result, element) => {
|
||||
return makeFunctionCall('$_typeModifier_'+element.modifier.value+'_$', [result, ...element.args])
|
||||
return h.makeFunctionCall('$_typeModifier_'+element.modifier.value+'_$', [result, ...element.args])
|
||||
}, head)
|
||||
}
|
||||
|
||||
typeOr = head:typeFunction tail:(_ '|' _nl @typeFunction)*
|
||||
{ return tail.length === 0 ? head : apply('$_typeOr_$', constructArray([head, ...tail])); }
|
||||
{ return tail.length === 0 ? head : h.apply('$_typeOr_$', h.constructArray([head, ...tail])); }
|
||||
|
||||
typeFunction = head:typeModifierExpression tail:(_ '=>' _nl @typeModifierExpression)*
|
||||
{ return tail.length === 0 ? head : apply( '$_typeFunction_$', constructArray([head, ...tail])); }
|
||||
{ return tail.length === 0 ? head : h.apply( '$_typeFunction_$', h.constructArray([head, ...tail])); }
|
||||
|
||||
typeModifierExpression = head:basicType tail:(_ '<-' _nl @typeModifier)*
|
||||
{
|
||||
return tail.reduce((result, element) => {
|
||||
return makeFunctionCall('$_typeModifier_'+element.modifier.value+'_$', [result, ...element.args])
|
||||
return h.makeFunctionCall('$_typeModifier_'+element.modifier.value+'_$', [result, ...element.args])
|
||||
}, head)
|
||||
}
|
||||
|
||||
|
@ -413,10 +346,10 @@ typeModifierExpression = head:basicType tail:(_ '<-' _nl @typeModifier)*
|
|||
basicType = typeConstructor / typeArray / typeRecord / typeInParanthesis / typeIdentifier
|
||||
|
||||
typeArray = '[' _nl elem:typeExpression _nl ']'
|
||||
{return apply('$_typeArray_$', elem)}
|
||||
{return h.apply('$_typeArray_$', elem)}
|
||||
|
||||
typeRecord = '{' _nl elems:array_typeRecordArguments _nl '}'
|
||||
{ return apply('$_typeRecord_$', constructRecord(elems)); }
|
||||
{ return h.apply('$_typeRecord_$', h.constructRecord(elems)); }
|
||||
|
||||
array_typeRecordArguments
|
||||
= head:typeKeyValuePair tail:(_ ',' _nl @typeKeyValuePair)*
|
||||
|
@ -424,22 +357,22 @@ typeRecord = '{' _nl elems:array_typeRecordArguments _nl '}'
|
|||
|
||||
typeKeyValuePair
|
||||
= key:identifier _ ':' _nl value:typeExpression
|
||||
{ return nodeKeyValue(key, value)}
|
||||
{ return h.nodeKeyValue(key, value)}
|
||||
|
||||
typeConstructor
|
||||
= constructor:typeConstructorIdentifier _ '(' _nl args:array_types _nl ')'
|
||||
{ return makeFunctionCall('$_typeConstructor_$', [constructor, constructArray(args)]); }
|
||||
{ return h.makeFunctionCall('$_typeConstructor_$', [constructor, h.constructArray(args)]); }
|
||||
/ constructor:typeConstructorIdentifier _ noArguments
|
||||
{ return makeFunctionCall('$_typeConstructor_$', [constructor, constructArray([])]); }
|
||||
{ return h.makeFunctionCall('$_typeConstructor_$', [constructor, h.constructArray([])]); }
|
||||
|
||||
array_types = head:typeExpression tail:(_ ',' _nl @typeExpression)*
|
||||
{ return [head, ...tail]; }
|
||||
|
||||
typeStatement = typeAliasStatement / typeOfStatement
|
||||
typeAliasStatement = 'type' __nl typeIdentifier:typeIdentifier _nl '=' _nl typeExpression:typeExpression
|
||||
{ return makeFunctionCall('$_typeAlias_$', [typeIdentifier, typeExpression])}
|
||||
{ return h.makeFunctionCall('$_typeAlias_$', [typeIdentifier, typeExpression])}
|
||||
typeOfStatement = identifier:identifier _ ':' _nl typeExpression:typeExpression
|
||||
{ return makeFunctionCall('$_typeOf_$', [identifier, typeExpression])}
|
||||
{ return h.makeFunctionCall('$_typeOf_$', [identifier, typeExpression])}
|
||||
|
||||
typeInParanthesis = '(' _nl typeExpression:typeExpression _nl ')' {return typeExpression}
|
||||
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
import { LocationRange } from "peggy";
|
||||
|
||||
export const toFunction = {
|
||||
"-": "subtract",
|
||||
"->": "pipe",
|
||||
"!=": "unequal",
|
||||
".-": "dotSubtract",
|
||||
".*": "dotMultiply",
|
||||
"./": "dotDivide",
|
||||
".^": "dotPow",
|
||||
".+": "dotAdd",
|
||||
"*": "multiply",
|
||||
"/": "divide",
|
||||
"&&": "and",
|
||||
"^": "pow", // or xor
|
||||
"+": "add",
|
||||
"<": "smaller",
|
||||
"<=": "smallerEq",
|
||||
"==": "equal",
|
||||
">": "larger",
|
||||
">=": "largerEq",
|
||||
"||": "or",
|
||||
to: "credibleIntervalToDistribution",
|
||||
};
|
||||
|
||||
export const unaryToFunction = {
|
||||
"-": "unaryMinus",
|
||||
"!": "not",
|
||||
".-": "unaryDotMinus",
|
||||
};
|
||||
|
||||
export const postOperatorToFunction = {
|
||||
".": "$_atIndex_$",
|
||||
"()": "$$_applyAll_$$",
|
||||
"[]": "$_atIndex_$",
|
||||
};
|
||||
|
||||
type NodeBlock = {
|
||||
type: "Block";
|
||||
statements: AnyPeggyNode[];
|
||||
};
|
||||
|
||||
type NodeExpression = {
|
||||
type: "Expression";
|
||||
nodes: AnyPeggyNode[];
|
||||
};
|
||||
|
||||
type NodeFloat = {
|
||||
type: "Float";
|
||||
value: number;
|
||||
};
|
||||
|
||||
type NodeInteger = {
|
||||
type: "Integer";
|
||||
value: number;
|
||||
};
|
||||
|
||||
type NodeIdentifier = {
|
||||
type: "Identifier";
|
||||
value: string;
|
||||
location: LocationRange;
|
||||
};
|
||||
|
||||
type NodeCallIdentifier = {
|
||||
type: "CallIdentifier";
|
||||
value: string;
|
||||
};
|
||||
|
||||
type NodeLetStatement = {
|
||||
type: "LetStatement";
|
||||
variable: NodeIdentifier;
|
||||
value: AnyPeggyNode;
|
||||
};
|
||||
|
||||
type NodeLambda = {
|
||||
type: "Lambda";
|
||||
args: AnyPeggyNode[];
|
||||
body: AnyPeggyNode;
|
||||
};
|
||||
|
||||
type NodeTernary = {
|
||||
type: "Ternary";
|
||||
condition: AnyPeggyNode;
|
||||
trueExpression: AnyPeggyNode;
|
||||
falseExpression: AnyPeggyNode;
|
||||
};
|
||||
|
||||
type NodeKeyValue = {
|
||||
type: "KeyValue";
|
||||
key: AnyPeggyNode;
|
||||
value: AnyPeggyNode;
|
||||
};
|
||||
|
||||
type NodeString = {
|
||||
type: "String";
|
||||
value: string;
|
||||
location?: LocationRange;
|
||||
};
|
||||
|
||||
type NodeBoolean = {
|
||||
type: "Boolean";
|
||||
value: boolean;
|
||||
};
|
||||
|
||||
export type AnyPeggyNode =
|
||||
| NodeBlock
|
||||
| NodeExpression
|
||||
| NodeFloat
|
||||
| NodeInteger
|
||||
| NodeIdentifier
|
||||
| NodeCallIdentifier
|
||||
| NodeLetStatement
|
||||
| NodeLambda
|
||||
| NodeTernary
|
||||
| NodeKeyValue
|
||||
| NodeString
|
||||
| NodeBoolean;
|
||||
|
||||
export function makeFunctionCall(fn: string, args: AnyPeggyNode[]) {
|
||||
if (fn === "$$_applyAll_$$") {
|
||||
// Any list of values is applied from left to right anyway.
|
||||
// Like in Haskell and Lisp.
|
||||
// So we remove the redundant $$_applyAll_$$.
|
||||
if (args[0].type === "Identifier") {
|
||||
args[0] = {
|
||||
...args[0],
|
||||
type: "CallIdentifier",
|
||||
};
|
||||
}
|
||||
return nodeExpression(args);
|
||||
} else {
|
||||
return nodeExpression([nodeCallIndentifier(fn), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
export function apply(fn: string, arg: AnyPeggyNode) {
|
||||
return makeFunctionCall(fn, [arg]);
|
||||
}
|
||||
export function constructArray(elems: AnyPeggyNode[]) {
|
||||
return apply("$_constructArray_$", nodeExpression(elems));
|
||||
}
|
||||
export function constructRecord(elems: AnyPeggyNode[]) {
|
||||
return apply("$_constructRecord_$", nodeExpression(elems));
|
||||
}
|
||||
|
||||
export function nodeBlock(statements: AnyPeggyNode[]): NodeBlock {
|
||||
return { type: "Block", statements };
|
||||
}
|
||||
export function nodeBoolean(value: boolean): NodeBoolean {
|
||||
return { type: "Boolean", value };
|
||||
}
|
||||
export function nodeCallIndentifier(value: string): NodeCallIdentifier {
|
||||
return { type: "CallIdentifier", value };
|
||||
}
|
||||
export function nodeExpression(args: AnyPeggyNode[]): NodeExpression {
|
||||
return { type: "Expression", nodes: args };
|
||||
}
|
||||
export function nodeFloat(value: number): NodeFloat {
|
||||
return { type: "Float", value };
|
||||
}
|
||||
export function nodeIdentifier(
|
||||
value: string,
|
||||
location: LocationRange
|
||||
): NodeIdentifier {
|
||||
return { type: "Identifier", value, location };
|
||||
}
|
||||
export function nodeInteger(value: number): NodeInteger {
|
||||
return { type: "Integer", value };
|
||||
}
|
||||
export function nodeKeyValue(
|
||||
key: AnyPeggyNode,
|
||||
value: AnyPeggyNode
|
||||
): NodeKeyValue {
|
||||
if (key.type === "Identifier") {
|
||||
key = {
|
||||
...key,
|
||||
type: "String",
|
||||
};
|
||||
}
|
||||
return { type: "KeyValue", key, value };
|
||||
}
|
||||
export function nodeLambda(
|
||||
args: AnyPeggyNode[],
|
||||
body: AnyPeggyNode
|
||||
): NodeLambda {
|
||||
return { type: "Lambda", args, body };
|
||||
}
|
||||
export function nodeLetStatement(
|
||||
variable: NodeIdentifier,
|
||||
value: AnyPeggyNode
|
||||
): NodeLetStatement {
|
||||
return { type: "LetStatement", variable, value };
|
||||
}
|
||||
export function nodeModuleIdentifier(value: string) {
|
||||
return { type: "ModuleIdentifier", value };
|
||||
}
|
||||
export function nodeString(value: string): NodeString {
|
||||
return { type: "String", value };
|
||||
}
|
||||
export function nodeTernary(
|
||||
condition: AnyPeggyNode,
|
||||
trueExpression: AnyPeggyNode,
|
||||
falseExpression: AnyPeggyNode
|
||||
): NodeTernary {
|
||||
return {
|
||||
type: "Ternary",
|
||||
condition,
|
||||
trueExpression,
|
||||
falseExpression,
|
||||
};
|
||||
}
|
||||
|
||||
export function nodeTypeIdentifier(typeValue: string) {
|
||||
return { type: "TypeIdentifier", value: typeValue };
|
||||
}
|
|
@ -4,6 +4,7 @@ import * as vscode from "vscode";
|
|||
import { startClient, stopClient } from "./client";
|
||||
|
||||
import { SquiggleEditorProvider } from "./editor";
|
||||
import { registerSemanticHighlight } from "./highlight";
|
||||
import { registerPreviewCommand } from "./preview";
|
||||
|
||||
// this method is called when your extension is activated
|
||||
|
@ -13,6 +14,8 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
|
||||
registerPreviewCommand(context);
|
||||
|
||||
registerSemanticHighlight();
|
||||
|
||||
startClient(context);
|
||||
}
|
||||
|
||||
|
|
96
packages/vscode-ext/client/src/highlight.ts
Normal file
96
packages/vscode-ext/client/src/highlight.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
import * as vscode from "vscode";
|
||||
|
||||
import { parse } from "@quri/squiggle-lang";
|
||||
import { AnyPeggyNode } from "@quri/squiggle-lang/dist/src/rescript/Reducer/Reducer_Peggy/helpers";
|
||||
|
||||
const tokenTypes = ["enum", "function", "variable", "property"];
|
||||
const tokenModifiers = ["declaration", "documentation"];
|
||||
const legend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers);
|
||||
|
||||
const convertRange = (
|
||||
range: Extract<AnyPeggyNode, { type: "Identifier" }>["location"]
|
||||
) =>
|
||||
new vscode.Range(
|
||||
new vscode.Position(range.start.line - 1, range.start.column - 1),
|
||||
new vscode.Position(range.end.line - 1, range.end.column - 1)
|
||||
);
|
||||
|
||||
const populateTokensBuilder = (
|
||||
tokensBuilder: vscode.SemanticTokensBuilder,
|
||||
node: AnyPeggyNode
|
||||
// bindings: { [key: string]: boolean }
|
||||
) => {
|
||||
switch (node.type) {
|
||||
case "Expression":
|
||||
for (const child of node.nodes) {
|
||||
populateTokensBuilder(tokensBuilder, child);
|
||||
}
|
||||
break;
|
||||
case "Block":
|
||||
for (const child of node.statements) {
|
||||
populateTokensBuilder(tokensBuilder, child);
|
||||
}
|
||||
break;
|
||||
case "LetStatement":
|
||||
tokensBuilder.push(
|
||||
convertRange(node.variable.location),
|
||||
node.value.type === "Lambda" ? "function" : "variable",
|
||||
["declaration"]
|
||||
);
|
||||
populateTokensBuilder(tokensBuilder, node.value);
|
||||
break;
|
||||
case "Lambda":
|
||||
for (const arg of node.args) {
|
||||
populateTokensBuilder(tokensBuilder, arg);
|
||||
}
|
||||
populateTokensBuilder(tokensBuilder, node.body);
|
||||
break;
|
||||
case "Ternary":
|
||||
populateTokensBuilder(tokensBuilder, node.condition);
|
||||
populateTokensBuilder(tokensBuilder, node.trueExpression);
|
||||
populateTokensBuilder(tokensBuilder, node.falseExpression);
|
||||
break;
|
||||
case "KeyValue":
|
||||
if (node.key.type === "String" && node.key.location) {
|
||||
tokensBuilder.push(convertRange(node.key.location), "property", [
|
||||
"declaration",
|
||||
]);
|
||||
} else {
|
||||
populateTokensBuilder(tokensBuilder, node.key);
|
||||
}
|
||||
populateTokensBuilder(tokensBuilder, node.value);
|
||||
break;
|
||||
case "Identifier":
|
||||
tokensBuilder.push(convertRange(node.location), "variable");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export const registerSemanticHighlight = () => {
|
||||
const provider: vscode.DocumentSemanticTokensProvider = {
|
||||
provideDocumentSemanticTokens(
|
||||
document: vscode.TextDocument
|
||||
): vscode.ProviderResult<vscode.SemanticTokens> {
|
||||
const parseResult = parse(document.getText());
|
||||
|
||||
const tokensBuilder = new vscode.SemanticTokensBuilder(legend);
|
||||
if (parseResult.tag === "Ok") {
|
||||
populateTokensBuilder(
|
||||
tokensBuilder,
|
||||
parseResult.value
|
||||
// {}
|
||||
);
|
||||
}
|
||||
|
||||
return tokensBuilder.build();
|
||||
},
|
||||
};
|
||||
|
||||
const selector = { language: "squiggle", scheme: "file" };
|
||||
|
||||
vscode.languages.registerDocumentSemanticTokensProvider(
|
||||
selector,
|
||||
provider,
|
||||
legend
|
||||
);
|
||||
};
|
|
@ -13,6 +13,10 @@ import { parse } from "@quri/squiggle-lang";
|
|||
|
||||
import { TextDocument } from "vscode-languageserver-textdocument";
|
||||
|
||||
// Documentation:
|
||||
// - https://code.visualstudio.com/api/language-extensions/language-server-extension-guide
|
||||
// - https://microsoft.github.io/language-server-protocol/specifications/specification-current
|
||||
|
||||
// Create a connection for the server, using Node's IPC as a transport.
|
||||
// Also include all preview / proposed LSP features.
|
||||
let connection = createConnection(ProposedFeatures.all);
|
||||
|
@ -23,17 +27,7 @@ documents.onDidChangeContent((change) => {
|
|||
validateSquiggleDocument(change.document);
|
||||
});
|
||||
|
||||
let hasDiagnosticRelatedInformationCapability = false;
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
const capabilities = params.capabilities;
|
||||
|
||||
hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
|
|
32
yarn.lock
32
yarn.lock
|
@ -1852,10 +1852,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324"
|
||||
integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==
|
||||
|
||||
"@hookform/resolvers@^2.9.1":
|
||||
version "2.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.1.tgz#59121e38d8fc95d2fd1f41c9631393cd21e10b65"
|
||||
integrity sha512-80lyFFcExEB7A09PFnl8k7A3obQyDF6MyO/FThtwetk+MTedYMs08Aqf7mgWnOawFGyz5QF+TZXJSYiIZW2tEg==
|
||||
"@hookform/resolvers@^2.9.3":
|
||||
version "2.9.3"
|
||||
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.3.tgz#13f6934cfe705e24fac094da377e0621adcfc424"
|
||||
integrity sha512-Eqc/qgjq0VX/TU0a5D2O+yR/kAKflnjaVlYFC1wI2qBm/sgjKTXxv27ijLwHUoHPIF+MUkB/VuQqHJ5DcmbCww==
|
||||
|
||||
"@humanwhocodes/config-array@^0.9.2":
|
||||
version "0.9.5"
|
||||
|
@ -8713,10 +8713,10 @@ fast-check@^2.17.0:
|
|||
dependencies:
|
||||
pure-rand "^5.0.1"
|
||||
|
||||
fast-check@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.0.0.tgz#6ea28d584e9ffebd7ecd0f06c163cd6af593ecfd"
|
||||
integrity sha512-uujtrFJEQQqnIMO52ARwzPcuV4omiL1OJBUBLE9WnNFeu0A97sREXDOmCIHY+Z6KLVcemUf09rWr0q0Xy/Y/Ew==
|
||||
fast-check@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.0.1.tgz#b9e7b57c4643a4e62893aca85e21c270591d0eac"
|
||||
integrity sha512-AriFDYpYVOBynpPZq/quxSLumFOo2hPB2H5Nz2vc1QlNfjOaA62zX8USNXcOY5nwKHEq7lZ84dG9M1W+LAND1g==
|
||||
dependencies:
|
||||
pure-rand "^5.0.1"
|
||||
|
||||
|
@ -11914,10 +11914,10 @@ markdown-it@^8.3.1:
|
|||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
mathjs@^10.6.0:
|
||||
version "10.6.1"
|
||||
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.6.1.tgz#95b34178eed65cbf7a63d35c468ad3ac912f7ddf"
|
||||
integrity sha512-8iZp6uUKKBoCFoUHze9ydsrSji9/IOEzMhwURyoQXaLL1+ILEZnraw4KzZnUBt/XN6lPJPV+7JO94oil3AmosQ==
|
||||
mathjs@^10.6.3:
|
||||
version "10.6.3"
|
||||
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.6.3.tgz#12802d9218cea82a9ae49a9824997798ac128e75"
|
||||
integrity sha512-3yYrc6z0kcQfC2ERwLIIq+BjvmUDO+RdALxNyuq8kupj/B1SPYuLxxPjPWFz3F20+mPRTn/Je1Tjr1t/NfBorA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.18.3"
|
||||
complex.js "^2.1.1"
|
||||
|
@ -14523,10 +14523,10 @@ react-helmet-async@*, react-helmet-async@^1.3.0:
|
|||
react-fast-compare "^3.2.0"
|
||||
shallowequal "^1.1.0"
|
||||
|
||||
react-hook-form@^7.32.2:
|
||||
version "7.32.2"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.32.2.tgz#58ec2ab0239ce97969baa2faa03ced13fae913ac"
|
||||
integrity sha512-F1A6n762xaRhvtQH5SkQQhMr19cCkHZYesTcKJJeNmrphiZp/cYFTIzC05FnQry0SspM54oPJ9tXFXlzya8VNQ==
|
||||
react-hook-form@^7.33.0:
|
||||
version "7.33.0"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.33.0.tgz#44a87ddd630f00ebeb0f15aa978f69ca74b8a77b"
|
||||
integrity sha512-h8XoeUHQs1Snx1s/sSvM+eVTSKkWQt8TcrbL+3/Rt5gugxpy4ueL5ZZkubffyNpUyyTz0qM0kwOi2c+JgGTjLA==
|
||||
|
||||
react-inspector@^5.1.0:
|
||||
version "5.1.1"
|
||||
|
|
Loading…
Reference in New Issue
Block a user