Merge remote-tracking branch 'origin/develop' into scoring-cleanup-three
This commit is contained in:
commit
9225710d2d
|
@ -5,14 +5,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^1.6.5",
|
"@headlessui/react": "^1.6.5",
|
||||||
"@heroicons/react": "^1.0.6",
|
"@heroicons/react": "^1.0.6",
|
||||||
"@hookform/resolvers": "^2.9.1",
|
"@hookform/resolvers": "^2.9.3",
|
||||||
"@quri/squiggle-lang": "^0.2.8",
|
"@quri/squiggle-lang": "^0.2.8",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-ace": "^10.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-use": "^17.4.0",
|
||||||
"react-vega": "^7.5.1",
|
"react-vega": "^7.5.1",
|
||||||
"vega": "^5.22.1",
|
"vega": "^5.22.1",
|
||||||
|
|
|
@ -244,7 +244,28 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
case "module": {
|
case "module": {
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Module" showTypes={showTypes}>
|
<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>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
1
packages/squiggle-lang/.gitignore
vendored
1
packages/squiggle-lang/.gitignore
vendored
|
@ -22,3 +22,4 @@ _coverage
|
||||||
coverage
|
coverage
|
||||||
.nyc_output/
|
.nyc_output/
|
||||||
src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
||||||
|
src/rescript/Reducer/Reducer_Peggy/helpers.js
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
"peggy": "peggy --cache",
|
"peggy": "peggy --cache",
|
||||||
"rescript": "rescript",
|
"rescript": "rescript",
|
||||||
"build": "yarn build:peggy && yarn build:rescript && yarn build:typescript",
|
"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:rescript": "rescript build -with-deps",
|
||||||
"build:typescript": "tsc",
|
"build:typescript": "tsc",
|
||||||
"bundle": "webpack",
|
"bundle": "webpack",
|
||||||
|
@ -41,7 +42,7 @@
|
||||||
"@stdlib/stats": "^0.0.13",
|
"@stdlib/stats": "^0.0.13",
|
||||||
"jstat": "^1.9.5",
|
"jstat": "^1.9.5",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mathjs": "^10.6.0",
|
"mathjs": "^10.6.3",
|
||||||
"pdfast": "^0.2.0"
|
"pdfast": "^0.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -52,7 +53,7 @@
|
||||||
"bisect_ppx": "^2.7.1",
|
"bisect_ppx": "^2.7.1",
|
||||||
"chalk": "^5.0.1",
|
"chalk": "^5.0.1",
|
||||||
"codecov": "^3.8.3",
|
"codecov": "^3.8.3",
|
||||||
"fast-check": "^3.0.0",
|
"fast-check": "^3.0.1",
|
||||||
"gentype": "^4.4.0",
|
"gentype": "^4.4.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"moduleserve": "^0.9.1",
|
"moduleserve": "^0.9.1",
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
evaluatePartialUsingExternalBindings,
|
evaluatePartialUsingExternalBindings,
|
||||||
evaluateUsingOptions,
|
evaluateUsingOptions,
|
||||||
foreignFunctionInterface,
|
foreignFunctionInterface,
|
||||||
parse as parseRescript,
|
|
||||||
} from "../rescript/TypescriptInterface.gen";
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
export {
|
export {
|
||||||
makeSampleSetDist,
|
makeSampleSetDist,
|
||||||
|
@ -32,12 +31,14 @@ import {
|
||||||
convertRawToTypescript,
|
convertRawToTypescript,
|
||||||
lambdaValue,
|
lambdaValue,
|
||||||
} from "./rescript_interop";
|
} from "./rescript_interop";
|
||||||
import { Ok, result, resultMap, tag, tagged } from "./types";
|
import { result, resultMap, tag, tagged } from "./types";
|
||||||
import { Distribution, shape } from "./distribution";
|
import { Distribution, shape } from "./distribution";
|
||||||
|
|
||||||
export { Distribution, resultMap, defaultEnvironment };
|
export { Distribution, resultMap, defaultEnvironment };
|
||||||
export type { result, shape, environment, lambdaValue, squiggleExpression };
|
export type { result, shape, environment, lambdaValue, squiggleExpression };
|
||||||
|
|
||||||
|
export { parse } from "./parse";
|
||||||
|
|
||||||
export let defaultSamplingInputs: environment = {
|
export let defaultSamplingInputs: environment = {
|
||||||
sampleCount: 10000,
|
sampleCount: 10000,
|
||||||
xyPointLength: 10000,
|
xyPointLength: 10000,
|
||||||
|
@ -59,23 +60,6 @@ export function run(
|
||||||
return resultMap(res, (x) => createTsExport(x, e));
|
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
|
// Run Partial. A partial is a block of code that doesn't return a value
|
||||||
export function runPartial(
|
export function runPartial(
|
||||||
squiggleString: string,
|
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
|
// Try in https://peggyjs.org/online
|
||||||
|
|
||||||
{{
|
{{
|
||||||
var toFunction = {
|
const h = require('./helpers');
|
||||||
'-': '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}}
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
start
|
start
|
||||||
|
@ -80,21 +13,21 @@ zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
|
||||||
outerBlock
|
outerBlock
|
||||||
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
||||||
{ if (finalExpression != null) { statements.push(finalExpression) }
|
{ if (finalExpression != null) { statements.push(finalExpression) }
|
||||||
return nodeBlock(statements) }
|
return h.nodeBlock(statements) }
|
||||||
/ finalExpression: expression
|
/ finalExpression: expression
|
||||||
{ return nodeBlock([finalExpression])}
|
{ return h.nodeBlock([finalExpression])}
|
||||||
|
|
||||||
innerBlockOrExpression
|
innerBlockOrExpression
|
||||||
= quotedInnerBlock
|
= quotedInnerBlock
|
||||||
/ finalExpression: expression
|
/ finalExpression: expression
|
||||||
{ return nodeBlock([finalExpression])}
|
{ return h.nodeBlock([finalExpression])}
|
||||||
|
|
||||||
quotedInnerBlock
|
quotedInnerBlock
|
||||||
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
||||||
{ statements.push(finalExpression)
|
{ statements.push(finalExpression)
|
||||||
return nodeBlock(statements) }
|
return h.nodeBlock(statements) }
|
||||||
/ '{' _nl finalExpression: expression _nl '}'
|
/ '{' _nl finalExpression: expression _nl '}'
|
||||||
{ return nodeBlock([finalExpression]) }
|
{ return h.nodeBlock([finalExpression]) }
|
||||||
|
|
||||||
array_statements
|
array_statements
|
||||||
= head:statement tail:(statementSeparator @array_statements )
|
= head:statement tail:(statementSeparator @array_statements )
|
||||||
|
@ -109,12 +42,12 @@ statement
|
||||||
|
|
||||||
letStatement
|
letStatement
|
||||||
= variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
|
= variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
|
||||||
{ return nodeLetStatment(variable, value) }
|
{ return h.nodeLetStatement(variable, value) }
|
||||||
|
|
||||||
defunStatement
|
defunStatement
|
||||||
= variable:identifier '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression
|
= variable:identifier '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression
|
||||||
{ var value = nodeLambda(args, body)
|
{ var value = h.nodeLambda(args, body)
|
||||||
return nodeLetStatment(variable, value) }
|
return h.nodeLetStatement(variable, value) }
|
||||||
|
|
||||||
assignmentOp "assignment" = '='
|
assignmentOp "assignment" = '='
|
||||||
|
|
||||||
|
@ -128,16 +61,16 @@ ifthenelse
|
||||||
= 'if' __nl condition:logicalAdditive
|
= 'if' __nl condition:logicalAdditive
|
||||||
__nl 'then' __nl trueExpression:innerBlockOrExpression
|
__nl 'then' __nl trueExpression:innerBlockOrExpression
|
||||||
__nl 'else' __nl falseExpression:(ifthenelse/innerBlockOrExpression)
|
__nl 'else' __nl falseExpression:(ifthenelse/innerBlockOrExpression)
|
||||||
{ return nodeTernary(condition, trueExpression, falseExpression) }
|
{ return h.nodeTernary(condition, trueExpression, falseExpression) }
|
||||||
|
|
||||||
ternary
|
ternary
|
||||||
= condition:logicalAdditive _ '?' _nl trueExpression:logicalAdditive _ ':' _nl falseExpression:(ternary/logicalAdditive)
|
= condition:logicalAdditive _ '?' _nl trueExpression:logicalAdditive _ ':' _nl falseExpression:(ternary/logicalAdditive)
|
||||||
{ return nodeTernary(condition, trueExpression, falseExpression) }
|
{ return h.nodeTernary(condition, trueExpression, falseExpression) }
|
||||||
|
|
||||||
logicalAdditive
|
logicalAdditive
|
||||||
= head:logicalMultiplicative tail:(_ operator:logicalAdditiveOp _nl arg:logicalMultiplicative {return {operator: operator, right: arg}})*
|
= head:logicalMultiplicative tail:(_ operator:logicalAdditiveOp _nl arg:logicalMultiplicative {return {operator: operator, right: arg}})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ 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)}
|
}, head)}
|
||||||
|
|
||||||
logicalAdditiveOp "operator" = '||'
|
logicalAdditiveOp "operator" = '||'
|
||||||
|
@ -146,21 +79,21 @@ logicalAdditive
|
||||||
logicalMultiplicative
|
logicalMultiplicative
|
||||||
= head:equality tail:(_ operator:logicalMultiplicativeOp _nl arg:equality {return {operator: operator, right: arg}})*
|
= head:equality tail:(_ operator:logicalMultiplicativeOp _nl arg:equality {return {operator: operator, right: arg}})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ 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)}
|
}, head)}
|
||||||
|
|
||||||
logicalMultiplicativeOp "operator" = '&&'
|
logicalMultiplicativeOp "operator" = '&&'
|
||||||
|
|
||||||
equality
|
equality
|
||||||
= left:relational _ operator:equalityOp _nl right:relational
|
= left:relational _ operator:equalityOp _nl right:relational
|
||||||
{ return makeFunctionCall(toFunction[operator], [left, right])}
|
{ return h.makeFunctionCall(h.toFunction[operator], [left, right])}
|
||||||
/ relational
|
/ relational
|
||||||
|
|
||||||
equalityOp "operator" = '=='/'!='
|
equalityOp "operator" = '=='/'!='
|
||||||
|
|
||||||
relational
|
relational
|
||||||
= left:additive _ operator:relationalOp _nl right:additive
|
= left:additive _ operator:relationalOp _nl right:additive
|
||||||
{ return makeFunctionCall(toFunction[operator], [left, right])}
|
{ return h.makeFunctionCall(h.toFunction[operator], [left, right])}
|
||||||
/ additive
|
/ additive
|
||||||
|
|
||||||
relationalOp "operator" = '<='/'<'/'>='/'>'
|
relationalOp "operator" = '<='/'<'/'>='/'>'
|
||||||
|
@ -168,7 +101,7 @@ relational
|
||||||
additive
|
additive
|
||||||
= head:multiplicative tail:(_ operator:additiveOp _nl arg:multiplicative {return {operator: operator, right: arg}})*
|
= head:multiplicative tail:(_ operator:additiveOp _nl arg:multiplicative {return {operator: operator, right: arg}})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ 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)}
|
}, head)}
|
||||||
|
|
||||||
additiveOp "operator" = '+' / '-' / '.+' / '.-'
|
additiveOp "operator" = '+' / '-' / '.+' / '.-'
|
||||||
|
@ -176,7 +109,7 @@ additive
|
||||||
multiplicative
|
multiplicative
|
||||||
= head:power tail:(_ operator:multiplicativeOp _nl arg:power {return {operator: operator, right: arg}})*
|
= head:power tail:(_ operator:multiplicativeOp _nl arg:power {return {operator: operator, right: arg}})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ 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)}
|
}, head)}
|
||||||
|
|
||||||
multiplicativeOp "operator" = '*' / '/' / '.*' / './'
|
multiplicativeOp "operator" = '*' / '/' / '.*' / './'
|
||||||
|
@ -184,7 +117,7 @@ multiplicative
|
||||||
power
|
power
|
||||||
= head:credibleInterval tail:(_ operator:powerOp _nl arg:credibleInterval {return {operator: operator, right: arg}})*
|
= head:credibleInterval tail:(_ operator:powerOp _nl arg:credibleInterval {return {operator: operator, right: arg}})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ 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)}
|
}, head)}
|
||||||
|
|
||||||
powerOp "operator" = '^' / '.^'
|
powerOp "operator" = '^' / '.^'
|
||||||
|
@ -192,7 +125,7 @@ power
|
||||||
credibleInterval
|
credibleInterval
|
||||||
= head:chainFunctionCall tail:(__ operator:credibleIntervalOp __nl arg:chainFunctionCall {return {operator: operator, right: arg}})*
|
= head:chainFunctionCall tail:(__ operator:credibleIntervalOp __nl arg:chainFunctionCall {return {operator: operator, right: arg}})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ 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)}
|
}, head)}
|
||||||
|
|
||||||
credibleIntervalOp "operator" = 'to'
|
credibleIntervalOp "operator" = 'to'
|
||||||
|
@ -200,7 +133,7 @@ credibleInterval
|
||||||
chainFunctionCall
|
chainFunctionCall
|
||||||
= head:unary tail:(_ ('->'/'|>') _nl chained:chainedFunction {return chained})*
|
= head:unary tail:(_ ('->'/'|>') _nl chained:chainedFunction {return chained})*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ return tail.reduce(function(result, element) {
|
||||||
return makeFunctionCall(element.fnName, [result, ...element.args])
|
return h.makeFunctionCall(element.fnName, [result, ...element.args])
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
chainedFunction
|
chainedFunction
|
||||||
|
@ -215,7 +148,7 @@ chainFunctionCall
|
||||||
|
|
||||||
unary
|
unary
|
||||||
= unaryOperator:unaryOperator _nl right:(unary/postOperator)
|
= unaryOperator:unaryOperator _nl right:(unary/postOperator)
|
||||||
{ return apply(unaryToFunction[unaryOperator], right)}
|
{ return h.apply(h.unaryToFunction[unaryOperator], right)}
|
||||||
/ postOperator
|
/ postOperator
|
||||||
|
|
||||||
unaryOperator "unary operator"
|
unaryOperator "unary operator"
|
||||||
|
@ -230,12 +163,12 @@ indexedValue
|
||||||
collectionElement
|
collectionElement
|
||||||
= head:atom &('['/'('/'.')
|
= head:atom &('['/'('/'.')
|
||||||
tail:(
|
tail:(
|
||||||
_ '[' _nl arg:expression _nl ']' {return {fn: postOperatorToFunction['[]'], args: [arg]}}
|
_ '[' _nl arg:expression _nl ']' {return {fn: h.postOperatorToFunction['[]'], args: [arg]}}
|
||||||
/ _ '(' _nl args:array_functionArguments _nl ')' {return {fn: postOperatorToFunction['()'], args: args}}
|
/ _ '(' _nl args:array_functionArguments _nl ')' {return {fn: h.postOperatorToFunction['()'], args: args}}
|
||||||
/ '.' arg:$dollarIdentifier {return {fn: postOperatorToFunction['[]'], args: [nodeString(arg)]}}
|
/ '.' arg:$dollarIdentifier {return {fn: h.postOperatorToFunction['[]'], args: [h.nodeString(arg)]}}
|
||||||
)*
|
)*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ return tail.reduce(function(result, element) {
|
||||||
return makeFunctionCall(element.fn, [result, ...element.args])
|
return h.makeFunctionCall(element.fn, [result, ...element.args])
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
array_functionArguments
|
array_functionArguments
|
||||||
|
@ -261,49 +194,49 @@ dollarIdentifierWithModule 'identifier'
|
||||||
final:$dollarIdentifier
|
final:$dollarIdentifier
|
||||||
{ tail.push(final);
|
{ tail.push(final);
|
||||||
return tail.reduce(function(result, element) {
|
return tail.reduce(function(result, element) {
|
||||||
return makeFunctionCall(postOperatorToFunction['[]'], [result, nodeString(element)])
|
return h.makeFunctionCall(h.postOperatorToFunction['[]'], [result, h.nodeString(element)])
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
identifier 'identifier'
|
identifier 'identifier'
|
||||||
= ([_a-z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
|
= ([_a-z]+[_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
||||||
|
|
||||||
unitIdentifier 'identifier'
|
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'
|
dollarIdentifier '$identifier'
|
||||||
= ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())}
|
= ([\$_a-z]+[\$_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
||||||
|
|
||||||
moduleIdentifier 'identifier'
|
moduleIdentifier 'identifier'
|
||||||
= ([A-Z]+[_a-z0-9]i*) {return nodeModuleIdentifier(text())}
|
= ([A-Z]+[_a-z0-9]i*) {return h.nodeModuleIdentifier(text())}
|
||||||
|
|
||||||
|
|
||||||
string 'string'
|
string 'string'
|
||||||
= characters:("'" @([^'])* "'") {return nodeString(characters.join(''))}
|
= characters:("'" @([^'])* "'") {return h.nodeString(characters.join(''))}
|
||||||
/ characters:('"' @([^"])* '"') {return nodeString(characters.join(''))}
|
/ characters:('"' @([^"])* '"') {return h.nodeString(characters.join(''))}
|
||||||
|
|
||||||
number = number:(float / integer) unit:unitIdentifier?
|
number = number:(float / integer) unit:unitIdentifier?
|
||||||
{
|
{
|
||||||
if (unit === null)
|
if (unit === null)
|
||||||
{ return number }
|
{ return number }
|
||||||
else
|
else
|
||||||
{ return apply('fromUnit_'+unit.value, number)
|
{ return h.apply('fromUnit_'+unit.value, number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
integer 'integer'
|
integer 'integer'
|
||||||
= d+ !"\." ![e]i
|
= d+ !"\." ![e]i
|
||||||
{ return nodeInteger(parseInt(text()))}
|
{ return h.nodeInteger(parseInt(text()))}
|
||||||
|
|
||||||
float 'float'
|
float 'float'
|
||||||
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
|
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
|
||||||
{ return nodeFloat(parseFloat(text()))}
|
{ return h.nodeFloat(parseFloat(text()))}
|
||||||
|
|
||||||
floatExponent = [e]i '-'? d+
|
floatExponent = [e]i '-'? d+
|
||||||
d = [0-9]
|
d = [0-9]
|
||||||
|
|
||||||
boolean 'boolean'
|
boolean 'boolean'
|
||||||
= ('true'/'false')
|
= ('true'/'false')
|
||||||
{ return nodeBoolean(text() === 'true')}
|
{ return h.nodeBoolean(text() === 'true')}
|
||||||
|
|
||||||
valueConstructor
|
valueConstructor
|
||||||
= recordConstructor
|
= recordConstructor
|
||||||
|
@ -314,15 +247,15 @@ valueConstructor
|
||||||
lambda
|
lambda
|
||||||
= '{' _nl '|' _nl args:array_parameters _nl '|' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
= '{' _nl '|' _nl args:array_parameters _nl '|' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
||||||
{ statements.push(finalExpression)
|
{ 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 '}'
|
/ '{' _nl '|' _nl args:array_parameters _nl '|' _nl finalExpression: expression _nl '}'
|
||||||
{ return nodeLambda(args, nodeBlock([finalExpression])) }
|
{ return h.nodeLambda(args, h.nodeBlock([finalExpression])) }
|
||||||
|
|
||||||
arrayConstructor 'array'
|
arrayConstructor 'array'
|
||||||
= '[' _nl ']'
|
= '[' _nl ']'
|
||||||
{ return constructArray([]); }
|
{ return h.constructArray([]); }
|
||||||
/ '[' _nl args:array_elements _nl ']'
|
/ '[' _nl args:array_elements _nl ']'
|
||||||
{ return constructArray(args); }
|
{ return h.constructArray(args); }
|
||||||
|
|
||||||
array_elements
|
array_elements
|
||||||
= head:expression tail:(_ ',' _nl @expression)*
|
= head:expression tail:(_ ',' _nl @expression)*
|
||||||
|
@ -330,7 +263,7 @@ arrayConstructor 'array'
|
||||||
|
|
||||||
recordConstructor 'record'
|
recordConstructor 'record'
|
||||||
= '{' _nl args:array_recordArguments _nl '}'
|
= '{' _nl args:array_recordArguments _nl '}'
|
||||||
{ return constructRecord(args); }
|
{ return h.constructRecord(args); }
|
||||||
|
|
||||||
array_recordArguments
|
array_recordArguments
|
||||||
= head:keyValuePair tail:(_ ',' _nl @keyValuePair)*
|
= head:keyValuePair tail:(_ ',' _nl @keyValuePair)*
|
||||||
|
@ -338,7 +271,7 @@ recordConstructor 'record'
|
||||||
|
|
||||||
keyValuePair
|
keyValuePair
|
||||||
= key:expression _ ':' _nl value:expression
|
= key:expression _ ':' _nl value:expression
|
||||||
{ return nodeKeyValue(key, value)}
|
{ return h.nodeKeyValue(key, value)}
|
||||||
|
|
||||||
// Separators
|
// Separators
|
||||||
|
|
||||||
|
@ -377,30 +310,30 @@ statementSeparator 'statement separator'
|
||||||
noArguments = ('(' _nl ')' )?
|
noArguments = ('(' _nl ')' )?
|
||||||
|
|
||||||
typeIdentifier 'type identifier'
|
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'
|
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
|
typeExpression = typePostModifierExpression
|
||||||
|
|
||||||
typePostModifierExpression = head:typeOr tail:(_ '$' _nl @typeModifier)*
|
typePostModifierExpression = head:typeOr tail:(_ '$' _nl @typeModifier)*
|
||||||
{
|
{
|
||||||
return tail.reduce((result, element) => {
|
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)
|
}, head)
|
||||||
}
|
}
|
||||||
|
|
||||||
typeOr = head:typeFunction tail:(_ '|' _nl @typeFunction)*
|
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)*
|
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)*
|
typeModifierExpression = head:basicType tail:(_ '<-' _nl @typeModifier)*
|
||||||
{
|
{
|
||||||
return tail.reduce((result, element) => {
|
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)
|
}, head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,10 +346,10 @@ typeModifierExpression = head:basicType tail:(_ '<-' _nl @typeModifier)*
|
||||||
basicType = typeConstructor / typeArray / typeRecord / typeInParanthesis / typeIdentifier
|
basicType = typeConstructor / typeArray / typeRecord / typeInParanthesis / typeIdentifier
|
||||||
|
|
||||||
typeArray = '[' _nl elem:typeExpression _nl ']'
|
typeArray = '[' _nl elem:typeExpression _nl ']'
|
||||||
{return apply('$_typeArray_$', elem)}
|
{return h.apply('$_typeArray_$', elem)}
|
||||||
|
|
||||||
typeRecord = '{' _nl elems:array_typeRecordArguments _nl '}'
|
typeRecord = '{' _nl elems:array_typeRecordArguments _nl '}'
|
||||||
{ return apply('$_typeRecord_$', constructRecord(elems)); }
|
{ return h.apply('$_typeRecord_$', h.constructRecord(elems)); }
|
||||||
|
|
||||||
array_typeRecordArguments
|
array_typeRecordArguments
|
||||||
= head:typeKeyValuePair tail:(_ ',' _nl @typeKeyValuePair)*
|
= head:typeKeyValuePair tail:(_ ',' _nl @typeKeyValuePair)*
|
||||||
|
@ -424,22 +357,22 @@ typeRecord = '{' _nl elems:array_typeRecordArguments _nl '}'
|
||||||
|
|
||||||
typeKeyValuePair
|
typeKeyValuePair
|
||||||
= key:identifier _ ':' _nl value:typeExpression
|
= key:identifier _ ':' _nl value:typeExpression
|
||||||
{ return nodeKeyValue(key, value)}
|
{ return h.nodeKeyValue(key, value)}
|
||||||
|
|
||||||
typeConstructor
|
typeConstructor
|
||||||
= constructor:typeConstructorIdentifier _ '(' _nl args:array_types _nl ')'
|
= constructor:typeConstructorIdentifier _ '(' _nl args:array_types _nl ')'
|
||||||
{ return makeFunctionCall('$_typeConstructor_$', [constructor, constructArray(args)]); }
|
{ return h.makeFunctionCall('$_typeConstructor_$', [constructor, h.constructArray(args)]); }
|
||||||
/ constructor:typeConstructorIdentifier _ noArguments
|
/ constructor:typeConstructorIdentifier _ noArguments
|
||||||
{ return makeFunctionCall('$_typeConstructor_$', [constructor, constructArray([])]); }
|
{ return h.makeFunctionCall('$_typeConstructor_$', [constructor, h.constructArray([])]); }
|
||||||
|
|
||||||
array_types = head:typeExpression tail:(_ ',' _nl @typeExpression)*
|
array_types = head:typeExpression tail:(_ ',' _nl @typeExpression)*
|
||||||
{ return [head, ...tail]; }
|
{ return [head, ...tail]; }
|
||||||
|
|
||||||
typeStatement = typeAliasStatement / typeOfStatement
|
typeStatement = typeAliasStatement / typeOfStatement
|
||||||
typeAliasStatement = 'type' __nl typeIdentifier:typeIdentifier _nl '=' _nl typeExpression:typeExpression
|
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
|
typeOfStatement = identifier:identifier _ ':' _nl typeExpression:typeExpression
|
||||||
{ return makeFunctionCall('$_typeOf_$', [identifier, typeExpression])}
|
{ return h.makeFunctionCall('$_typeOf_$', [identifier, typeExpression])}
|
||||||
|
|
||||||
typeInParanthesis = '(' _nl typeExpression:typeExpression _nl ')' {return typeExpression}
|
typeInParanthesis = '(' _nl typeExpression:typeExpression _nl ')' {return typeExpression}
|
||||||
|
|
||||||
|
@ -447,4 +380,4 @@ typeInParanthesis = '(' _nl typeExpression:typeExpression _nl ')' {return typeEx
|
||||||
// TODO: Example of foo = {a: 2, b: 5}; type fooKeys = string $ memberOf(foo->keys)
|
// TODO: Example of foo = {a: 2, b: 5}; type fooKeys = string $ memberOf(foo->keys)
|
||||||
// TODO: Example of memberOf( [1,2,3] )
|
// TODO: Example of memberOf( [1,2,3] )
|
||||||
// TODO: Example of $
|
// TODO: Example of $
|
||||||
// TODO: Cons(a, list) | EmptyList
|
// TODO: Cons(a, list) | EmptyList
|
||||||
|
|
|
@ -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 { startClient, stopClient } from "./client";
|
||||||
|
|
||||||
import { SquiggleEditorProvider } from "./editor";
|
import { SquiggleEditorProvider } from "./editor";
|
||||||
|
import { registerSemanticHighlight } from "./highlight";
|
||||||
import { registerPreviewCommand } from "./preview";
|
import { registerPreviewCommand } from "./preview";
|
||||||
|
|
||||||
// this method is called when your extension is activated
|
// this method is called when your extension is activated
|
||||||
|
@ -13,6 +14,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||||
|
|
||||||
registerPreviewCommand(context);
|
registerPreviewCommand(context);
|
||||||
|
|
||||||
|
registerSemanticHighlight();
|
||||||
|
|
||||||
startClient(context);
|
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";
|
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.
|
// Create a connection for the server, using Node's IPC as a transport.
|
||||||
// Also include all preview / proposed LSP features.
|
// Also include all preview / proposed LSP features.
|
||||||
let connection = createConnection(ProposedFeatures.all);
|
let connection = createConnection(ProposedFeatures.all);
|
||||||
|
@ -23,17 +27,7 @@ documents.onDidChangeContent((change) => {
|
||||||
validateSquiggleDocument(change.document);
|
validateSquiggleDocument(change.document);
|
||||||
});
|
});
|
||||||
|
|
||||||
let hasDiagnosticRelatedInformationCapability = false;
|
|
||||||
|
|
||||||
connection.onInitialize((params: InitializeParams) => {
|
connection.onInitialize((params: InitializeParams) => {
|
||||||
const capabilities = params.capabilities;
|
|
||||||
|
|
||||||
hasDiagnosticRelatedInformationCapability = !!(
|
|
||||||
capabilities.textDocument &&
|
|
||||||
capabilities.textDocument.publishDiagnostics &&
|
|
||||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
|
||||||
);
|
|
||||||
|
|
||||||
const result: InitializeResult = {
|
const result: InitializeResult = {
|
||||||
capabilities: {
|
capabilities: {
|
||||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
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"
|
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324"
|
||||||
integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==
|
integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==
|
||||||
|
|
||||||
"@hookform/resolvers@^2.9.1":
|
"@hookform/resolvers@^2.9.3":
|
||||||
version "2.9.1"
|
version "2.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.1.tgz#59121e38d8fc95d2fd1f41c9631393cd21e10b65"
|
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.3.tgz#13f6934cfe705e24fac094da377e0621adcfc424"
|
||||||
integrity sha512-80lyFFcExEB7A09PFnl8k7A3obQyDF6MyO/FThtwetk+MTedYMs08Aqf7mgWnOawFGyz5QF+TZXJSYiIZW2tEg==
|
integrity sha512-Eqc/qgjq0VX/TU0a5D2O+yR/kAKflnjaVlYFC1wI2qBm/sgjKTXxv27ijLwHUoHPIF+MUkB/VuQqHJ5DcmbCww==
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.9.2":
|
"@humanwhocodes/config-array@^0.9.2":
|
||||||
version "0.9.5"
|
version "0.9.5"
|
||||||
|
@ -8713,10 +8713,10 @@ fast-check@^2.17.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
pure-rand "^5.0.1"
|
pure-rand "^5.0.1"
|
||||||
|
|
||||||
fast-check@^3.0.0:
|
fast-check@^3.0.1:
|
||||||
version "3.0.0"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.0.0.tgz#6ea28d584e9ffebd7ecd0f06c163cd6af593ecfd"
|
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.0.1.tgz#b9e7b57c4643a4e62893aca85e21c270591d0eac"
|
||||||
integrity sha512-uujtrFJEQQqnIMO52ARwzPcuV4omiL1OJBUBLE9WnNFeu0A97sREXDOmCIHY+Z6KLVcemUf09rWr0q0Xy/Y/Ew==
|
integrity sha512-AriFDYpYVOBynpPZq/quxSLumFOo2hPB2H5Nz2vc1QlNfjOaA62zX8USNXcOY5nwKHEq7lZ84dG9M1W+LAND1g==
|
||||||
dependencies:
|
dependencies:
|
||||||
pure-rand "^5.0.1"
|
pure-rand "^5.0.1"
|
||||||
|
|
||||||
|
@ -11914,10 +11914,10 @@ markdown-it@^8.3.1:
|
||||||
mdurl "^1.0.1"
|
mdurl "^1.0.1"
|
||||||
uc.micro "^1.0.5"
|
uc.micro "^1.0.5"
|
||||||
|
|
||||||
mathjs@^10.6.0:
|
mathjs@^10.6.3:
|
||||||
version "10.6.1"
|
version "10.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.6.1.tgz#95b34178eed65cbf7a63d35c468ad3ac912f7ddf"
|
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-10.6.3.tgz#12802d9218cea82a9ae49a9824997798ac128e75"
|
||||||
integrity sha512-8iZp6uUKKBoCFoUHze9ydsrSji9/IOEzMhwURyoQXaLL1+ILEZnraw4KzZnUBt/XN6lPJPV+7JO94oil3AmosQ==
|
integrity sha512-3yYrc6z0kcQfC2ERwLIIq+BjvmUDO+RdALxNyuq8kupj/B1SPYuLxxPjPWFz3F20+mPRTn/Je1Tjr1t/NfBorA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.18.3"
|
"@babel/runtime" "^7.18.3"
|
||||||
complex.js "^2.1.1"
|
complex.js "^2.1.1"
|
||||||
|
@ -14523,10 +14523,10 @@ react-helmet-async@*, react-helmet-async@^1.3.0:
|
||||||
react-fast-compare "^3.2.0"
|
react-fast-compare "^3.2.0"
|
||||||
shallowequal "^1.1.0"
|
shallowequal "^1.1.0"
|
||||||
|
|
||||||
react-hook-form@^7.32.2:
|
react-hook-form@^7.33.0:
|
||||||
version "7.32.2"
|
version "7.33.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.32.2.tgz#58ec2ab0239ce97969baa2faa03ced13fae913ac"
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.33.0.tgz#44a87ddd630f00ebeb0f15aa978f69ca74b8a77b"
|
||||||
integrity sha512-F1A6n762xaRhvtQH5SkQQhMr19cCkHZYesTcKJJeNmrphiZp/cYFTIzC05FnQry0SspM54oPJ9tXFXlzya8VNQ==
|
integrity sha512-h8XoeUHQs1Snx1s/sSvM+eVTSKkWQt8TcrbL+3/Rt5gugxpy4ueL5ZZkubffyNpUyyTz0qM0kwOi2c+JgGTjLA==
|
||||||
|
|
||||||
react-inspector@^5.1.0:
|
react-inspector@^5.1.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user