return typed peggy AST from parse
This commit is contained in:
parent
4ca6c99205
commit
5a2b5b2a4d
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",
|
||||||
|
|
|
@ -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 = {
|
import * as h from './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,214 @@
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 };
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user