error stacktraces and locations (initial take, WIP)
This commit is contained in:
parent
d3bc08ab9d
commit
41574e08c9
|
@ -7,5 +7,9 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SquiggleErrorAlert: React.FC<Props> = ({ error }) => {
|
export const SquiggleErrorAlert: React.FC<Props> = ({ error }) => {
|
||||||
return <ErrorAlert heading="Error">{error.toString()}</ErrorAlert>;
|
return (
|
||||||
|
<ErrorAlert heading="Error">
|
||||||
|
<pre>{error.toString()}</pre>
|
||||||
|
</ErrorAlert>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -298,7 +298,9 @@ export const ExpressionViewer: React.FC<Props> = ({ value, width }) => {
|
||||||
{() => (
|
{() => (
|
||||||
<div>
|
<div>
|
||||||
<span>No display for type: </span>{" "}
|
<span>No display for type: </span>{" "}
|
||||||
<span className="font-semibold text-slate-600">{value.tag}</span>
|
<span className="font-semibold text-slate-600">
|
||||||
|
{(value as any).tag}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</VariableList>
|
</VariableList>
|
||||||
|
|
|
@ -9,12 +9,12 @@ open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
let expectParseToBe = (expr, answer) =>
|
let expectParseToBe = (expr, answer) =>
|
||||||
Parse.parse(expr)->Parse.toStringResult->expect->toBe(answer)
|
Parse.parse(expr, "test")->Parse.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
||||||
|
|
||||||
let expectToExpressionToBe = (expr, answer, ~v="_", ()) => {
|
let expectToExpressionToBe = (expr, answer, ~v="_", ()) => {
|
||||||
let rExpr = Parse.parse(expr)->Result.map(ToExpression.fromNode)
|
let rExpr = Parse.parse(expr, "test")->Result.map(ToExpression.fromNode)
|
||||||
let a1 = rExpr->ExpressionT.toStringResultOkless
|
let a1 = rExpr->ExpressionT.toStringResultOkless
|
||||||
|
|
||||||
if v == "_" {
|
if v == "_" {
|
||||||
|
@ -22,6 +22,7 @@ let expectToExpressionToBe = (expr, answer, ~v="_", ()) => {
|
||||||
} else {
|
} else {
|
||||||
let a2 =
|
let a2 =
|
||||||
rExpr
|
rExpr
|
||||||
|
->E.R2.errMap(e => e->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue)
|
||||||
->Result.flatMap(expr => Expression.BackCompatible.evaluate(expr))
|
->Result.flatMap(expr => Expression.BackCompatible.evaluate(expr))
|
||||||
->Reducer_Value.toStringResultOkless
|
->Reducer_Value.toStringResultOkless
|
||||||
(a1, a2)->expect->toEqual((answer, v))
|
(a1, a2)->expect->toEqual((answer, v))
|
||||||
|
|
|
@ -25,7 +25,7 @@ x=1`,
|
||||||
let mainIncludes = Project.getIncludes(project, "main")
|
let mainIncludes = Project.getIncludes(project, "main")
|
||||||
switch mainIncludes {
|
switch mainIncludes {
|
||||||
| Ok(includes) => expect(includes) == ["common"]
|
| Ok(includes) => expect(includes) == ["common"]
|
||||||
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
| Error(error) => fail(error->Reducer_ErrorValue.errorValueToString)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
test("past chain", () => {
|
test("past chain", () => {
|
||||||
|
@ -60,7 +60,7 @@ x=1`,
|
||||||
let mainIncludes = Project.getIncludes(project, "main")
|
let mainIncludes = Project.getIncludes(project, "main")
|
||||||
switch mainIncludes {
|
switch mainIncludes {
|
||||||
| Ok(includes) => expect(includes) == ["common", "myModule"]
|
| Ok(includes) => expect(includes) == ["common", "myModule"]
|
||||||
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
| Error(error) => fail(error->Reducer_ErrorValue.errorValueToString)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ x=1`,
|
||||||
let mainIncludes = Project.getIncludes(project, "main")
|
let mainIncludes = Project.getIncludes(project, "main")
|
||||||
switch mainIncludes {
|
switch mainIncludes {
|
||||||
| Ok(includes) => expect(includes) == ["common", "common2", "myModule"]
|
| Ok(includes) => expect(includes) == ["common", "common2", "myModule"]
|
||||||
| Error(error) => fail(error->Reducer_ErrorValue.errorToString)
|
| Error(error) => fail(error->Reducer_ErrorValue.errorValueToString)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
test("direct past chain", () => {
|
test("direct past chain", () => {
|
||||||
|
|
|
@ -36,7 +36,7 @@ Here we will finally proceed to a real life scenario. */
|
||||||
/* Parse includes has set the includes */
|
/* Parse includes has set the includes */
|
||||||
switch project->Project.getIncludes("main") {
|
switch project->Project.getIncludes("main") {
|
||||||
| Ok(includes) => includes->expect == ["common"]
|
| Ok(includes) => includes->expect == ["common"]
|
||||||
| Error(err) => err->Reducer_ErrorValue.errorToString->fail
|
| Error(err) => err->Reducer_ErrorValue.errorValueToString->fail
|
||||||
}
|
}
|
||||||
/* If the includes cannot be parsed then you get a syntax error.
|
/* If the includes cannot be parsed then you get a syntax error.
|
||||||
Otherwise you get the includes.
|
Otherwise you get the includes.
|
||||||
|
@ -85,7 +85,7 @@ Here we will finally proceed to a real life scenario. */
|
||||||
let rIncludes = project->Project.getIncludes(sourceName)
|
let rIncludes = project->Project.getIncludes(sourceName)
|
||||||
switch rIncludes {
|
switch rIncludes {
|
||||||
/* Maybe there is an include syntax error */
|
/* Maybe there is an include syntax error */
|
||||||
| Error(err) => err->Reducer_ErrorValue.errorToString->Js.Exn.raiseError
|
| Error(err) => err->Reducer_ErrorValue.errorValueToString->Js.Exn.raiseError
|
||||||
|
|
||||||
| Ok(includes) =>
|
| Ok(includes) =>
|
||||||
includes->Belt.Array.forEach(newIncludeName => {
|
includes->Belt.Array.forEach(newIncludeName => {
|
||||||
|
@ -169,7 +169,7 @@ Here we will finally proceed to a real life scenario. */
|
||||||
test("getIncludes", () => {
|
test("getIncludes", () => {
|
||||||
switch Project.getIncludes(project, "main") {
|
switch Project.getIncludes(project, "main") {
|
||||||
| Ok(includes) => includes->expect == ["common"]
|
| Ok(includes) => includes->expect == ["common"]
|
||||||
| Error(err) => err->Reducer_ErrorValue.errorToString->fail
|
| Error(err) => err->Reducer_ErrorValue.errorValueToString->fail
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { run } from "./lib.mjs";
|
import { run } from "./lib.mjs";
|
||||||
|
|
||||||
const src = process.argv[2];
|
import { Command } from "commander";
|
||||||
|
|
||||||
|
const program = new Command();
|
||||||
|
|
||||||
|
program.arguments("<string>");
|
||||||
|
|
||||||
|
const options = program.parse(process.argv);
|
||||||
|
|
||||||
|
const src = program.args[0];
|
||||||
if (!src) {
|
if (!src) {
|
||||||
throw new Error("Expected src");
|
throw new Error("Expected src");
|
||||||
}
|
}
|
||||||
console.log(`Running ${src}`);
|
|
||||||
|
|
||||||
const sampleCount = process.env.SAMPLE_COUNT;
|
const sampleCount = process.env.SAMPLE_COUNT;
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
import * as RSErrorValue from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
|
import * as RSErrorValue from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
|
||||||
|
|
||||||
export class SqError {
|
export class SqError {
|
||||||
constructor(private _value: RSErrorValue.reducerErrorValue) {}
|
constructor(private _value: RSErrorValue.reducerError) {}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return RSErrorValue.toString(this._value);
|
return RSErrorValue.toString(this._value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createTodoError(v: string) {
|
|
||||||
return new SqError(RSErrorValue.createTodoError(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
static createOtherError(v: string) {
|
static createOtherError(v: string) {
|
||||||
return new SqError(RSErrorValue.createOtherError(v));
|
return new SqError(RSErrorValue.createOtherError(v));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import * as RSProject from "../rescript/ForTS/ForTS_ReducerProject.gen";
|
import * as RSProject from "../rescript/ForTS/ForTS_ReducerProject.gen";
|
||||||
import { reducerErrorValue } from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
|
import {
|
||||||
|
reducerError,
|
||||||
|
reducerErrorValue,
|
||||||
|
attachEmptyStackTraceToErrorValue,
|
||||||
|
} from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
|
||||||
import { environment } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.gen";
|
import { environment } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.gen";
|
||||||
import { SqError } from "./SqError";
|
import { SqError } from "./SqError";
|
||||||
import { SqRecord } from "./SqRecord";
|
import { SqRecord } from "./SqRecord";
|
||||||
|
@ -50,7 +54,8 @@ export class SqProject {
|
||||||
return resultMap2(
|
return resultMap2(
|
||||||
RSProject.getIncludes(this._value, sourceId),
|
RSProject.getIncludes(this._value, sourceId),
|
||||||
(a) => a,
|
(a) => a,
|
||||||
(v: reducerErrorValue) => new SqError(v)
|
(v: reducerErrorValue) =>
|
||||||
|
new SqError(attachEmptyStackTraceToErrorValue(v))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +109,7 @@ export class SqProject {
|
||||||
items: [],
|
items: [],
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
(v: reducerErrorValue) => new SqError(v)
|
(v: reducerError) => new SqError(v)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ module Integration = {
|
||||||
| Error(b) =>
|
| Error(b) =>
|
||||||
("Integration error 2 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
|
("Integration error 2 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
|
||||||
"Original error: " ++
|
"Original error: " ++
|
||||||
b->Reducer_ErrorValue.errorToString)
|
b->Reducer_ErrorValue.errorValueToString)
|
||||||
->Reducer_ErrorValue.REOther
|
->Reducer_ErrorValue.REOther
|
||||||
->Error
|
->Error
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ module Integration = {
|
||||||
reducer,
|
reducer,
|
||||||
)->E.R2.errMap(b =>
|
)->E.R2.errMap(b =>
|
||||||
("Integration error 7 in Danger.integrate. Something went wrong along the way: " ++
|
("Integration error 7 in Danger.integrate. Something went wrong along the way: " ++
|
||||||
b->Reducer_ErrorValue.errorToString)->Reducer_ErrorValue.REOther
|
b->Reducer_ErrorValue.errorValueToString)->Reducer_ErrorValue.REOther
|
||||||
)
|
)
|
||||||
| _ =>
|
| _ =>
|
||||||
"Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))"
|
"Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@genType type reducerProject = ReducerProject_T.project //re-export
|
@genType type reducerProject = ReducerProject_T.project //re-export
|
||||||
|
|
||||||
|
type reducerError = ForTS_Reducer_ErrorValue.reducerError //use
|
||||||
type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use
|
type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use
|
||||||
|
|
||||||
type squiggleValue = ForTS_SquiggleValue.squiggleValue //use
|
type squiggleValue = ForTS_SquiggleValue.squiggleValue //use
|
||||||
|
@ -191,10 +192,8 @@ let getBindings = (project: reducerProject, sourceId: string): squiggleValue_Rec
|
||||||
Get the result after running this source file or the project
|
Get the result after running this source file or the project
|
||||||
*/
|
*/
|
||||||
@genType
|
@genType
|
||||||
let getResult = (project: reducerProject, sourceId: string): result<
|
let getResult = (project: reducerProject, sourceId: string): result<squiggleValue, reducerError> =>
|
||||||
squiggleValue,
|
project->Private.getResult(sourceId)
|
||||||
reducerErrorValue,
|
|
||||||
> => project->Private.getResult(sourceId)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is a convenience function to get the result of a single source without creating a project.
|
This is a convenience function to get the result of a single source without creating a project.
|
||||||
|
@ -202,10 +201,8 @@ However, without a project, you cannot handle include directives.
|
||||||
The source has to be include free
|
The source has to be include free
|
||||||
*/
|
*/
|
||||||
@genType
|
@genType
|
||||||
let evaluate = (sourceCode: string): (
|
let evaluate = (sourceCode: string): (result<squiggleValue, reducerError>, squiggleValue_Record) =>
|
||||||
result<squiggleValue, reducerErrorValue>,
|
Private.evaluate(sourceCode)
|
||||||
squiggleValue_Record,
|
|
||||||
) => Private.evaluate(sourceCode)
|
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let setEnvironment = (project: reducerProject, environment: environment): unit =>
|
let setEnvironment = (project: reducerProject, environment: environment): unit =>
|
||||||
|
@ -213,24 +210,3 @@ let setEnvironment = (project: reducerProject, environment: environment): unit =
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let getEnvironment = (project: reducerProject): environment => project->Private.getEnvironment
|
let getEnvironment = (project: reducerProject): environment => project->Private.getEnvironment
|
||||||
|
|
||||||
/*
|
|
||||||
Foreign function interface is intentionally demolished.
|
|
||||||
There is another way to do that: Umur.
|
|
||||||
Also there is no more conversion from javascript to squiggle values currently.
|
|
||||||
If the conversion to the new project is too difficult, I can add it later.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// let foreignFunctionInterface = (
|
|
||||||
// lambdaValue: squiggleValue_Lambda,
|
|
||||||
// argArray: array<squiggleValue>,
|
|
||||||
// environment: environment,
|
|
||||||
// ): result<squiggleValue, reducerErrorValue> => {
|
|
||||||
// let accessors = ReducerProject_ProjectAccessors_T.identityAccessorsWithEnvironment(environment)
|
|
||||||
// Reducer_Expression_Lambda.foreignFunctionInterface(
|
|
||||||
// lambdaValue,
|
|
||||||
// argArray,
|
|
||||||
// accessors,
|
|
||||||
// Reducer_Expression.reduceExpressionInProject,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
|
@genType type reducerError = Reducer_ErrorValue.error //alias
|
||||||
@genType type reducerErrorValue = Reducer_ErrorValue.errorValue //alias
|
@genType type reducerErrorValue = Reducer_ErrorValue.errorValue //alias
|
||||||
@genType type syntaxErrorLocation = Reducer_ErrorValue.syntaxErrorLocation //alias
|
@genType type location = Reducer_ErrorValue.location //alias
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let toString = (e: reducerErrorValue): string => Reducer_ErrorValue.errorToString(e)
|
let toString = (e: reducerError): string => Reducer_ErrorValue.errorToString(e)
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let getLocation = (e: reducerErrorValue): option<syntaxErrorLocation> =>
|
let getLocation = (e: reducerError): option<location> =>
|
||||||
switch e {
|
switch e.stackTrace {
|
||||||
| RESyntaxError(_, optionalLocation) => optionalLocation
|
| Some(stack) => Some(stack.location)
|
||||||
| _ => None
|
| None => None
|
||||||
}
|
}
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let createTodoError = (v: string) => Reducer_ErrorValue.RETodo(v)
|
let createOtherError = (v: string): reducerError =>
|
||||||
|
Reducer_ErrorValue.REOther(v)->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let createOtherError = (v: string) => Reducer_ErrorValue.REOther(v)
|
let attachEmptyStackTraceToErrorValue = (v: reducerErrorValue): reducerError =>
|
||||||
|
Reducer_ErrorValue.attachEmptyStackTraceToErrorValue(v)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@genType type squiggleValue = Reducer_T.value //re-export
|
@genType type squiggleValue = Reducer_T.value //re-export
|
||||||
type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //use
|
type reducerError = ForTS_Reducer_ErrorValue.reducerError //use
|
||||||
|
|
||||||
@genType type squiggleValue_Array = Reducer_T.arrayValue //re-export recursive type
|
@genType type squiggleValue_Array = Reducer_T.arrayValue //re-export recursive type
|
||||||
@genType type squiggleValue_Record = Reducer_T.map //re-export recursive type
|
@genType type squiggleValue_Record = Reducer_T.map //re-export recursive type
|
||||||
|
@ -69,7 +69,7 @@ let toString = (variant: squiggleValue) => Reducer_Value.toString(variant)
|
||||||
// This is a useful method for unit tests.
|
// This is a useful method for unit tests.
|
||||||
// Convert the result along with the error message to a string.
|
// Convert the result along with the error message to a string.
|
||||||
@genType
|
@genType
|
||||||
let toStringResult = (variantResult: result<squiggleValue, reducerErrorValue>) =>
|
let toStringResult = (variantResult: result<squiggleValue, reducerError>) =>
|
||||||
Reducer_Value.toStringResult(variantResult)
|
Reducer_Value.toStringResult(variantResult)
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@genType type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //re-export
|
@genType type reducerErrorValue = ForTS_Reducer_ErrorValue.reducerErrorValue //re-export
|
||||||
@genType type syntaxErrorLocation = ForTS_Reducer_ErrorValue.syntaxErrorLocation //re-export
|
@genType type location = ForTS_Reducer_ErrorValue.location //re-export
|
||||||
|
|
||||||
@genType type reducerProject = ForTS_ReducerProject.reducerProject //re-export
|
@genType type reducerProject = ForTS_ReducerProject.reducerProject //re-export
|
||||||
@genType type squiggleValue = ForTS_SquiggleValue.squiggleValue //re-export
|
@genType type squiggleValue = ForTS_SquiggleValue.squiggleValue //re-export
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
//TODO: Do not export here but in ForTS__Types
|
// Do not gentype this, use LocationRange from peggy types instead
|
||||||
@gentype.import("peggy") @genType.as("LocationRange")
|
// TODO - rename locationPoint -> location, location -> locationRange to match peggy
|
||||||
type syntaxErrorLocation
|
@genType
|
||||||
|
type locationPoint = {
|
||||||
|
line: int,
|
||||||
|
column: int,
|
||||||
|
}
|
||||||
|
@genType
|
||||||
|
type location = {
|
||||||
|
source: string,
|
||||||
|
start: locationPoint,
|
||||||
|
end: locationPoint,
|
||||||
|
}
|
||||||
|
|
||||||
@genType.opaque
|
@genType.opaque
|
||||||
type errorValue =
|
type errorValue =
|
||||||
|
@ -18,7 +28,7 @@ type errorValue =
|
||||||
| REOperationError(Operation.operationError)
|
| REOperationError(Operation.operationError)
|
||||||
| RERecordPropertyNotFound(string, string)
|
| RERecordPropertyNotFound(string, string)
|
||||||
| RESymbolNotFound(string)
|
| RESymbolNotFound(string)
|
||||||
| RESyntaxError(string, option<syntaxErrorLocation>)
|
| RESyntaxError(string, option<location>)
|
||||||
| RETodo(string) // To do
|
| RETodo(string) // To do
|
||||||
| REUnitNotFound(string)
|
| REUnitNotFound(string)
|
||||||
| RENeedToRun
|
| RENeedToRun
|
||||||
|
@ -28,7 +38,20 @@ type t = errorValue
|
||||||
|
|
||||||
exception ErrorException(errorValue)
|
exception ErrorException(errorValue)
|
||||||
|
|
||||||
let errorToString = err =>
|
type rec stackTrace = {
|
||||||
|
location: location,
|
||||||
|
parent: option<stackTrace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@genType.opaque
|
||||||
|
type error = {
|
||||||
|
error: t,
|
||||||
|
stackTrace: option<stackTrace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
exception ExceptionWithStackTrace(error)
|
||||||
|
|
||||||
|
let errorValueToString = (err: errorValue) =>
|
||||||
switch err {
|
switch err {
|
||||||
| REArityError(_oFnName, arity, usedArity) =>
|
| REArityError(_oFnName, arity, usedArity) =>
|
||||||
`${Js.String.make(arity)} arguments expected. Instead ${Js.String.make(
|
`${Js.String.make(arity)} arguments expected. Instead ${Js.String.make(
|
||||||
|
@ -80,4 +103,37 @@ let fromException = exn =>
|
||||||
| _e => REOther("Unknown error")
|
| _e => REOther("Unknown error")
|
||||||
}
|
}
|
||||||
|
|
||||||
let toException = (errorValue: t) => raise(ErrorException(errorValue))
|
let rec stackTraceToString = ({location, parent}: stackTrace) => {
|
||||||
|
` Line ${location.start.line->Js.Int.toString}, column ${location.start.column->Js.Int.toString}, source ${location.source}\n` ++
|
||||||
|
switch parent {
|
||||||
|
| Some(parent) => stackTraceToString(parent)
|
||||||
|
| None => ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let errorToString = (err: error) =>
|
||||||
|
switch err.stackTrace {
|
||||||
|
| Some(stack) => "Traceback:\n" ++ stack->stackTraceToString
|
||||||
|
| None => ""
|
||||||
|
} ++
|
||||||
|
err.error->errorValueToString
|
||||||
|
|
||||||
|
let toException = (errorValue: t) => errorValue->ErrorException->raise
|
||||||
|
|
||||||
|
let attachEmptyStackTraceToErrorValue = (errorValue: t) => {
|
||||||
|
error: errorValue,
|
||||||
|
stackTrace: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
let attachLocationToErrorValue = (errorValue: t, location: location): error => {
|
||||||
|
error: errorValue,
|
||||||
|
stackTrace: Some({location: location, parent: None}),
|
||||||
|
}
|
||||||
|
|
||||||
|
let raiseNewExceptionWithStackTrace = (errorValue: t, location: location) =>
|
||||||
|
errorValue->attachLocationToErrorValue(location)->ExceptionWithStackTrace->raise
|
||||||
|
|
||||||
|
let raiseExtendedExceptionWithStackTrace = ({error, stackTrace}: error, location: location) =>
|
||||||
|
{error: error, stackTrace: Some({location: location, parent: stackTrace})}
|
||||||
|
->ExceptionWithStackTrace
|
||||||
|
->raise
|
||||||
|
|
|
@ -5,12 +5,19 @@ module T = Reducer_T
|
||||||
|
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
|
||||||
|
let toLocation = (expression: T.expression): Reducer_ErrorValue.location => {
|
||||||
|
expression.ast.location
|
||||||
|
}
|
||||||
|
|
||||||
|
let throwFrom = (error: errorValue, expression: T.expression) =>
|
||||||
|
error->Reducer_ErrorValue.raiseNewExceptionWithStackTrace(expression->toLocation)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Recursively evaluate the expression
|
Recursively evaluate the expression
|
||||||
*/
|
*/
|
||||||
let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
// Js.log(`reduce: ${expression->Reducer_Expression_T.toString}`)
|
// Js.log(`reduce: ${expression->Reducer_Expression_T.toString}`)
|
||||||
switch expression {
|
switch expression.content {
|
||||||
| T.EBlock(statements) => {
|
| T.EBlock(statements) => {
|
||||||
let innerContext = {...context, bindings: context.bindings->Bindings.extend}
|
let innerContext = {...context, bindings: context.bindings->Bindings.extend}
|
||||||
let (value, _) =
|
let (value, _) =
|
||||||
|
@ -49,7 +56,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
let (key, _) = eKey->evaluate(context)
|
let (key, _) = eKey->evaluate(context)
|
||||||
let keyString = switch key {
|
let keyString = switch key {
|
||||||
| IEvString(s) => s
|
| IEvString(s) => s
|
||||||
| _ => REOther("Record keys must be strings")->Reducer_ErrorValue.ErrorException->raise
|
| _ => REOther("Record keys must be strings")->throwFrom(expression)
|
||||||
}
|
}
|
||||||
let (value, _) = eValue->evaluate(context)
|
let (value, _) = eValue->evaluate(context)
|
||||||
(keyString, value)
|
(keyString, value)
|
||||||
|
@ -73,7 +80,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
| T.ESymbol(name) =>
|
| T.ESymbol(name) =>
|
||||||
switch context.bindings->Bindings.get(name) {
|
switch context.bindings->Bindings.get(name) {
|
||||||
| Some(v) => (v, context)
|
| Some(v) => (v, context)
|
||||||
| None => Reducer_ErrorValue.RESymbolNotFound(name)->Reducer_ErrorValue.ErrorException->raise
|
| None => RESymbolNotFound(name)->throwFrom(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.EValue(value) => (value, context)
|
| T.EValue(value) => (value, context)
|
||||||
|
@ -82,7 +89,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
let (predicateResult, _) = predicate->evaluate(context)
|
let (predicateResult, _) = predicate->evaluate(context)
|
||||||
switch predicateResult {
|
switch predicateResult {
|
||||||
| T.IEvBool(value) => (value ? trueCase : falseCase)->evaluate(context)
|
| T.IEvBool(value) => (value ? trueCase : falseCase)->evaluate(context)
|
||||||
| _ => REExpectedType("Boolean", "")->Reducer_ErrorValue.ErrorException->raise
|
| _ => REExpectedType("Boolean", "")->throwFrom(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,12 +105,18 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
argValue
|
argValue
|
||||||
})
|
})
|
||||||
switch lambda {
|
switch lambda {
|
||||||
| T.IEvLambda(lambda) => (
|
| T.IEvLambda(lambda) =>
|
||||||
Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate),
|
try {
|
||||||
context,
|
let result = Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate)
|
||||||
)
|
(result, context)
|
||||||
| _ =>
|
} catch {
|
||||||
RENotAFunction(lambda->Reducer_Value.toString)->Reducer_ErrorValue.ErrorException->raise
|
| Reducer_ErrorValue.ErrorException(e) => e->throwFrom(expression) // function implementation returned an error without location
|
||||||
|
| Reducer_ErrorValue.ExceptionWithStackTrace(e) =>
|
||||||
|
Reducer_ErrorValue.raiseExtendedExceptionWithStackTrace(e, expression->toLocation) // function implementation probably called a lambda that threw an exception
|
||||||
|
| Js.Exn.Error(obj) =>
|
||||||
|
REJavaScriptExn(obj->Js.Exn.message, obj->Js.Exn.name)->throwFrom(expression)
|
||||||
|
}
|
||||||
|
| _ => RENotAFunction(lambda->Reducer_Value.toString)->throwFrom(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,18 +126,24 @@ module BackCompatible = {
|
||||||
// Those methods are used to support the existing tests
|
// Those methods are used to support the existing tests
|
||||||
// If they are used outside limited testing context, error location reporting will fail
|
// If they are used outside limited testing context, error location reporting will fail
|
||||||
let parse = (peggyCode: string): result<T.expression, errorValue> =>
|
let parse = (peggyCode: string): result<T.expression, errorValue> =>
|
||||||
peggyCode->Reducer_Peggy_Parse.parse->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
peggyCode->Reducer_Peggy_Parse.parse("main")->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
||||||
|
|
||||||
let evaluate = (expression: T.expression): result<T.value, errorValue> => {
|
let evaluate = (expression: T.expression): result<T.value, Reducer_ErrorValue.error> => {
|
||||||
let context = Reducer_Context.createDefaultContext()
|
let context = Reducer_Context.createDefaultContext()
|
||||||
try {
|
try {
|
||||||
let (value, _) = expression->evaluate(context)
|
let (value, _) = expression->evaluate(context)
|
||||||
value->Ok
|
value->Ok
|
||||||
} catch {
|
} catch {
|
||||||
| exn => Reducer_ErrorValue.fromException(exn)->Error
|
| exn =>
|
||||||
|
exn
|
||||||
|
->Reducer_ErrorValue.fromException
|
||||||
|
->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue
|
||||||
|
->Error // TODO - this could be done better (see ReducerProject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluateString = (peggyCode: string): result<T.value, errorValue> =>
|
let evaluateString = (peggyCode: string): result<T.value, Reducer_ErrorValue.error> =>
|
||||||
parse(peggyCode)->Result.flatMap(evaluate)
|
parse(peggyCode)
|
||||||
|
->E.R2.errMap(e => e->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue)
|
||||||
|
->Result.flatMap(evaluate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,18 @@ module T = Reducer_T
|
||||||
|
|
||||||
type errorValue = BErrorValue.errorValue
|
type errorValue = BErrorValue.errorValue
|
||||||
type expression = Reducer_T.expression
|
type expression = Reducer_T.expression
|
||||||
|
type expressionContent = Reducer_T.expressionContent
|
||||||
|
|
||||||
let eArray = (anArray: array<T.expression>) => anArray->T.EArray
|
let eArray = (anArray: array<T.expression>): expressionContent => anArray->T.EArray
|
||||||
|
|
||||||
let eBool = aBool => aBool->T.IEvBool->T.EValue
|
let eBool = aBool => aBool->T.IEvBool->T.EValue
|
||||||
|
|
||||||
let eCall = (fn: expression, args: array<expression>): expression => T.ECall(fn, args)
|
let eCall = (fn: expression, args: array<expression>): expressionContent => T.ECall(fn, args)
|
||||||
|
|
||||||
let eLambda = (parameters: array<string>, expr: expression) => T.ELambda(parameters, expr)
|
let eLambda = (parameters: array<string>, expr: expression): expressionContent => T.ELambda(
|
||||||
|
parameters,
|
||||||
|
expr,
|
||||||
|
)
|
||||||
|
|
||||||
let eNumber = aNumber => aNumber->T.IEvNumber->T.EValue
|
let eNumber = aNumber => aNumber->T.IEvNumber->T.EValue
|
||||||
|
|
||||||
|
@ -18,13 +22,13 @@ let eRecord = (aMap: array<(T.expression, T.expression)>) => aMap->T.ERecord
|
||||||
|
|
||||||
let eString = aString => aString->T.IEvString->T.EValue
|
let eString = aString => aString->T.IEvString->T.EValue
|
||||||
|
|
||||||
let eSymbol = (name: string): expression => T.ESymbol(name)
|
let eSymbol = (name: string): expressionContent => T.ESymbol(name)
|
||||||
|
|
||||||
let eBlock = (exprs: array<expression>): expression => T.EBlock(exprs)
|
let eBlock = (exprs: array<expression>): expressionContent => T.EBlock(exprs)
|
||||||
|
|
||||||
let eProgram = (exprs: array<expression>): expression => T.EProgram(exprs)
|
let eProgram = (exprs: array<expression>): expressionContent => T.EProgram(exprs)
|
||||||
|
|
||||||
let eLetStatement = (symbol: string, valueExpression: expression): expression => T.EAssign(
|
let eLetStatement = (symbol: string, valueExpression: expression): expressionContent => T.EAssign(
|
||||||
symbol,
|
symbol,
|
||||||
valueExpression,
|
valueExpression,
|
||||||
)
|
)
|
||||||
|
@ -33,11 +37,8 @@ let eTernary = (
|
||||||
predicate: expression,
|
predicate: expression,
|
||||||
trueCase: expression,
|
trueCase: expression,
|
||||||
falseCase: expression,
|
falseCase: expression,
|
||||||
): expression => T.ETernary(predicate, trueCase, falseCase)
|
): expressionContent => T.ETernary(predicate, trueCase, falseCase)
|
||||||
|
|
||||||
let eIdentifier = (name: string): expression => name->T.ESymbol
|
let eIdentifier = (name: string): expressionContent => name->T.ESymbol
|
||||||
|
|
||||||
// let eTypeIdentifier = (name: string): expression =>
|
let eVoid: expressionContent = T.IEvVoid->T.EValue
|
||||||
// name->T.IEvTypeIdentifier->T.EValue
|
|
||||||
|
|
||||||
let eVoid: expression = T.IEvVoid->T.EValue
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ let semicolonJoin = values =>
|
||||||
Converts the expression to String
|
Converts the expression to String
|
||||||
*/
|
*/
|
||||||
let rec toString = (expression: t) =>
|
let rec toString = (expression: t) =>
|
||||||
switch expression {
|
switch expression.content {
|
||||||
| EBlock(statements) =>
|
| EBlock(statements) =>
|
||||||
`{${Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin}}`
|
`{${Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin}}`
|
||||||
| EProgram(statements) => Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin
|
| EProgram(statements) => Js.Array2.map(statements, aValue => toString(aValue))->semicolonJoin
|
||||||
|
@ -31,13 +31,13 @@ let rec toString = (expression: t) =>
|
||||||
let toStringResult = codeResult =>
|
let toStringResult = codeResult =>
|
||||||
switch codeResult {
|
switch codeResult {
|
||||||
| Ok(a) => `Ok(${toString(a)})`
|
| Ok(a) => `Ok(${toString(a)})`
|
||||||
| Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${Reducer_ErrorValue.errorValueToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringResultOkless = codeResult =>
|
let toStringResultOkless = codeResult =>
|
||||||
switch codeResult {
|
switch codeResult {
|
||||||
| Ok(a) => toString(a)
|
| Ok(a) => toString(a)
|
||||||
| Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${Reducer_ErrorValue.errorValueToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
let inspect = (expr: t): t => {
|
let inspect = (expr: t): t => {
|
||||||
|
|
|
@ -12,21 +12,21 @@ zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
|
||||||
outerBlock
|
outerBlock
|
||||||
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
= statements:array_statements finalExpression: (statementSeparator @expression)?
|
||||||
{ if (finalExpression) statements.push(finalExpression)
|
{ if (finalExpression) statements.push(finalExpression)
|
||||||
return h.nodeProgram(statements) }
|
return h.nodeProgram(statements, location()) }
|
||||||
/ finalExpression: expression
|
/ finalExpression: expression
|
||||||
{ return h.nodeProgram([finalExpression]) }
|
{ return h.nodeProgram([finalExpression], location()) }
|
||||||
|
|
||||||
innerBlockOrExpression
|
innerBlockOrExpression
|
||||||
= quotedInnerBlock
|
= quotedInnerBlock
|
||||||
/ finalExpression: expression
|
/ finalExpression: expression
|
||||||
{ return h.nodeBlock([finalExpression])}
|
{ return h.nodeBlock([finalExpression], location())}
|
||||||
|
|
||||||
quotedInnerBlock
|
quotedInnerBlock
|
||||||
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
|
||||||
{ if (finalExpression) statements.push(finalExpression)
|
{ if (finalExpression) statements.push(finalExpression)
|
||||||
return h.nodeBlock(statements) }
|
return h.nodeBlock(statements, location()) }
|
||||||
/ '{' _nl finalExpression: expression _nl '}'
|
/ '{' _nl finalExpression: expression _nl '}'
|
||||||
{ return h.nodeBlock([finalExpression]) }
|
{ return h.nodeBlock([finalExpression], location()) }
|
||||||
|
|
||||||
array_statements
|
array_statements
|
||||||
= head:statement tail:(statementSeparator @array_statements )
|
= head:statement tail:(statementSeparator @array_statements )
|
||||||
|
@ -42,16 +42,16 @@ statement
|
||||||
voidStatement
|
voidStatement
|
||||||
= "call" _nl value:zeroOMoreArgumentsBlockOrExpression
|
= "call" _nl value:zeroOMoreArgumentsBlockOrExpression
|
||||||
{ var variable = h.nodeIdentifier("_", location());
|
{ var variable = h.nodeIdentifier("_", location());
|
||||||
return h.nodeLetStatement(variable, value); }
|
return h.nodeLetStatement(variable, value, location()); }
|
||||||
|
|
||||||
letStatement
|
letStatement
|
||||||
= variable:variable _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
|
= variable:variable _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
|
||||||
{ return h.nodeLetStatement(variable, value) }
|
{ return h.nodeLetStatement(variable, value, location()) }
|
||||||
|
|
||||||
defunStatement
|
defunStatement
|
||||||
= variable:variable '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression
|
= variable:variable '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression
|
||||||
{ var value = h.nodeLambda(args, body)
|
{ var value = h.nodeLambda(args, body, location())
|
||||||
return h.nodeLetStatement(variable, value) }
|
return h.nodeLetStatement(variable, value, location()) }
|
||||||
|
|
||||||
assignmentOp "assignment" = '='
|
assignmentOp "assignment" = '='
|
||||||
|
|
||||||
|
@ -67,16 +67,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 h.nodeTernary(condition, trueExpression, falseExpression) }
|
{ return h.nodeTernary(condition, trueExpression, falseExpression, location()) }
|
||||||
|
|
||||||
ternary
|
ternary
|
||||||
= condition:logicalAdditive _ '?' _nl trueExpression:logicalAdditive _ ':' _nl falseExpression:(ternary/logicalAdditive)
|
= condition:logicalAdditive _ '?' _nl trueExpression:logicalAdditive _ ':' _nl falseExpression:(ternary/logicalAdditive)
|
||||||
{ return h.nodeTernary(condition, trueExpression, falseExpression) }
|
{ return h.nodeTernary(condition, trueExpression, falseExpression, location()) }
|
||||||
|
|
||||||
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 h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
logicalAdditiveOp "operator" = '||'
|
logicalAdditiveOp "operator" = '||'
|
||||||
|
@ -85,21 +85,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 h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
logicalMultiplicativeOp "operator" = '&&'
|
logicalMultiplicativeOp "operator" = '&&'
|
||||||
|
|
||||||
equality
|
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], location())}
|
||||||
/ relational
|
/ relational
|
||||||
|
|
||||||
equalityOp "operator" = '=='/'!='
|
equalityOp "operator" = '=='/'!='
|
||||||
|
|
||||||
relational
|
relational
|
||||||
= left:additive _ operator:relationalOp _nl right:additive
|
= left:additive _ operator:relationalOp _nl right:additive
|
||||||
{ return h.makeFunctionCall(h.toFunction[operator], [left, right])}
|
{ return h.makeFunctionCall(h.toFunction[operator], [left, right], location())}
|
||||||
/ additive
|
/ additive
|
||||||
|
|
||||||
relationalOp "operator" = '<='/'<'/'>='/'>'
|
relationalOp "operator" = '<='/'<'/'>='/'>'
|
||||||
|
@ -107,7 +107,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 h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
additiveOp "operator" = '+' / '-' / '.+' / '.-'
|
additiveOp "operator" = '+' / '-' / '.+' / '.-'
|
||||||
|
@ -115,7 +115,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 h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
multiplicativeOp "operator" = '*' / '/' / '.*' / './'
|
multiplicativeOp "operator" = '*' / '/' / '.*' / './'
|
||||||
|
@ -123,7 +123,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 h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
powerOp "operator" = '^' / '.^'
|
powerOp "operator" = '^' / '.^'
|
||||||
|
@ -131,7 +131,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 h.makeFunctionCall(h.toFunction[element.operator], [result, element.right])
|
return h.makeFunctionCall(h.toFunction[element.operator], [result, element.right], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
credibleIntervalOp "operator" = 'to'
|
credibleIntervalOp "operator" = 'to'
|
||||||
|
@ -139,7 +139,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 h.makeFunctionCall(element.fnName, [result, ...element.args])
|
return h.makeFunctionCall(element.fnName, [result, ...element.args], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
chainedFunction
|
chainedFunction
|
||||||
|
@ -154,7 +154,7 @@ chainFunctionCall
|
||||||
|
|
||||||
unary
|
unary
|
||||||
= unaryOperator:unaryOperator _nl right:(unary/postOperator)
|
= unaryOperator:unaryOperator _nl right:(unary/postOperator)
|
||||||
{ return h.makeFunctionCall(h.unaryToFunction[unaryOperator], [right])}
|
{ return h.makeFunctionCall(h.unaryToFunction[unaryOperator], [right], location())}
|
||||||
/ postOperator
|
/ postOperator
|
||||||
|
|
||||||
unaryOperator "unary operator"
|
unaryOperator "unary operator"
|
||||||
|
@ -169,17 +169,17 @@ collectionElement
|
||||||
tail:(
|
tail:(
|
||||||
_ '[' _nl arg:expression _nl ']' {return {fn: h.postOperatorToFunction['[]'], args: [arg]}}
|
_ '[' _nl arg:expression _nl ']' {return {fn: h.postOperatorToFunction['[]'], args: [arg]}}
|
||||||
/ _ '(' _nl args:array_functionArguments _nl ')' {return {fn: h.postOperatorToFunction['()'], args: args}}
|
/ _ '(' _nl args:array_functionArguments _nl ')' {return {fn: h.postOperatorToFunction['()'], args: args}}
|
||||||
/ '.' arg:$dollarIdentifier {return {fn: h.postOperatorToFunction['[]'], args: [h.nodeString(arg)]}}
|
/ '.' arg:$dollarIdentifier {return {fn: h.postOperatorToFunction['[]'], args: [h.nodeString(arg, location())]}}
|
||||||
)*
|
)*
|
||||||
{ return tail.reduce(function(result, element) {
|
{ return tail.reduce(function(result, element) {
|
||||||
return h.makeFunctionCall(element.fn, [result, ...element.args])
|
return h.makeFunctionCall(element.fn, [result, ...element.args], location())
|
||||||
}, head)}
|
}, head)}
|
||||||
|
|
||||||
array_functionArguments
|
array_functionArguments
|
||||||
= head:expression tail:(_ ',' _nl @expression)*
|
= head:expression tail:(_ ',' _nl @expression)*
|
||||||
{ return [head, ...tail]; }
|
{ return [head, ...tail]; }
|
||||||
/ ""
|
/ ""
|
||||||
{return [h.nodeVoid()];}
|
{return [h.nodeVoid(location())];}
|
||||||
|
|
||||||
atom
|
atom
|
||||||
= '(' _nl expression:expression _nl ')' {return expression}
|
= '(' _nl expression:expression _nl ')' {return expression}
|
||||||
|
@ -195,7 +195,7 @@ basicLiteral
|
||||||
/ voidLiteral
|
/ voidLiteral
|
||||||
|
|
||||||
voidLiteral 'void'
|
voidLiteral 'void'
|
||||||
= "()" {return h.nodeVoid();}
|
= "()" {return h.nodeVoid(location());}
|
||||||
|
|
||||||
variable = dollarIdentifierWithModule / dollarIdentifier
|
variable = dollarIdentifierWithModule / dollarIdentifier
|
||||||
|
|
||||||
|
@ -221,36 +221,36 @@ dollarIdentifier '$identifier'
|
||||||
= ([\$_a-z]+[\$_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
= ([\$_a-z]+[\$_a-z0-9]i*) {return h.nodeIdentifier(text(), location())}
|
||||||
|
|
||||||
moduleIdentifier 'identifier'
|
moduleIdentifier 'identifier'
|
||||||
= ([A-Z]+[_a-z0-9]i*) {return h.nodeModuleIdentifier(text())}
|
= ([A-Z]+[_a-z0-9]i*) {return h.nodeModuleIdentifier(text(), location())}
|
||||||
|
|
||||||
|
|
||||||
string 'string'
|
string 'string'
|
||||||
= characters:("'" @([^'])* "'") {return h.nodeString(characters.join(''))}
|
= characters:("'" @([^'])* "'") {return h.nodeString(characters.join(''), location())}
|
||||||
/ characters:('"' @([^"])* '"') {return h.nodeString(characters.join(''))}
|
/ characters:('"' @([^"])* '"') {return h.nodeString(characters.join(''), location())}
|
||||||
|
|
||||||
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 h.makeFunctionCall('fromUnit_'+unit.value, [number])
|
{ return h.makeFunctionCall('fromUnit_'+unit.value, [number], location())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
integer 'integer'
|
integer 'integer'
|
||||||
= d+ !"\." ![e]i
|
= d+ !"\." ![e]i
|
||||||
{ return h.nodeInteger(parseInt(text()))}
|
{ return h.nodeInteger(parseInt(text()), location())}
|
||||||
|
|
||||||
float 'float'
|
float 'float'
|
||||||
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
|
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
|
||||||
{ return h.nodeFloat(parseFloat(text()))}
|
{ return h.nodeFloat(parseFloat(text()), location())}
|
||||||
|
|
||||||
floatExponent = [e]i '-'? d+
|
floatExponent = [e]i '-'? d+
|
||||||
d = [0-9]
|
d = [0-9]
|
||||||
|
|
||||||
boolean 'boolean'
|
boolean 'boolean'
|
||||||
= ('true'/'false') ! [a-z]i ! [_$]
|
= ('true'/'false') ! [a-z]i ! [_$]
|
||||||
{ return h.nodeBoolean(text() === 'true')}
|
{ return h.nodeBoolean(text() === 'true', location())}
|
||||||
|
|
||||||
valueConstructor
|
valueConstructor
|
||||||
= recordConstructor
|
= recordConstructor
|
||||||
|
@ -261,15 +261,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 h.nodeLambda(args, h.nodeBlock(statements)) }
|
return h.nodeLambda(args, h.nodeBlock(statements, location()), location()) }
|
||||||
/ '{' _nl '|' _nl args:array_parameters _nl '|' _nl finalExpression: expression _nl '}'
|
/ '{' _nl '|' _nl args:array_parameters _nl '|' _nl finalExpression: expression _nl '}'
|
||||||
{ return h.nodeLambda(args, finalExpression) }
|
{ return h.nodeLambda(args, finalExpression, location()) }
|
||||||
|
|
||||||
arrayConstructor 'array'
|
arrayConstructor 'array'
|
||||||
= '[' _nl ']'
|
= '[' _nl ']'
|
||||||
{ return h.constructArray([]); }
|
{ return h.constructArray([], location()); }
|
||||||
/ '[' _nl args:array_elements _nl ']'
|
/ '[' _nl args:array_elements _nl ']'
|
||||||
{ return h.constructArray(args); }
|
{ return h.constructArray(args, location()); }
|
||||||
|
|
||||||
array_elements
|
array_elements
|
||||||
= head:expression tail:(_ ',' _nl @expression)*
|
= head:expression tail:(_ ',' _nl @expression)*
|
||||||
|
@ -277,7 +277,7 @@ arrayConstructor 'array'
|
||||||
|
|
||||||
recordConstructor 'record'
|
recordConstructor 'record'
|
||||||
= '{' _nl args:array_recordArguments _nl end_of_record
|
= '{' _nl args:array_recordArguments _nl end_of_record
|
||||||
{ return h.constructRecord(args); }
|
{ return h.constructRecord(args, location()); }
|
||||||
|
|
||||||
end_of_record
|
end_of_record
|
||||||
= '}'
|
= '}'
|
||||||
|
@ -289,7 +289,7 @@ recordConstructor 'record'
|
||||||
|
|
||||||
keyValuePair
|
keyValuePair
|
||||||
= key:expression _ ':' _nl value:expression
|
= key:expression _ ':' _nl value:expression
|
||||||
{ return h.nodeKeyValue(key, value)}
|
{ return h.nodeKeyValue(key, value, location())}
|
||||||
|
|
||||||
// Separators
|
// Separators
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
module Extra = Reducer_Extra
|
module Extra = Reducer_Extra
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
type node = {"type": string}
|
type node = {"type": string, "location": Reducer_ErrorValue.location}
|
||||||
|
|
||||||
@module("./Reducer_Peggy_GeneratedParser.js") external parse__: string => node = "parse"
|
@module("./Reducer_Peggy_GeneratedParser.js")
|
||||||
|
external parse__: (string, {"grammarSource": string}) => node = "parse"
|
||||||
|
|
||||||
type withLocation = {"location": Reducer_ErrorValue.syntaxErrorLocation}
|
type withLocation = {"location": Reducer_ErrorValue.location}
|
||||||
external castWithLocation: Js.Exn.t => withLocation = "%identity"
|
external castWithLocation: Js.Exn.t => withLocation = "%identity"
|
||||||
|
|
||||||
let syntaxErrorToLocation = (error: Js.Exn.t): Reducer_ErrorValue.syntaxErrorLocation =>
|
let syntaxErrorToLocation = (error: Js.Exn.t): Reducer_ErrorValue.location =>
|
||||||
castWithLocation(error)["location"]
|
castWithLocation(error)["location"]
|
||||||
|
|
||||||
let parse = (expr: string): result<node, errorValue> =>
|
let parse = (expr: string, source: string): result<node, errorValue> =>
|
||||||
try {
|
try {
|
||||||
Ok(parse__(expr))
|
Ok(parse__(expr, {"grammarSource": source}))
|
||||||
} catch {
|
} catch {
|
||||||
| Js.Exn.Error(obj) =>
|
| Js.Exn.Error(obj) =>
|
||||||
RESyntaxError(Belt.Option.getExn(Js.Exn.message(obj)), syntaxErrorToLocation(obj)->Some)->Error
|
RESyntaxError(Belt.Option.getExn(Js.Exn.message(obj)), syntaxErrorToLocation(obj)->Some)->Error
|
||||||
|
@ -34,27 +35,30 @@ type nodeLetStatement = {...node, "variable": nodeIdentifier, "value": node}
|
||||||
type nodeModuleIdentifier = {...node, "value": string}
|
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 nodeVoid = node
|
type nodeVoid = node
|
||||||
|
|
||||||
type peggyNode =
|
type astContent =
|
||||||
| PgNodeBlock(nodeBlock)
|
| ASTBlock(nodeBlock)
|
||||||
| PgNodeProgram(nodeProgram)
|
| ASTProgram(nodeProgram)
|
||||||
| PgNodeArray(nodeArray)
|
| ASTArray(nodeArray)
|
||||||
| PgNodeRecord(nodeRecord)
|
| ASTRecord(nodeRecord)
|
||||||
| PgNodeBoolean(nodeBoolean)
|
| ASTBoolean(nodeBoolean)
|
||||||
| PgNodeFloat(nodeFloat)
|
| ASTFloat(nodeFloat)
|
||||||
| PgNodeCall(nodeCall)
|
| ASTCall(nodeCall)
|
||||||
| PgNodeIdentifier(nodeIdentifier)
|
| ASTIdentifier(nodeIdentifier)
|
||||||
| PgNodeInteger(nodeInteger)
|
| ASTInteger(nodeInteger)
|
||||||
| PgNodeKeyValue(nodeKeyValue)
|
| ASTKeyValue(nodeKeyValue)
|
||||||
| PgNodeLambda(nodeLambda)
|
| ASTLambda(nodeLambda)
|
||||||
| PgNodeLetStatement(nodeLetStatement)
|
| ASTLetStatement(nodeLetStatement)
|
||||||
| PgNodeModuleIdentifier(nodeModuleIdentifier)
|
| ASTModuleIdentifier(nodeModuleIdentifier)
|
||||||
| PgNodeString(nodeString)
|
| ASTString(nodeString)
|
||||||
| PgNodeTernary(nodeTernary)
|
| ASTTernary(nodeTernary)
|
||||||
// | PgNodeTypeIdentifier(nodeTypeIdentifier)
|
| ASTVoid(nodeVoid)
|
||||||
| PgNodeVoid(nodeVoid)
|
|
||||||
|
type ast = {
|
||||||
|
location: location,
|
||||||
|
content: astContent,
|
||||||
|
}
|
||||||
|
|
||||||
external castNodeBlock: node => nodeBlock = "%identity"
|
external castNodeBlock: node => nodeBlock = "%identity"
|
||||||
external castNodeProgram: node => nodeProgram = "%identity"
|
external castNodeProgram: node => nodeProgram = "%identity"
|
||||||
|
@ -71,80 +75,87 @@ external castNodeLetStatement: node => nodeLetStatement = "%identity"
|
||||||
external castNodeModuleIdentifier: node => nodeModuleIdentifier = "%identity"
|
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 castNodeVoid: node => nodeVoid = "%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 nodeToAST = (node: node) => {
|
||||||
switch node["type"] {
|
let content = switch node["type"] {
|
||||||
| "Block" => node->castNodeBlock->PgNodeBlock
|
| "Block" => node->castNodeBlock->ASTBlock
|
||||||
| "Program" => node->castNodeBlock->PgNodeProgram
|
| "Program" => node->castNodeBlock->ASTProgram
|
||||||
| "Array" => node->castNodeArray->PgNodeArray
|
| "Array" => node->castNodeArray->ASTArray
|
||||||
| "Record" => node->castNodeRecord->PgNodeRecord
|
| "Record" => node->castNodeRecord->ASTRecord
|
||||||
| "Boolean" => node->castNodeBoolean->PgNodeBoolean
|
| "Boolean" => node->castNodeBoolean->ASTBoolean
|
||||||
| "Call" => node->castNodeCall->PgNodeCall
|
| "Call" => node->castNodeCall->ASTCall
|
||||||
| "Float" => node->castNodeFloat->PgNodeFloat
|
| "Float" => node->castNodeFloat->ASTFloat
|
||||||
| "Identifier" => node->castNodeIdentifier->PgNodeIdentifier
|
| "Identifier" => node->castNodeIdentifier->ASTIdentifier
|
||||||
| "Integer" => node->castNodeInteger->PgNodeInteger
|
| "Integer" => node->castNodeInteger->ASTInteger
|
||||||
| "KeyValue" => node->castNodeKeyValue->PgNodeKeyValue
|
| "KeyValue" => node->castNodeKeyValue->ASTKeyValue
|
||||||
| "Lambda" => node->castNodeLambda->PgNodeLambda
|
| "Lambda" => node->castNodeLambda->ASTLambda
|
||||||
| "LetStatement" => node->castNodeLetStatement->PgNodeLetStatement
|
| "LetStatement" => node->castNodeLetStatement->ASTLetStatement
|
||||||
| "ModuleIdentifier" => node->castNodeModuleIdentifier->PgNodeModuleIdentifier
|
| "ModuleIdentifier" => node->castNodeModuleIdentifier->ASTModuleIdentifier
|
||||||
| "String" => node->castNodeString->PgNodeString
|
| "String" => node->castNodeString->ASTString
|
||||||
| "Ternary" => node->castNodeTernary->PgNodeTernary
|
| "Ternary" => node->castNodeTernary->ASTTernary
|
||||||
// | "TypeIdentifier" => node->castNodeTypeIdentifier->PgNodeTypeIdentifier
|
| "Void" => node->castNodeVoid->ASTVoid
|
||||||
| "Void" => node->castNodeVoid->PgNodeVoid
|
|
||||||
| _ => raise(UnsupportedPeggyNodeType(node["type"]))
|
| _ => raise(UnsupportedPeggyNodeType(node["type"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
let rec pgToString = (peggyNode: peggyNode): string => {
|
{location: node["location"], content: content}
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodeIdentifierToAST = (node: nodeIdentifier) => {
|
||||||
|
{location: node["location"], content: node->ASTIdentifier}
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodeKeyValueToAST = (node: nodeKeyValue) => {
|
||||||
|
{location: node["location"], content: node->ASTKeyValue}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rec pgToString = (ast: ast): string => {
|
||||||
let argsToString = (args: array<nodeIdentifier>): string =>
|
let argsToString = (args: array<nodeIdentifier>): string =>
|
||||||
args->Js.Array2.map(arg => PgNodeIdentifier(arg)->pgToString)->Js.Array2.toString
|
args->Belt.Array.map(arg => arg->nodeIdentifierToAST->pgToString)->Js.Array2.toString
|
||||||
|
|
||||||
let nodesToStringUsingSeparator = (nodes: array<node>, separator: string): string =>
|
let nodesToStringUsingSeparator = (nodes: array<node>, separator: string): string =>
|
||||||
nodes->Js.Array2.map(toString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
nodes->Belt.Array.map(toString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
||||||
|
|
||||||
let pgNodesToStringUsingSeparator = (nodes: array<peggyNode>, separator: string): string =>
|
let pgNodesToStringUsingSeparator = (nodes: array<ast>, separator: string): string =>
|
||||||
nodes->Js.Array2.map(pgToString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
nodes->Belt.Array.map(pgToString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
||||||
|
|
||||||
switch peggyNode {
|
switch ast.content {
|
||||||
| PgNodeBlock(node)
|
| ASTBlock(node)
|
||||||
| PgNodeProgram(node) =>
|
| ASTProgram(node) =>
|
||||||
"{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}"
|
"{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}"
|
||||||
| PgNodeArray(node) => "[" ++ node["elements"]->nodesToStringUsingSeparator("; ") ++ "]"
|
| ASTArray(node) => "[" ++ node["elements"]->nodesToStringUsingSeparator("; ") ++ "]"
|
||||||
| PgNodeRecord(node) =>
|
| ASTRecord(node) =>
|
||||||
"{" ++
|
"{" ++
|
||||||
node["elements"]
|
node["elements"]
|
||||||
->Js.Array2.map(element => PgNodeKeyValue(element))
|
->Belt.Array.map(element => element->nodeKeyValueToAST)
|
||||||
->pgNodesToStringUsingSeparator(", ") ++ "}"
|
->pgNodesToStringUsingSeparator(", ") ++ "}"
|
||||||
| PgNodeBoolean(node) => node["value"]->Js.String.make
|
| ASTBoolean(node) => node["value"]->Js.String.make
|
||||||
| PgNodeCall(node) =>
|
| ASTCall(node) =>
|
||||||
"(" ++ node["fn"]->toString ++ " " ++ node["args"]->nodesToStringUsingSeparator(" ") ++ ")"
|
"(" ++ node["fn"]->toString ++ " " ++ node["args"]->nodesToStringUsingSeparator(" ") ++ ")"
|
||||||
| PgNodeFloat(node) => node["value"]->Js.String.make
|
| ASTFloat(node) => node["value"]->Js.String.make
|
||||||
| PgNodeIdentifier(node) => `:${node["value"]}`
|
| ASTIdentifier(node) => `:${node["value"]}`
|
||||||
| PgNodeInteger(node) => node["value"]->Js.String.make
|
| ASTInteger(node) => node["value"]->Js.String.make
|
||||||
| PgNodeKeyValue(node) => toString(node["key"]) ++ ": " ++ toString(node["value"])
|
| ASTKeyValue(node) => toString(node["key"]) ++ ": " ++ toString(node["value"])
|
||||||
| PgNodeLambda(node) =>
|
| ASTLambda(node) => "{|" ++ node["args"]->argsToString ++ "| " ++ node["body"]->toString ++ "}"
|
||||||
"{|" ++ node["args"]->argsToString ++ "| " ++ node["body"]->toString ++ "}"
|
| ASTLetStatement(node) =>
|
||||||
| PgNodeLetStatement(node) =>
|
pgToString(node["variable"]->nodeIdentifierToAST) ++ " = " ++ toString(node["value"])
|
||||||
pgToString(PgNodeIdentifier(node["variable"])) ++ " = " ++ toString(node["value"])
|
| ASTModuleIdentifier(node) => `@${node["value"]}`
|
||||||
| PgNodeModuleIdentifier(node) => `@${node["value"]}`
|
| ASTString(node) => `'${node["value"]->Js.String.make}'`
|
||||||
| PgNodeString(node) => `'${node["value"]->Js.String.make}'`
|
| ASTTernary(node) =>
|
||||||
| PgNodeTernary(node) =>
|
|
||||||
"(::$$_ternary_$$ " ++
|
"(::$$_ternary_$$ " ++
|
||||||
toString(node["condition"]) ++
|
toString(node["condition"]) ++
|
||||||
" " ++
|
" " ++
|
||||||
toString(node["trueExpression"]) ++
|
toString(node["trueExpression"]) ++
|
||||||
" " ++
|
" " ++
|
||||||
toString(node["falseExpression"]) ++ ")"
|
toString(node["falseExpression"]) ++ ")"
|
||||||
// | PgNodeTypeIdentifier(node) => `#${node["value"]}`
|
| ASTVoid(_node) => "()"
|
||||||
| PgNodeVoid(_node) => "()"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
and toString = (node: node): string => node->castNodeType->pgToString
|
and toString = (node: node): string => node->nodeToAST->pgToString
|
||||||
|
|
||||||
let toStringResult = (rNode: result<node, errorValue>): string =>
|
let toStringResult = (rNode: result<node, errorValue>): string =>
|
||||||
switch rNode {
|
switch rNode {
|
||||||
| Ok(node) => toString(node)
|
| Ok(node) => toString(node)
|
||||||
| Error(error) => `Error(${errorToString(error)})`
|
| Error(error) => `Error(${errorValueToString(error)})`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,62 +3,72 @@ module ExpressionT = Reducer_Expression_T
|
||||||
module Parse = Reducer_Peggy_Parse
|
module Parse = Reducer_Peggy_Parse
|
||||||
|
|
||||||
type expression = Reducer_T.expression
|
type expression = Reducer_T.expression
|
||||||
|
type expressionContent = Reducer_T.expressionContent
|
||||||
|
|
||||||
let rec fromNode = (node: Parse.node): expression => {
|
let rec fromNode = (node: Parse.node): expression => {
|
||||||
let caseBlock = nodeBlock =>
|
let ast = Parse.nodeToAST(node)
|
||||||
ExpressionBuilder.eBlock(nodeBlock["statements"]->Js.Array2.map(fromNode))
|
|
||||||
|
|
||||||
let caseProgram = nodeProgram =>
|
let content: expressionContent = {
|
||||||
ExpressionBuilder.eProgram(nodeProgram["statements"]->Js.Array2.map(fromNode))
|
let caseBlock = nodeBlock =>
|
||||||
|
ExpressionBuilder.eBlock(nodeBlock["statements"]->Js.Array2.map(fromNode))
|
||||||
|
|
||||||
let caseLambda = (nodeLambda: Parse.nodeLambda): expression => {
|
let caseProgram = nodeProgram =>
|
||||||
let args =
|
ExpressionBuilder.eProgram(nodeProgram["statements"]->Js.Array2.map(fromNode))
|
||||||
nodeLambda["args"]->Js.Array2.map((argNode: Parse.nodeIdentifier) => argNode["value"])
|
|
||||||
let body = nodeLambda["body"]->fromNode
|
|
||||||
|
|
||||||
ExpressionBuilder.eLambda(args, body)
|
let caseLambda = (nodeLambda: Parse.nodeLambda): expressionContent => {
|
||||||
|
let args =
|
||||||
|
nodeLambda["args"]->Js.Array2.map((argNode: Parse.nodeIdentifier) => argNode["value"])
|
||||||
|
let body = nodeLambda["body"]->fromNode
|
||||||
|
|
||||||
|
ExpressionBuilder.eLambda(args, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
let caseRecord = (nodeRecord): expressionContent => {
|
||||||
|
nodeRecord["elements"]
|
||||||
|
->Js.Array2.map(keyValueNode => (
|
||||||
|
keyValueNode["key"]->fromNode,
|
||||||
|
keyValueNode["value"]->fromNode,
|
||||||
|
))
|
||||||
|
->ExpressionBuilder.eRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ast.content {
|
||||||
|
| ASTBlock(nodeBlock) => caseBlock(nodeBlock)
|
||||||
|
| ASTProgram(nodeProgram) => caseProgram(nodeProgram)
|
||||||
|
| ASTArray(nodeArray) =>
|
||||||
|
ExpressionBuilder.eArray(nodeArray["elements"]->Js.Array2.map(fromNode))
|
||||||
|
| ASTRecord(nodeRecord) => caseRecord(nodeRecord)
|
||||||
|
| ASTBoolean(nodeBoolean) => ExpressionBuilder.eBool(nodeBoolean["value"])
|
||||||
|
| ASTCall(nodeCall) =>
|
||||||
|
ExpressionBuilder.eCall(fromNode(nodeCall["fn"]), nodeCall["args"]->Js.Array2.map(fromNode))
|
||||||
|
| ASTFloat(nodeFloat) => ExpressionBuilder.eNumber(nodeFloat["value"])
|
||||||
|
| ASTIdentifier(nodeIdentifier) => ExpressionBuilder.eSymbol(nodeIdentifier["value"])
|
||||||
|
| ASTInteger(nodeInteger) => ExpressionBuilder.eNumber(Belt.Int.toFloat(nodeInteger["value"]))
|
||||||
|
| ASTKeyValue(nodeKeyValue) =>
|
||||||
|
ExpressionBuilder.eArray([fromNode(nodeKeyValue["key"]), fromNode(nodeKeyValue["value"])])
|
||||||
|
| ASTLambda(nodeLambda) => caseLambda(nodeLambda)
|
||||||
|
| ASTLetStatement(nodeLetStatement) =>
|
||||||
|
ExpressionBuilder.eLetStatement(
|
||||||
|
nodeLetStatement["variable"]["value"],
|
||||||
|
fromNode(nodeLetStatement["value"]),
|
||||||
|
)
|
||||||
|
| ASTModuleIdentifier(nodeModuleIdentifier) =>
|
||||||
|
ExpressionBuilder.eIdentifier(nodeModuleIdentifier["value"])
|
||||||
|
| ASTString(nodeString) => ExpressionBuilder.eString(nodeString["value"])
|
||||||
|
| ASTTernary(nodeTernary) =>
|
||||||
|
ExpressionBuilder.eTernary(
|
||||||
|
fromNode(nodeTernary["condition"]),
|
||||||
|
fromNode(nodeTernary["trueExpression"]),
|
||||||
|
fromNode(nodeTernary["falseExpression"]),
|
||||||
|
)
|
||||||
|
// | PgNodeTypeIdentifier(nodeTypeIdentifier) =>
|
||||||
|
// ExpressionBuilder.eTypeIdentifier(nodeTypeIdentifier["value"])
|
||||||
|
| ASTVoid(_) => ExpressionBuilder.eVoid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let caseRecord = (nodeRecord): expression => {
|
{
|
||||||
nodeRecord["elements"]
|
ast: ast,
|
||||||
->Js.Array2.map(keyValueNode => (
|
content: content,
|
||||||
keyValueNode["key"]->fromNode,
|
|
||||||
keyValueNode["value"]->fromNode,
|
|
||||||
))
|
|
||||||
->ExpressionBuilder.eRecord
|
|
||||||
}
|
|
||||||
|
|
||||||
switch Parse.castNodeType(node) {
|
|
||||||
| PgNodeBlock(nodeBlock) => caseBlock(nodeBlock)
|
|
||||||
| PgNodeProgram(nodeProgram) => caseProgram(nodeProgram)
|
|
||||||
| PgNodeArray(nodeArray) =>
|
|
||||||
ExpressionBuilder.eArray(nodeArray["elements"]->Js.Array2.map(fromNode))
|
|
||||||
| PgNodeRecord(nodeRecord) => caseRecord(nodeRecord)
|
|
||||||
| PgNodeBoolean(nodeBoolean) => ExpressionBuilder.eBool(nodeBoolean["value"])
|
|
||||||
| PgNodeCall(nodeCall) =>
|
|
||||||
ExpressionBuilder.eCall(fromNode(nodeCall["fn"]), nodeCall["args"]->Js.Array2.map(fromNode))
|
|
||||||
| PgNodeFloat(nodeFloat) => ExpressionBuilder.eNumber(nodeFloat["value"])
|
|
||||||
| PgNodeIdentifier(nodeIdentifier) => ExpressionBuilder.eSymbol(nodeIdentifier["value"])
|
|
||||||
| PgNodeInteger(nodeInteger) => ExpressionBuilder.eNumber(Belt.Int.toFloat(nodeInteger["value"]))
|
|
||||||
| PgNodeKeyValue(nodeKeyValue) =>
|
|
||||||
ExpressionBuilder.eArray([fromNode(nodeKeyValue["key"]), fromNode(nodeKeyValue["value"])])
|
|
||||||
| PgNodeLambda(nodeLambda) => caseLambda(nodeLambda)
|
|
||||||
| PgNodeLetStatement(nodeLetStatement) =>
|
|
||||||
ExpressionBuilder.eLetStatement(
|
|
||||||
nodeLetStatement["variable"]["value"],
|
|
||||||
fromNode(nodeLetStatement["value"]),
|
|
||||||
)
|
|
||||||
| PgNodeModuleIdentifier(nodeModuleIdentifier) =>
|
|
||||||
ExpressionBuilder.eIdentifier(nodeModuleIdentifier["value"])
|
|
||||||
| PgNodeString(nodeString) => ExpressionBuilder.eString(nodeString["value"])
|
|
||||||
| PgNodeTernary(nodeTernary) =>
|
|
||||||
ExpressionBuilder.eTernary(
|
|
||||||
fromNode(nodeTernary["condition"]),
|
|
||||||
fromNode(nodeTernary["trueExpression"]),
|
|
||||||
fromNode(nodeTernary["falseExpression"]),
|
|
||||||
)
|
|
||||||
// | PgNodeTypeIdentifier(nodeTypeIdentifier) =>
|
|
||||||
// ExpressionBuilder.eTypeIdentifier(nodeTypeIdentifier["value"])
|
|
||||||
| PgNodeVoid(_) => ExpressionBuilder.eVoid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,83 +34,91 @@ export const postOperatorToFunction = {
|
||||||
"[]": "$_atIndex_$",
|
"[]": "$_atIndex_$",
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeBlock = {
|
type Node = {
|
||||||
|
location: LocationRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NodeBlock = Node & {
|
||||||
type: "Block";
|
type: "Block";
|
||||||
statements: AnyPeggyNode[];
|
statements: AnyPeggyNode[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeProgram = {
|
type NodeProgram = Node & {
|
||||||
type: "Program";
|
type: "Program";
|
||||||
statements: AnyPeggyNode[];
|
statements: AnyPeggyNode[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeArray = {
|
type NodeArray = Node & {
|
||||||
type: "Array";
|
type: "Array";
|
||||||
elements: AnyPeggyNode[];
|
elements: AnyPeggyNode[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeRecord = {
|
type NodeRecord = Node & {
|
||||||
type: "Record";
|
type: "Record";
|
||||||
elements: NodeKeyValue[];
|
elements: NodeKeyValue[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeCall = {
|
type NodeCall = Node & {
|
||||||
type: "Call";
|
type: "Call";
|
||||||
fn: AnyPeggyNode;
|
fn: AnyPeggyNode;
|
||||||
args: AnyPeggyNode[];
|
args: AnyPeggyNode[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeFloat = {
|
type NodeFloat = Node & {
|
||||||
type: "Float";
|
type: "Float";
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeInteger = {
|
type NodeInteger = Node & {
|
||||||
type: "Integer";
|
type: "Integer";
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeIdentifier = {
|
type NodeIdentifier = Node & {
|
||||||
type: "Identifier";
|
type: "Identifier";
|
||||||
value: string;
|
value: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeLetStatement = {
|
type NodeLetStatement = Node & {
|
||||||
type: "LetStatement";
|
type: "LetStatement";
|
||||||
variable: NodeIdentifier;
|
variable: NodeIdentifier;
|
||||||
value: AnyPeggyNode;
|
value: AnyPeggyNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeLambda = {
|
type NodeLambda = Node & {
|
||||||
type: "Lambda";
|
type: "Lambda";
|
||||||
args: AnyPeggyNode[];
|
args: AnyPeggyNode[];
|
||||||
body: AnyPeggyNode;
|
body: AnyPeggyNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeTernary = {
|
type NodeTernary = Node & {
|
||||||
type: "Ternary";
|
type: "Ternary";
|
||||||
condition: AnyPeggyNode;
|
condition: AnyPeggyNode;
|
||||||
trueExpression: AnyPeggyNode;
|
trueExpression: AnyPeggyNode;
|
||||||
falseExpression: AnyPeggyNode;
|
falseExpression: AnyPeggyNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeKeyValue = {
|
type NodeKeyValue = Node & {
|
||||||
type: "KeyValue";
|
type: "KeyValue";
|
||||||
key: AnyPeggyNode;
|
key: AnyPeggyNode;
|
||||||
value: AnyPeggyNode;
|
value: AnyPeggyNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeString = {
|
type NodeString = Node & {
|
||||||
type: "String";
|
type: "String";
|
||||||
value: string;
|
value: string;
|
||||||
location?: LocationRange;
|
location?: LocationRange;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeBoolean = {
|
type NodeBoolean = Node & {
|
||||||
type: "Boolean";
|
type: "Boolean";
|
||||||
value: boolean;
|
value: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NodeVoid = Node & {
|
||||||
|
type: "Void";
|
||||||
|
};
|
||||||
|
|
||||||
export type AnyPeggyNode =
|
export type AnyPeggyNode =
|
||||||
| NodeArray
|
| NodeArray
|
||||||
| NodeRecord
|
| NodeRecord
|
||||||
|
@ -125,47 +133,78 @@ export type AnyPeggyNode =
|
||||||
| NodeTernary
|
| NodeTernary
|
||||||
| NodeKeyValue
|
| NodeKeyValue
|
||||||
| NodeString
|
| NodeString
|
||||||
| NodeBoolean;
|
| NodeBoolean
|
||||||
|
| NodeVoid;
|
||||||
|
|
||||||
export function makeFunctionCall(fn: string, args: AnyPeggyNode[]) {
|
export function makeFunctionCall(
|
||||||
|
fn: string,
|
||||||
|
args: AnyPeggyNode[],
|
||||||
|
location: LocationRange
|
||||||
|
) {
|
||||||
if (fn === "$$_applyAll_$$") {
|
if (fn === "$$_applyAll_$$") {
|
||||||
return nodeCall(args[0], args.splice(1));
|
return nodeCall(args[0], args.splice(1), location);
|
||||||
} else {
|
} else {
|
||||||
return nodeCall(nodeIdentifier(fn), args);
|
return nodeCall(nodeIdentifier(fn, location), args, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function constructArray(elements: AnyPeggyNode[]) {
|
export function constructArray(
|
||||||
return { type: "Array", elements };
|
elements: AnyPeggyNode[],
|
||||||
|
location: LocationRange
|
||||||
|
): NodeArray {
|
||||||
|
return { type: "Array", elements, location };
|
||||||
}
|
}
|
||||||
export function constructRecord(elements: AnyPeggyNode[]) {
|
export function constructRecord(
|
||||||
return { type: "Record", elements };
|
elements: NodeKeyValue[],
|
||||||
|
location: LocationRange
|
||||||
|
): NodeRecord {
|
||||||
|
return { type: "Record", elements, location };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nodeBlock(statements: AnyPeggyNode[]): NodeBlock {
|
export function nodeBlock(
|
||||||
return { type: "Block", statements };
|
statements: AnyPeggyNode[],
|
||||||
|
location: LocationRange
|
||||||
|
): NodeBlock {
|
||||||
|
return { type: "Block", statements, location };
|
||||||
}
|
}
|
||||||
export function nodeProgram(statements: AnyPeggyNode[]): NodeProgram {
|
export function nodeProgram(
|
||||||
return { type: "Program", statements };
|
statements: AnyPeggyNode[],
|
||||||
|
location: LocationRange
|
||||||
|
): NodeProgram {
|
||||||
|
return { type: "Program", statements, location };
|
||||||
}
|
}
|
||||||
export function nodeBoolean(value: boolean): NodeBoolean {
|
export function nodeBoolean(
|
||||||
return { type: "Boolean", value };
|
value: boolean,
|
||||||
|
location: LocationRange
|
||||||
|
): NodeBoolean {
|
||||||
|
return { type: "Boolean", value, location };
|
||||||
}
|
}
|
||||||
export function nodeCall(fn: AnyPeggyNode, args: AnyPeggyNode[]): NodeCall {
|
export function nodeCall(
|
||||||
return { type: "Call", fn, args };
|
fn: AnyPeggyNode,
|
||||||
|
args: AnyPeggyNode[],
|
||||||
|
location: LocationRange
|
||||||
|
): NodeCall {
|
||||||
|
return { type: "Call", fn, args, location };
|
||||||
}
|
}
|
||||||
export function nodeFloat(value: number): NodeFloat {
|
export function nodeFloat(value: number, location: LocationRange): NodeFloat {
|
||||||
return { type: "Float", value };
|
return { type: "Float", value, location };
|
||||||
}
|
}
|
||||||
export function nodeIdentifier(value: string): NodeIdentifier {
|
export function nodeIdentifier(
|
||||||
return { type: "Identifier", value };
|
value: string,
|
||||||
|
location: LocationRange
|
||||||
|
): NodeIdentifier {
|
||||||
|
return { type: "Identifier", value, location };
|
||||||
}
|
}
|
||||||
export function nodeInteger(value: number): NodeInteger {
|
export function nodeInteger(
|
||||||
return { type: "Integer", value };
|
value: number,
|
||||||
|
location: LocationRange
|
||||||
|
): NodeInteger {
|
||||||
|
return { type: "Integer", value, location };
|
||||||
}
|
}
|
||||||
export function nodeKeyValue(
|
export function nodeKeyValue(
|
||||||
key: AnyPeggyNode,
|
key: AnyPeggyNode,
|
||||||
value: AnyPeggyNode
|
value: AnyPeggyNode,
|
||||||
|
location: LocationRange
|
||||||
): NodeKeyValue {
|
): NodeKeyValue {
|
||||||
if (key.type === "Identifier") {
|
if (key.type === "Identifier") {
|
||||||
key = {
|
key = {
|
||||||
|
@ -173,43 +212,43 @@ export function nodeKeyValue(
|
||||||
type: "String",
|
type: "String",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { type: "KeyValue", key, value };
|
return { type: "KeyValue", key, value, location };
|
||||||
}
|
}
|
||||||
export function nodeLambda(
|
export function nodeLambda(
|
||||||
args: AnyPeggyNode[],
|
args: AnyPeggyNode[],
|
||||||
body: AnyPeggyNode
|
body: AnyPeggyNode,
|
||||||
|
location: LocationRange
|
||||||
): NodeLambda {
|
): NodeLambda {
|
||||||
return { type: "Lambda", args, body };
|
return { type: "Lambda", args, body, location };
|
||||||
}
|
}
|
||||||
export function nodeLetStatement(
|
export function nodeLetStatement(
|
||||||
variable: NodeIdentifier,
|
variable: NodeIdentifier,
|
||||||
value: AnyPeggyNode
|
value: AnyPeggyNode,
|
||||||
|
location: LocationRange
|
||||||
): NodeLetStatement {
|
): NodeLetStatement {
|
||||||
return { type: "LetStatement", variable, value };
|
return { type: "LetStatement", variable, value, location };
|
||||||
}
|
}
|
||||||
export function nodeModuleIdentifier(value: string) {
|
export function nodeModuleIdentifier(value: string, location: LocationRange) {
|
||||||
return { type: "ModuleIdentifier", value };
|
return { type: "ModuleIdentifier", value, location };
|
||||||
}
|
}
|
||||||
export function nodeString(value: string): NodeString {
|
export function nodeString(value: string, location: LocationRange): NodeString {
|
||||||
return { type: "String", value };
|
return { type: "String", value, location };
|
||||||
}
|
}
|
||||||
export function nodeTernary(
|
export function nodeTernary(
|
||||||
condition: AnyPeggyNode,
|
condition: AnyPeggyNode,
|
||||||
trueExpression: AnyPeggyNode,
|
trueExpression: AnyPeggyNode,
|
||||||
falseExpression: AnyPeggyNode
|
falseExpression: AnyPeggyNode,
|
||||||
|
location: LocationRange
|
||||||
): NodeTernary {
|
): NodeTernary {
|
||||||
return {
|
return {
|
||||||
type: "Ternary",
|
type: "Ternary",
|
||||||
condition,
|
condition,
|
||||||
trueExpression,
|
trueExpression,
|
||||||
falseExpression,
|
falseExpression,
|
||||||
|
location,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nodeTypeIdentifier(typeValue: string) {
|
export function nodeVoid(location: LocationRange): NodeVoid {
|
||||||
return { type: "TypeIdentifier", value: typeValue };
|
return { type: "Void", location };
|
||||||
}
|
|
||||||
|
|
||||||
export function nodeVoid() {
|
|
||||||
return { type: "Void" };
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ and lambdaValue = {
|
||||||
body: lambdaBody,
|
body: lambdaBody,
|
||||||
}
|
}
|
||||||
@genType.opaque and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
@genType.opaque and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
||||||
and expression =
|
and expressionContent =
|
||||||
| EBlock(array<expression>)
|
| EBlock(array<expression>)
|
||||||
// programs are similar to blocks, but don't create an inner scope. there can be only one program at the top level of the expression.
|
// programs are similar to blocks, but don't create an inner scope. there can be only one program at the top level of the expression.
|
||||||
| EProgram(array<expression>)
|
| EProgram(array<expression>)
|
||||||
|
@ -35,6 +35,11 @@ and expression =
|
||||||
| ELambda(array<string>, expression)
|
| ELambda(array<string>, expression)
|
||||||
| EValue(value)
|
| EValue(value)
|
||||||
|
|
||||||
|
and expression = {
|
||||||
|
ast: Reducer_Peggy_Parse.ast,
|
||||||
|
content: expressionContent,
|
||||||
|
}
|
||||||
|
|
||||||
and namespace = Belt.Map.String.t<value>
|
and namespace = Belt.Map.String.t<value>
|
||||||
and bindings = {
|
and bindings = {
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
|
|
|
@ -79,24 +79,12 @@ let toStringResult = x =>
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringOptionResult = x =>
|
let toStringResultOkless = (codeResult: result<t, ErrorValue.error>): string =>
|
||||||
switch x {
|
|
||||||
| Some(a) => toStringResult(a)
|
|
||||||
| None => "None"
|
|
||||||
}
|
|
||||||
|
|
||||||
let toStringResultOkless = (codeResult: result<t, ErrorValue.errorValue>): string =>
|
|
||||||
switch codeResult {
|
switch codeResult {
|
||||||
| Ok(a) => toString(a)
|
| Ok(a) => toString(a)
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringResultRecord = x =>
|
|
||||||
switch x {
|
|
||||||
| Ok(a) => `Ok(${toStringMap(a)})`
|
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
|
||||||
}
|
|
||||||
|
|
||||||
type internalExpressionValueType =
|
type internalExpressionValueType =
|
||||||
| EvtArray
|
| EvtArray
|
||||||
| EvtBool
|
| EvtBool
|
||||||
|
|
|
@ -117,7 +117,7 @@ let getResultOption = (project: t, sourceId: string): ProjectItem.T.resultType =
|
||||||
|
|
||||||
let getResult = (project: t, sourceId: string): ProjectItem.T.resultArgumentType =>
|
let getResult = (project: t, sourceId: string): ProjectItem.T.resultArgumentType =>
|
||||||
switch getResultOption(project, sourceId) {
|
switch getResultOption(project, sourceId) {
|
||||||
| None => RENeedToRun->Error
|
| None => RENeedToRun->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue->Error
|
||||||
| Some(result) => result
|
| Some(result) => result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ let linkDependencies = (project: t, sourceId: string): Reducer_T.namespace => {
|
||||||
"__result__",
|
"__result__",
|
||||||
switch project->getResult(id) {
|
switch project->getResult(id) {
|
||||||
| Ok(result) => result
|
| Ok(result) => result
|
||||||
| Error(error) => error->Reducer_ErrorValue.ErrorException->raise
|
| Error(error) => error->Reducer_ErrorValue.ExceptionWithStackTrace->raise
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|
|
@ -4,8 +4,9 @@ module T = ReducerProject_ProjectItem_T
|
||||||
type projectItem = T.projectItem
|
type projectItem = T.projectItem
|
||||||
type t = T.t
|
type t = T.t
|
||||||
|
|
||||||
let emptyItem: projectItem = {
|
let emptyItem = (sourceId: string): projectItem => {
|
||||||
source: "",
|
source: "",
|
||||||
|
sourceId: sourceId,
|
||||||
rawParse: None,
|
rawParse: None,
|
||||||
expression: None,
|
expression: None,
|
||||||
continuation: Reducer_Namespace.make(),
|
continuation: Reducer_Namespace.make(),
|
||||||
|
@ -18,6 +19,7 @@ let emptyItem: projectItem = {
|
||||||
// source -> rawParse -> includes -> expression -> continuation -> result
|
// source -> rawParse -> includes -> expression -> continuation -> result
|
||||||
|
|
||||||
let getSource = (r: t): T.sourceType => r.source
|
let getSource = (r: t): T.sourceType => r.source
|
||||||
|
let getSourceId = (r: t): T.sourceType => r.sourceId
|
||||||
let getRawParse = (r: t): T.rawParseType => r.rawParse
|
let getRawParse = (r: t): T.rawParseType => r.rawParse
|
||||||
let getExpression = (r: t): T.expressionType => r.expression
|
let getExpression = (r: t): T.expressionType => r.expression
|
||||||
let getContinuation = (r: t): T.continuationArgumentType => r.continuation
|
let getContinuation = (r: t): T.continuationArgumentType => r.continuation
|
||||||
|
@ -29,7 +31,7 @@ let getDirectIncludes = (r: t): array<string> => r.directIncludes
|
||||||
let getIncludesAsVariables = (r: t): T.importAsVariablesType => r.includeAsVariables
|
let getIncludesAsVariables = (r: t): T.importAsVariablesType => r.includeAsVariables
|
||||||
|
|
||||||
let touchSource = (this: t): t => {
|
let touchSource = (this: t): t => {
|
||||||
let r = emptyItem
|
let r = emptyItem(this->getSourceId)
|
||||||
{
|
{
|
||||||
...r,
|
...r,
|
||||||
source: getSource(this),
|
source: getSource(this),
|
||||||
|
@ -41,8 +43,9 @@ let touchSource = (this: t): t => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let touchRawParse = (this: t): t => {
|
let touchRawParse = (this: t): t => {
|
||||||
|
let r = emptyItem(this->getSourceId)
|
||||||
{
|
{
|
||||||
...emptyItem,
|
...r,
|
||||||
source: getSource(this),
|
source: getSource(this),
|
||||||
continues: getContinues(this),
|
continues: getContinues(this),
|
||||||
includes: getIncludes(this),
|
includes: getIncludes(this),
|
||||||
|
@ -148,7 +151,8 @@ let parseIncludes = (this: t): t => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let doRawParse = (this: t): T.rawParseArgumentType => this->getSource->Reducer_Peggy_Parse.parse
|
let doRawParse = (this: t): T.rawParseArgumentType =>
|
||||||
|
this->getSource->Reducer_Peggy_Parse.parse(this.sourceId)
|
||||||
|
|
||||||
let rawParse = (this: t): t =>
|
let rawParse = (this: t): t =>
|
||||||
this->getRawParse->E.O2.defaultFn(() => doRawParse(this))->setRawParse(this, _)
|
this->getRawParse->E.O2.defaultFn(() => doRawParse(this))->setRawParse(this, _)
|
||||||
|
@ -167,7 +171,7 @@ let buildExpression = (this: t): t => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let failRun = (this: t, e: Reducer_ErrorValue.errorValue): t =>
|
let failRun = (this: t, e: Reducer_ErrorValue.error): t =>
|
||||||
this->setResult(e->Error)->setContinuation(Reducer_Namespace.make())
|
this->setResult(e->Error)->setContinuation(Reducer_Namespace.make())
|
||||||
|
|
||||||
let doRun = (this: t, context: Reducer_T.context): t =>
|
let doRun = (this: t, context: Reducer_T.context): t =>
|
||||||
|
@ -181,12 +185,24 @@ let doRun = (this: t, context: Reducer_T.context): t =>
|
||||||
->setResult(result->Ok)
|
->setResult(result->Ok)
|
||||||
->setContinuation(contextAfterEvaluation.bindings->Reducer_Bindings.locals)
|
->setContinuation(contextAfterEvaluation.bindings->Reducer_Bindings.locals)
|
||||||
} catch {
|
} catch {
|
||||||
| Reducer_ErrorValue.ErrorException(e) => this->failRun(e)
|
| Reducer_ErrorValue.ErrorException(e) =>
|
||||||
| _ => this->failRun(RETodo("unhandled rescript exception"))
|
this->failRun(e->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue)
|
||||||
|
| Reducer_ErrorValue.ExceptionWithStackTrace(e) => this->failRun(e)
|
||||||
|
| _ =>
|
||||||
|
this->failRun(
|
||||||
|
RETodo(
|
||||||
|
"unhandled rescript exception",
|
||||||
|
)->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
| Error(e) => this->failRun(e)
|
| Error(e) => this->failRun(e->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue)
|
||||||
}
|
}
|
||||||
| None => this->failRun(RETodo("attempt to run without expression"))
|
| None =>
|
||||||
|
this->failRun(
|
||||||
|
RETodo(
|
||||||
|
"attempt to run without expression",
|
||||||
|
)->Reducer_ErrorValue.attachEmptyStackTraceToErrorValue,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let run = (this: t, context: Reducer_T.context): t => {
|
let run = (this: t, context: Reducer_T.context): t => {
|
||||||
|
|
|
@ -11,7 +11,7 @@ type expressionType = option<expressionArgumentType>
|
||||||
type continuationArgumentType = Reducer_T.namespace
|
type continuationArgumentType = Reducer_T.namespace
|
||||||
type continuationType = option<continuationArgumentType>
|
type continuationType = option<continuationArgumentType>
|
||||||
type continuationResultType = option<result<continuationArgumentType, errorValue>>
|
type continuationResultType = option<result<continuationArgumentType, errorValue>>
|
||||||
type resultArgumentType = result<Reducer_T.value, errorValue>
|
type resultArgumentType = result<Reducer_T.value, error>
|
||||||
type resultType = option<resultArgumentType>
|
type resultType = option<resultArgumentType>
|
||||||
type continuesArgumentType = array<string>
|
type continuesArgumentType = array<string>
|
||||||
type continuesType = array<string>
|
type continuesType = array<string>
|
||||||
|
@ -21,6 +21,7 @@ type importAsVariablesType = array<(string, string)>
|
||||||
|
|
||||||
type projectItem = {
|
type projectItem = {
|
||||||
source: sourceType,
|
source: sourceType,
|
||||||
|
sourceId: string,
|
||||||
rawParse: rawParseType,
|
rawParse: rawParseType,
|
||||||
expression: expressionType,
|
expression: expressionType,
|
||||||
continuation: continuationArgumentType,
|
continuation: continuationArgumentType,
|
||||||
|
|
|
@ -13,4 +13,4 @@ type t = project
|
||||||
let getSourceIds = (project: t): array<string> => Belt.MutableMap.String.keysToArray(project.items)
|
let getSourceIds = (project: t): array<string> => Belt.MutableMap.String.keysToArray(project.items)
|
||||||
|
|
||||||
let getItem = (project: t, sourceId: string) =>
|
let getItem = (project: t, sourceId: string) =>
|
||||||
Belt.MutableMap.String.getWithDefault(project.items, sourceId, ProjectItem.emptyItem)
|
Belt.MutableMap.String.getWithDefault(project.items, sourceId, ProjectItem.emptyItem(sourceId))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user