Merge pull request #865 from quantified-uncertainty/reducer-void

Reducer: void type
This commit is contained in:
Ozzie Gooen 2022-07-20 16:46:48 -07:00 committed by GitHub
commit 4055d1e93c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 163 additions and 91 deletions

View File

@ -200,6 +200,12 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
{expression.value.toDateString()} {expression.value.toDateString()}
</VariableBox> </VariableBox>
); );
case "void":
return (
<VariableBox heading="Void" showTypes={showTypes}>
{"Void"}
</VariableBox>
);
case "timeDuration": { case "timeDuration": {
return ( return (
<VariableBox heading="Time Duration" showTypes={showTypes}> <VariableBox heading="Time Duration" showTypes={showTypes}>

View File

@ -0,0 +1,20 @@
open Jest
open Reducer_Peggy_TestHelpers
describe("Peggy void", () => {
//literal
testToExpression("()", "{()}", ~v="()", ())
testToExpression(
"fn()=1",
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1}))}",
~v="@{fn: lambda(_=>internal code)}",
(),
)
testToExpression("fn()=1; fn()", "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:fn ())}", ~v="1", ())
testToExpression(
"fn(a)=(); call fn(1)",
"{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)})}",
~v="@{_: (),fn: lambda(a=>internal code)}",
(),
)
})

View File

@ -31,6 +31,7 @@
"format:prettier": "prettier --write .", "format:prettier": "prettier --write .",
"format": "yarn format:rescript && yarn format:prettier", "format": "yarn format:rescript && yarn format:prettier",
"prepack": "yarn build && yarn test && yarn bundle", "prepack": "yarn build && yarn test && yarn bundle",
"all:rescript": "yarn build:rescript && yarn test:rescript && yarn format:rescript",
"all": "yarn build && yarn bundle && yarn test" "all": "yarn build && yarn bundle && yarn test"
}, },
"keywords": [ "keywords": [

View File

@ -120,77 +120,86 @@ function createTsExport(
x: expressionValue, x: expressionValue,
environment: environment environment: environment
): squiggleExpression { ): squiggleExpression {
switch (x.tag) { switch (x) {
case "EvArray": case "EvVoid":
// genType doesn't convert anything more than 2 layers down into {tag: x, value: x} return tag("void", "");
// format, leaving it as the raw values. This converts the raw values default: {
// directly into typescript values. switch (x.tag) {
// case "EvArray":
// The casting here is because genType is about the types of the returned // genType doesn't convert anything more than 2 layers down into {tag: x, value: x}
// values, claiming they are fully recursive when that's not actually the // format, leaving it as the raw values. This converts the raw values
// case // directly into typescript values.
return tag( //
"array", // The casting here is because genType is about the types of the returned
x.value.map( // values, claiming they are fully recursive when that's not actually the
(arrayItem): squiggleExpression => // case
convertRawToTypescript( return tag(
arrayItem as unknown as rescriptExport, "array",
environment x.value.map(
(arrayItem): squiggleExpression =>
convertRawToTypescript(
arrayItem as unknown as rescriptExport,
environment
)
) )
) );
); case "EvArrayString":
case "EvArrayString": return tag("arraystring", x.value);
return tag("arraystring", x.value); case "EvBool":
case "EvBool": return tag("boolean", x.value);
return tag("boolean", x.value); case "EvCall":
case "EvCall": return tag("call", x.value);
return tag("call", x.value); case "EvLambda":
case "EvLambda": return tag("lambda", x.value);
return tag("lambda", x.value); case "EvDistribution":
case "EvDistribution": return tag("distribution", new Distribution(x.value, environment));
return tag("distribution", new Distribution(x.value, environment)); case "EvNumber":
case "EvNumber": return tag("number", x.value);
return tag("number", x.value); case "EvRecord":
case "EvRecord": // genType doesn't support records, so we have to do the raw conversion ourself
// genType doesn't support records, so we have to do the raw conversion ourself let result: tagged<"record", { [key: string]: squiggleExpression }> =
let result: tagged<"record", { [key: string]: squiggleExpression }> = tag( tag(
"record", "record",
_.mapValues(x.value, (x: unknown) => _.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, environment) convertRawToTypescript(x as rescriptExport, environment)
) )
); );
return result; return result;
case "EvString": case "EvString":
return tag("string", x.value); return tag("string", x.value);
case "EvSymbol": case "EvSymbol":
return tag("symbol", x.value); return tag("symbol", x.value);
case "EvDate": case "EvDate":
return tag("date", x.value); return tag("date", x.value);
case "EvTimeDuration": case "EvTimeDuration":
return tag("timeDuration", x.value); return tag("timeDuration", x.value);
case "EvDeclaration": case "EvDeclaration":
return tag("lambdaDeclaration", x.value); return tag("lambdaDeclaration", x.value);
case "EvTypeIdentifier": case "EvTypeIdentifier":
return tag("typeIdentifier", x.value); return tag("typeIdentifier", x.value);
case "EvType": case "EvType":
let typeResult: tagged<"type", { [key: string]: squiggleExpression }> = let typeResult: tagged<
tag( "type",
"type", { [key: string]: squiggleExpression }
_.mapValues(x.value, (x: unknown) => > = tag(
convertRawToTypescript(x as rescriptExport, environment) "type",
) _.mapValues(x.value, (x: unknown) =>
); convertRawToTypescript(x as rescriptExport, environment)
return typeResult; )
case "EvModule": );
let moduleResult: tagged< return typeResult;
"module", case "EvModule":
{ [key: string]: squiggleExpression } let moduleResult: tagged<
> = tag( "module",
"module", { [key: string]: squiggleExpression }
_.mapValues(x.value, (x: unknown) => > = tag(
convertRawToTypescript(x as rescriptExport, environment) "module",
) _.mapValues(x.value, (x: unknown) =>
); convertRawToTypescript(x as rescriptExport, environment)
return moduleResult; )
);
return moduleResult;
}
}
} }
} }

View File

@ -131,7 +131,8 @@ export type squiggleExpression =
| tagged<"record", { [key: string]: squiggleExpression }> | tagged<"record", { [key: string]: squiggleExpression }>
| tagged<"type", { [key: string]: squiggleExpression }> | tagged<"type", { [key: string]: squiggleExpression }>
| tagged<"typeIdentifier", string> | tagged<"typeIdentifier", string>
| tagged<"module", { [key: string]: squiggleExpression }>; | tagged<"module", { [key: string]: squiggleExpression }>
| tagged<"void", string>;
export { lambdaValue }; export { lambdaValue };

View File

@ -82,3 +82,5 @@ let eIdentifier = (name: string): expression =>
let eTypeIdentifier = (name: string): expression => let eTypeIdentifier = (name: string): expression =>
name->BInternalExpressionValue.IEvTypeIdentifier->BExpressionT.EValue name->BInternalExpressionValue.IEvTypeIdentifier->BExpressionT.EValue
let eVoid: expression = BInternalExpressionValue.IEvVoid->BExpressionT.EValue

View File

@ -5,13 +5,12 @@
}} }}
start start
// = _nl start:typeExpression _nl finalComment? {return start}
= _nl start:outerBlock _nl finalComment? {return start} = _nl start:outerBlock _nl finalComment? {return start}
zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda 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 h.nodeBlock(statements) } return h.nodeBlock(statements) }
/ finalExpression: expression / finalExpression: expression
@ -24,25 +23,31 @@ innerBlockOrExpression
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 h.nodeBlock(statements) } return h.nodeBlock(statements) }
/ '{' _nl finalExpression: expression _nl '}' / '{' _nl finalExpression: expression _nl '}'
{ return h.nodeBlock([finalExpression]) } { return h.nodeBlock([finalExpression]) }
array_statements array_statements
= head:statement tail:(statementSeparator @array_statements ) = head:statement tail:(statementSeparator @array_statements )
{ return [head, ...tail] } { return [head, ...tail] }
/ head:statement / head:statement
{ return [head] } { return [head] }
statement statement
= letStatement = letStatement
/ defunStatement / defunStatement
/ typeStatement / typeStatement
/ voidStatement
voidStatement
= "call" _nl value:zeroOMoreArgumentsBlockOrExpression
{ var variable = h.nodeIdentifier("_", location());
return h.nodeLetStatement(variable, value); }
letStatement letStatement
= variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression = variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
{ return h.nodeLetStatement(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
@ -53,13 +58,15 @@ defunStatement
array_parameters array_parameters
= head:dollarIdentifier tail:(_ ',' _nl @dollarIdentifier)* = head:dollarIdentifier tail:(_ ',' _nl @dollarIdentifier)*
{ return [head, ...tail]; } { return [head, ...tail]; }
/ ""
{ return [h.nodeIdentifier("_", location())]; }
expression = ifthenelse / ternary / logicalAdditive expression = ifthenelse / ternary / logicalAdditive
ifthenelse 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 h.nodeTernary(condition, trueExpression, falseExpression) } { return h.nodeTernary(condition, trueExpression, falseExpression) }
@ -88,8 +95,8 @@ equality
= left:relational _ operator:equalityOp _nl right:relational = left:relational _ operator:equalityOp _nl right:relational
{ return h.makeFunctionCall(h.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
@ -172,19 +179,25 @@ collectionElement
array_functionArguments array_functionArguments
= head:expression tail:(_ ',' _nl @expression)* = head:expression tail:(_ ',' _nl @expression)*
{ return [head, ...tail]; } { return [head, ...tail]; }
/ ""
{return [h.nodeVoid()];}
atom atom
= '(' _nl expression:expression _nl ')' {return expression} = '(' _nl expression:expression _nl ')' {return expression}
/ basicValue / basicValue
basicValue = valueConstructor / basicLiteral basicValue = valueConstructor / basicLiteral
basicLiteral basicLiteral
= string = string
/ number / number
/ boolean / boolean
/ dollarIdentifierWithModule / dollarIdentifierWithModule
/ dollarIdentifier / dollarIdentifier
/ voidLiteral
voidLiteral 'void'
= "()" {return h.nodeVoid();}
dollarIdentifierWithModule 'identifier' dollarIdentifierWithModule 'identifier'
= head:$moduleIdentifier = head:$moduleIdentifier
@ -195,7 +208,7 @@ dollarIdentifierWithModule 'identifier'
modifiers.unshift(head) modifiers.unshift(head)
modifiers.push(final) modifiers.push(final)
let modifiedIdentifier = modifiers.join('.') let modifiedIdentifier = modifiers.join('.')
return h.nodeIdentifier(modifiedIdentifier) return h.nodeIdentifier(modifiedIdentifier, location())
} }
identifier 'identifier' identifier 'identifier'
@ -232,8 +245,8 @@ float 'float'
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent) = $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
{ return h.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')
@ -247,10 +260,10 @@ 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 h.nodeLambda(args, h.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 h.nodeLambda(args, h.nodeBlock([finalExpression])) } { return h.nodeLambda(args, h.nodeBlock([finalExpression])) }
arrayConstructor 'array' arrayConstructor 'array'
= '[' _nl ']' = '[' _nl ']'
@ -289,7 +302,7 @@ __nl 'whitespace or newline'
= (whiteSpaceCharactersOrComment / commentOrNewLine )+ = (whiteSpaceCharactersOrComment / commentOrNewLine )+
statementSeparator 'statement separator' statementSeparator 'statement separator'
= _ (';'/ commentOrNewLine)+ _nl = _ (';'/ commentOrNewLine)+ _nl
commentOrNewLine = finalComment? newLine commentOrNewLine = finalComment? newLine

View File

@ -34,6 +34,7 @@ type nodeModuleIdentifier = {...node, "value": string}
type nodeString = {...node, "value": string} type nodeString = {...node, "value": string}
type nodeTernary = {...node, "condition": node, "trueExpression": node, "falseExpression": node} type nodeTernary = {...node, "condition": node, "trueExpression": node, "falseExpression": node}
type nodeTypeIdentifier = {...node, "value": string} type nodeTypeIdentifier = {...node, "value": string}
type nodeVoid = node
type peggyNode = type peggyNode =
| PgNodeBlock(nodeBlock) | PgNodeBlock(nodeBlock)
@ -50,6 +51,7 @@ type peggyNode =
| PgNodeString(nodeString) | PgNodeString(nodeString)
| PgNodeTernary(nodeTernary) | PgNodeTernary(nodeTernary)
| PgNodeTypeIdentifier(nodeTypeIdentifier) | PgNodeTypeIdentifier(nodeTypeIdentifier)
| PgNodeVoid(nodeVoid)
external castNodeBlock: node => nodeBlock = "%identity" external castNodeBlock: node => nodeBlock = "%identity"
external castNodeBoolean: node => nodeBoolean = "%identity" external castNodeBoolean: node => nodeBoolean = "%identity"
@ -65,6 +67,7 @@ external castNodeModuleIdentifier: node => nodeModuleIdentifier = "%identity"
external castNodeString: node => nodeString = "%identity" external castNodeString: node => nodeString = "%identity"
external castNodeTernary: node => nodeTernary = "%identity" external castNodeTernary: node => nodeTernary = "%identity"
external castNodeTypeIdentifier: node => nodeTypeIdentifier = "%identity" external castNodeTypeIdentifier: node => nodeTypeIdentifier = "%identity"
external castNodeVoid: node => nodeVoid = "%identity"
exception UnsupportedPeggyNodeType(string) // This should never happen; programming error exception UnsupportedPeggyNodeType(string) // This should never happen; programming error
let castNodeType = (node: node) => let castNodeType = (node: node) =>
@ -83,6 +86,7 @@ let castNodeType = (node: node) =>
| "String" => node->castNodeString->PgNodeString | "String" => node->castNodeString->PgNodeString
| "Ternary" => node->castNodeTernary->PgNodeTernary | "Ternary" => node->castNodeTernary->PgNodeTernary
| "TypeIdentifier" => node->castNodeTypeIdentifier->PgNodeTypeIdentifier | "TypeIdentifier" => node->castNodeTypeIdentifier->PgNodeTypeIdentifier
| "Void" => node->castNodeVoid->PgNodeVoid
| _ => raise(UnsupportedPeggyNodeType(node["type"])) | _ => raise(UnsupportedPeggyNodeType(node["type"]))
} }
@ -116,6 +120,7 @@ let rec pgToString = (peggyNode: peggyNode): string => {
" " ++ " " ++
toString(node["falseExpression"]) ++ ")" toString(node["falseExpression"]) ++ ")"
| PgNodeTypeIdentifier(node) => `#${node["value"]}` | PgNodeTypeIdentifier(node) => `#${node["value"]}`
| PgNodeVoid(_node) => "()"
} }
} }
and toString = (node: node): string => node->castNodeType->pgToString and toString = (node: node): string => node->castNodeType->pgToString

View File

@ -48,5 +48,6 @@ let rec fromNode = (node: Parse.node): expression => {
) )
| PgNodeTypeIdentifier(nodeTypeIdentifier) => | PgNodeTypeIdentifier(nodeTypeIdentifier) =>
ExpressionBuilder.eTypeIdentifier(nodeTypeIdentifier["value"]) ExpressionBuilder.eTypeIdentifier(nodeTypeIdentifier["value"])
| PgNodeVoid(_) => ExpressionBuilder.eVoid
} }
} }

View File

@ -213,3 +213,7 @@ export function nodeTernary(
export function nodeTypeIdentifier(typeValue: string) { export function nodeTypeIdentifier(typeValue: string) {
return { type: "TypeIdentifier", value: typeValue }; return { type: "TypeIdentifier", value: typeValue };
} }
export function nodeVoid() {
return { type: "Void" };
}

View File

@ -25,6 +25,7 @@ type rec externalExpressionValue =
| EvTypeIdentifier(string) | EvTypeIdentifier(string)
| EvModule(record) | EvModule(record)
| EvType(record) | EvType(record)
| EvVoid
and record = Js.Dict.t<externalExpressionValue> and record = Js.Dict.t<externalExpressionValue>
and externalBindings = record and externalBindings = record
and lambdaValue = { and lambdaValue = {
@ -63,6 +64,7 @@ let rec toString = aValue =>
| EvTimeDuration(t) => DateTime.Duration.toString(t) | EvTimeDuration(t) => DateTime.Duration.toString(t)
| EvType(t) => `type${t->toStringRecord}` | EvType(t) => `type${t->toStringRecord}`
| EvTypeIdentifier(id) => `#${id}` | EvTypeIdentifier(id) => `#${id}`
| EvVoid => `()`
} }
and toStringRecord = aRecord => { and toStringRecord = aRecord => {
let pairs = let pairs =

View File

@ -23,6 +23,7 @@ type rec t =
| IEvTimeDuration(float) | IEvTimeDuration(float)
| IEvType(map) | IEvType(map)
| IEvTypeIdentifier(string) | IEvTypeIdentifier(string)
| IEvVoid
and map = Belt.Map.String.t<t> and map = Belt.Map.String.t<t>
and nameSpace = NameSpace(Belt.Map.String.t<t>) and nameSpace = NameSpace(Belt.Map.String.t<t>)
and lambdaValue = { and lambdaValue = {
@ -60,6 +61,7 @@ let rec toString = aValue =>
| IEvType(aMap) => aMap->toStringMap | IEvType(aMap) => aMap->toStringMap
| IEvTimeDuration(t) => DateTime.Duration.toString(t) | IEvTimeDuration(t) => DateTime.Duration.toString(t)
| IEvTypeIdentifier(id) => `#${id}` | IEvTypeIdentifier(id) => `#${id}`
| IEvVoid => `()`
} }
and toStringMap = aMap => { and toStringMap = aMap => {
let pairs = let pairs =
@ -92,6 +94,7 @@ let toStringWithType = aValue =>
| IEvTimeDuration(_) => `Date::${toString(aValue)}` | IEvTimeDuration(_) => `Date::${toString(aValue)}`
| IEvType(_) => `Type::${toString(aValue)}` | IEvType(_) => `Type::${toString(aValue)}`
| IEvTypeIdentifier(_) => `TypeIdentifier::${toString(aValue)}` | IEvTypeIdentifier(_) => `TypeIdentifier::${toString(aValue)}`
| IEvVoid => `Void`
} }
let argsToString = (args: array<t>): string => { let argsToString = (args: array<t>): string => {
@ -135,6 +138,7 @@ type internalExpressionValueType =
| EvtTimeDuration | EvtTimeDuration
| EvtType | EvtType
| EvtTypeIdentifier | EvtTypeIdentifier
| EvtVoid
type functionCallSignature = CallSignature(string, array<internalExpressionValueType>) type functionCallSignature = CallSignature(string, array<internalExpressionValueType>)
type functionDefinitionSignature = type functionDefinitionSignature =
@ -158,6 +162,7 @@ let valueToValueType = value =>
| IEvTimeDuration(_) => EvtTimeDuration | IEvTimeDuration(_) => EvtTimeDuration
| IEvType(_) => EvtType | IEvType(_) => EvtType
| IEvTypeIdentifier(_) => EvtTypeIdentifier | IEvTypeIdentifier(_) => EvtTypeIdentifier
| IEvVoid => EvtVoid
} }
let externalValueToValueType = (value: ExternalExpressionValue.t) => let externalValueToValueType = (value: ExternalExpressionValue.t) =>
@ -203,6 +208,7 @@ let valueTypeToString = (valueType: internalExpressionValueType): string =>
| EvtTimeDuration => `Duration` | EvtTimeDuration => `Duration`
| EvtType => `Type` | EvtType => `Type`
| EvtTypeIdentifier => `TypeIdentifier` | EvtTypeIdentifier => `TypeIdentifier`
| EvtVoid => `Void`
} }
let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => { let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => {
@ -232,6 +238,7 @@ let rec toExternal = (iev: t): ExternalExpressionValue.t => {
| IEvType(v) => v->mapToExternal->EvType | IEvType(v) => v->mapToExternal->EvType
| IEvTypeIdentifier(v) => EvTypeIdentifier(v) | IEvTypeIdentifier(v) => EvTypeIdentifier(v)
| IEvBindings(v) => v->nameSpaceToTypeScriptBindings->EvModule | IEvBindings(v) => v->nameSpaceToTypeScriptBindings->EvModule
| IEvVoid => EvVoid
} }
} }
and mapToExternal = v => and mapToExternal = v =>
@ -271,6 +278,7 @@ let rec toInternal = (ev: ExternalExpressionValue.t): t => {
| EvTimeDuration(v) => IEvTimeDuration(v) | EvTimeDuration(v) => IEvTimeDuration(v)
| EvType(v) => v->recordToInternal->IEvType | EvType(v) => v->recordToInternal->IEvType
| EvTypeIdentifier(v) => IEvTypeIdentifier(v) | EvTypeIdentifier(v) => IEvTypeIdentifier(v)
| EvVoid => IEvVoid
} }
} }
and recordToInternal = v => and recordToInternal = v =>