Update to new source-region SourceRegion abstraction
This commit is contained in:
parent
38b147c3e7
commit
909caaf7ac
12 changed files with 63 additions and 52 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
import * as readline from 'readline';
|
import * as readline from 'readline';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { parseExpr, ParseError } from '../parser/parser';
|
import { parseExpr, ParseError } from '../parser/parser';
|
||||||
import { SourceText, renderSpan, sourceText } from 'source-text';
|
import { SourceRegion, SourceText, renderSpan, sourceText } from 'source-text';
|
||||||
import { exprToString } from '../debug/expr_show';
|
import { exprToString } from '../debug/expr_show';
|
||||||
import { valueToString } from '../debug/value_show';
|
import { valueToString } from '../debug/value_show';
|
||||||
import { Program } from '../program';
|
import { Program } from '../program';
|
||||||
|
|
@ -27,7 +27,7 @@ function runSource(inputRaw: string, isRepl: boolean): boolean {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Wrap in SourceText
|
// Wrap in SourceText
|
||||||
const text = sourceText(input);
|
const text = sourceText(input).fullRegion();
|
||||||
|
|
||||||
// === Parse ===
|
// === Parse ===
|
||||||
const parseResult = parseExpr(text);
|
const parseResult = parseExpr(text);
|
||||||
|
|
@ -184,7 +184,7 @@ function getErrorMessage(err: ParseError): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function printPrettyError(text: SourceText, err: ParseError) {
|
function printPrettyError(text: SourceRegion, err: ParseError) {
|
||||||
const msg = getErrorMessage(err);
|
const msg = getErrorMessage(err);
|
||||||
console.log(`\n${C.Red}${C.Bold}Parse Error:${C.Reset} ${C.Bold}${msg}${C.Reset}`);
|
console.log(`\n${C.Red}${C.Bold}Parse Error:${C.Reset} ${C.Bold}${msg}${C.Reset}`);
|
||||||
|
|
||||||
|
|
@ -213,3 +213,4 @@ function printPrettyError(text: SourceText, err: ParseError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// AI GENERATED
|
// AI GENERATED
|
||||||
import { SourceText } from "source-text";
|
import { SourceText, sourceText } from "source-text";
|
||||||
import { Cursor, scanString, scanNumber } from "./cursor";
|
import { Cursor, scanString, scanNumber } from "./cursor";
|
||||||
import { Result } from "../result";
|
import { Result } from "../result";
|
||||||
|
|
||||||
|
|
@ -53,13 +53,13 @@ function assertError(result: Result<any, any>, expectedTag: string, expectedReas
|
||||||
// === Number Tests ===
|
// === Number Tests ===
|
||||||
|
|
||||||
function test_integers() {
|
function test_integers() {
|
||||||
const src = new SourceText("123");
|
const src = sourceText("123").fullRegion();
|
||||||
const cursor = new Cursor(src);
|
const cursor = new Cursor(src);
|
||||||
const result = scanNumber(cursor);
|
const result = scanNumber(cursor);
|
||||||
|
|
||||||
assertOk(result, 123);
|
assertOk(result, 123);
|
||||||
|
|
||||||
const src2 = new SourceText("-500");
|
const src2 = sourceText("-500").fullRegion();
|
||||||
const cursor2 = new Cursor(src2);
|
const cursor2 = new Cursor(src2);
|
||||||
const result2 = scanNumber(cursor2);
|
const result2 = scanNumber(cursor2);
|
||||||
|
|
||||||
|
|
@ -69,12 +69,12 @@ function test_integers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_floats() {
|
function test_floats() {
|
||||||
const src = new SourceText("3.14159");
|
const src = sourceText("3.14159").fullRegion();
|
||||||
const cursor = new Cursor(src);
|
const cursor = new Cursor(src);
|
||||||
const result = scanNumber(cursor);
|
const result = scanNumber(cursor);
|
||||||
assertOk(result, 3.14159);
|
assertOk(result, 3.14159);
|
||||||
|
|
||||||
const src2 = new SourceText("-0.001");
|
const src2 = sourceText("-0.001").fullRegion();
|
||||||
const cursor2 = new Cursor(src2);
|
const cursor2 = new Cursor(src2);
|
||||||
const result2 = scanNumber(cursor2);
|
const result2 = scanNumber(cursor2);
|
||||||
assertOk(result2, -0.001);
|
assertOk(result2, -0.001);
|
||||||
|
|
@ -84,14 +84,14 @@ function test_floats() {
|
||||||
|
|
||||||
function test_number_errors() {
|
function test_number_errors() {
|
||||||
// 1. Trailing Dot
|
// 1. Trailing Dot
|
||||||
const c1 = new Cursor(new SourceText("1."));
|
const c1 = new Cursor(sourceText("1.").fullRegion());
|
||||||
const r1 = scanNumber(c1);
|
const r1 = scanNumber(c1);
|
||||||
assertError(r1, "InvalidNumber", "MissingFractionalDigits");
|
assertError(r1, "InvalidNumber", "MissingFractionalDigits");
|
||||||
|
|
||||||
// 2. No leading digit (.5)
|
// 2. No leading digit (.5)
|
||||||
|
|
||||||
// Let's test "Saw Sign but no digits" which is a hard error
|
// Let's test "Saw Sign but no digits" which is a hard error
|
||||||
const c2 = new Cursor(new SourceText("-")); // Just a minus
|
const c2 = new Cursor(sourceText("-").fullRegion()); // Just a minus
|
||||||
const r2 = scanNumber(c2);
|
const r2 = scanNumber(c2);
|
||||||
assertError(r2, "ExpectedNumber");
|
assertError(r2, "ExpectedNumber");
|
||||||
|
|
||||||
|
|
@ -101,13 +101,13 @@ function test_number_errors() {
|
||||||
// === String Tests ===
|
// === String Tests ===
|
||||||
|
|
||||||
function test_basic_strings() {
|
function test_basic_strings() {
|
||||||
const src = new SourceText('"hello world"');
|
const src = sourceText('"hello world"').fullRegion();
|
||||||
const cursor = new Cursor(src);
|
const cursor = new Cursor(src);
|
||||||
const result = scanString(cursor);
|
const result = scanString(cursor);
|
||||||
|
|
||||||
assertOk(result, "hello world");
|
assertOk(result, "hello world");
|
||||||
|
|
||||||
const src2 = new SourceText('""'); // Empty string
|
const src2 = sourceText('""').fullRegion(); // Empty string
|
||||||
const cursor2 = new Cursor(src2);
|
const cursor2 = new Cursor(src2);
|
||||||
const result2 = scanString(cursor2);
|
const result2 = scanString(cursor2);
|
||||||
|
|
||||||
|
|
@ -117,26 +117,26 @@ function test_basic_strings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_string_escapes() {
|
function test_string_escapes() {
|
||||||
const src = new SourceText('"line1\\nline2"');
|
const src = sourceText('"line1\\nline2"').fullRegion();
|
||||||
const cursor = new Cursor(src);
|
const cursor = new Cursor(src);
|
||||||
const result = scanString(cursor);
|
const result = scanString(cursor);
|
||||||
|
|
||||||
assertOk(result, "line1\nline2");
|
assertOk(result, "line1\nline2");
|
||||||
|
|
||||||
const src2 = new SourceText('"col1\\tcol2"');
|
const src2 = sourceText('"col1\\tcol2"').fullRegion();
|
||||||
const cursor2 = new Cursor(src2);
|
const cursor2 = new Cursor(src2);
|
||||||
const result2 = scanString(cursor2);
|
const result2 = scanString(cursor2);
|
||||||
|
|
||||||
assertOk(result2, "col1\tcol2");
|
assertOk(result2, "col1\tcol2");
|
||||||
|
|
||||||
const src3 = new SourceText('"quote: \\" slash: \\\\"');
|
const src3 = sourceText('"quote: \\" slash: \\\\"').fullRegion();
|
||||||
const cursor3 = new Cursor(src3);
|
const cursor3 = new Cursor(src3);
|
||||||
const result3 = scanString(cursor3);
|
const result3 = scanString(cursor3);
|
||||||
|
|
||||||
assertOk(result3, 'quote: " slash: \\');
|
assertOk(result3, 'quote: " slash: \\');
|
||||||
|
|
||||||
// Null byte test
|
// Null byte test
|
||||||
const src4 = new SourceText('"null\\0byte"');
|
const src4 = sourceText('"null\\0byte"').fullRegion();
|
||||||
const cursor4 = new Cursor(src4);
|
const cursor4 = new Cursor(src4);
|
||||||
const result4 = scanString(cursor4);
|
const result4 = scanString(cursor4);
|
||||||
assertOk(result4, "null\0byte");
|
assertOk(result4, "null\0byte");
|
||||||
|
|
@ -146,23 +146,23 @@ function test_string_escapes() {
|
||||||
|
|
||||||
function test_unicode_escapes() {
|
function test_unicode_escapes() {
|
||||||
// Rocket emoji: 🚀 (U+1F680)
|
// Rocket emoji: 🚀 (U+1F680)
|
||||||
const c1 = new Cursor(new SourceText('"\\u{1F680}"'));
|
const c1 = new Cursor(sourceText('"\\u{1F680}"').fullRegion());
|
||||||
assertOk(scanString(c1), "🚀");
|
assertOk(scanString(c1), "🚀");
|
||||||
|
|
||||||
// Two escapes
|
// Two escapes
|
||||||
const c2 = new Cursor(new SourceText('"\\u{41}\\u{42}"'));
|
const c2 = new Cursor(sourceText('"\\u{41}\\u{42}"').fullRegion());
|
||||||
assertOk(scanString(c2), "AB");
|
assertOk(scanString(c2), "AB");
|
||||||
|
|
||||||
// Error: Missing Brace
|
// Error: Missing Brace
|
||||||
const c3 = new Cursor(new SourceText('"\\u1F680"'));
|
const c3 = new Cursor(sourceText('"\\u1F680"').fullRegion());
|
||||||
assertError(scanString(c3), "InvalidEscape", { tag: "UnicodeMissingBrace" });
|
assertError(scanString(c3), "InvalidEscape", { tag: "UnicodeMissingBrace" });
|
||||||
|
|
||||||
// Error: Empty
|
// Error: Empty
|
||||||
const c4 = new Cursor(new SourceText('"\\u{}"'));
|
const c4 = new Cursor(sourceText('"\\u{}"').fullRegion());
|
||||||
assertError(scanString(c4), "InvalidEscape", { tag: "UnicodeNoDigits" });
|
assertError(scanString(c4), "InvalidEscape", { tag: "UnicodeNoDigits" });
|
||||||
|
|
||||||
// Error: Overflow
|
// Error: Overflow
|
||||||
const c5 = new Cursor(new SourceText('"\\u{110000}"'));
|
const c5 = new Cursor(sourceText('"\\u{110000}"').fullRegion());
|
||||||
const res5 = scanString(c5);
|
const res5 = scanString(c5);
|
||||||
// Need to check the value inside the reason for overflow
|
// Need to check the value inside the reason for overflow
|
||||||
if (res5.tag === 'ok') throw new Error("Should have failed overflow");
|
if (res5.tag === 'ok') throw new Error("Should have failed overflow");
|
||||||
|
|
@ -180,7 +180,7 @@ function test_cursor_tracking() {
|
||||||
// Line 2: 456 (LF)
|
// Line 2: 456 (LF)
|
||||||
// Line 3: "foo"
|
// Line 3: "foo"
|
||||||
const code = "123\r\n456\n\"foo\"";
|
const code = "123\r\n456\n\"foo\"";
|
||||||
const src = new SourceText(code);
|
const src = sourceText(code).fullRegion();
|
||||||
const cursor = new Cursor(src);
|
const cursor = new Cursor(src);
|
||||||
|
|
||||||
// 1. Scan 123
|
// 1. Scan 123
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { char, NEW_LINE, CARRIAGE_RETURN, DOT, DIGIT_0, DIGIT_9, LOWERCASE_a, LOWERCASE_f, UPPERCASE_A, UPPERCASE_F, SPACE, TAB } from 'source-text';
|
import { char, NEW_LINE, CARRIAGE_RETURN, DOT, DIGIT_0, DIGIT_9, LOWERCASE_a, LOWERCASE_f, UPPERCASE_A, UPPERCASE_F, SPACE, TAB } from 'source-text';
|
||||||
import type { SourceText, Span, SourceLocation, CodePoint, StringIndex, CodePointIndex } from 'source-text';
|
import type { SourceRegion, SourceText, Span, SourceLocation, CodePoint, StringIndex, CodePointIndex } from 'source-text';
|
||||||
import { Result } from '../result';
|
import { Result } from '../result';
|
||||||
|
|
||||||
export type CursorState = {
|
export type CursorState = {
|
||||||
|
|
@ -10,13 +10,21 @@ export type CursorState = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Cursor {
|
export class Cursor {
|
||||||
private index: CodePointIndex = 0;
|
private index: CodePointIndex;
|
||||||
private line: number = 1;
|
private line: number;
|
||||||
private column: number = 1;
|
private column: number;
|
||||||
// Track previous char to handle \r\n correctly
|
// Track previous char to handle \r\n correctly
|
||||||
private lastCharWasCR: boolean = false;
|
private lastCharWasCR: boolean = false;
|
||||||
|
|
||||||
constructor(readonly text: SourceText) {}
|
constructor(readonly region: SourceRegion) {
|
||||||
|
this.index = region.span.start.index;
|
||||||
|
this.line = region.span.start.line;
|
||||||
|
this.column = region.span.start.column;
|
||||||
|
}
|
||||||
|
|
||||||
|
get text(): SourceText {
|
||||||
|
return this.region.source;
|
||||||
|
}
|
||||||
|
|
||||||
save(): CursorState {
|
save(): CursorState {
|
||||||
return { index: this.index, line: this.line, column: this.column, lastCharWasCR: this.lastCharWasCR };
|
return { index: this.index, line: this.line, column: this.column, lastCharWasCR: this.lastCharWasCR };
|
||||||
|
|
@ -30,14 +38,16 @@ export class Cursor {
|
||||||
}
|
}
|
||||||
|
|
||||||
eof(): boolean {
|
eof(): boolean {
|
||||||
return this.index >= this.text.length;
|
return this.index >= this.region.span.end.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
peek(n: number = 0): CodePoint | undefined {
|
peek(n: number = 0): CodePoint | undefined {
|
||||||
|
if (this.index + n >= this.region.span.end.index) return undefined;
|
||||||
return this.text.chars[this.index + n]?.char;
|
return this.text.chars[this.index + n]?.char;
|
||||||
}
|
}
|
||||||
|
|
||||||
next(): CodePoint | undefined {
|
next(): CodePoint | undefined {
|
||||||
|
if (this.eof()) return undefined;
|
||||||
const ref = this.text.chars[this.index];
|
const ref = this.text.chars[this.index];
|
||||||
if (!ref) return undefined;
|
if (!ref) return undefined;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Cursor } from './cursor';
|
import { Cursor } from './cursor';
|
||||||
import { ExprScanError, exprStart, ExprStartToken, IdentifierKind, identifierScanner, isNextTokenExprStart, isNextTokenProductPatternStart, patternStart, PatternStartToken, signalExprStart, SignalExprStartToken, skipWhitespaceAndComments } from './scanner';
|
import { ExprScanError, exprStart, ExprStartToken, IdentifierKind, identifierScanner, isNextTokenExprStart, isNextTokenProductPatternStart, patternStart, PatternStartToken, signalExprStart, SignalExprStartToken, skipWhitespaceAndComments } from './scanner';
|
||||||
import { char, CodePoint, SourceText, Span } from 'source-text';
|
import { char, CodePoint, SourceRegion, SourceText, Span } from 'source-text';
|
||||||
import { Result } from '../result';
|
import { Result } from '../result';
|
||||||
import { Expr, ExprBinding, FieldAssignment, FieldPattern, FunctionName, MatchBranch, Pattern, ProductPattern, SignalExpr, SignalExprBinding } from '../expr';
|
import { Expr, ExprBinding, FieldAssignment, FieldPattern, FunctionName, MatchBranch, Pattern, ProductPattern, SignalExpr, SignalExprBinding } from '../expr';
|
||||||
|
|
||||||
|
|
@ -531,7 +531,7 @@ function recordPatternField(cursor: Cursor): FieldPattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function parseExpr(source: SourceText): Result<Expr, ParseError> {
|
export function parseExpr(source: SourceRegion): Result<Expr, ParseError> {
|
||||||
const cursor = new Cursor(source);
|
const cursor = new Cursor(source);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -553,7 +553,7 @@ export function parseExpr(source: SourceText): Result<Expr, ParseError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseSignalExpr(source: SourceText): Result<SignalExpr, ParseError> {
|
export function parseSignalExpr(source: SourceRegion): Result<SignalExpr, ParseError> {
|
||||||
const cursor = new Cursor(source);
|
const cursor = new Cursor(source);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -581,7 +581,7 @@ function functionParameters(cursor: Cursor): ProductPattern[] {
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseFunctionParameters(source: SourceText): Result<ProductPattern[], ParseError> {
|
export function parseFunctionParameters(source: SourceRegion): Result<ProductPattern[], ParseError> {
|
||||||
const cursor = new Cursor(source);
|
const cursor = new Cursor(source);
|
||||||
try {
|
try {
|
||||||
skipWhitespaceAndComments(cursor);
|
skipWhitespaceAndComments(cursor);
|
||||||
|
|
@ -603,7 +603,7 @@ export function parseFunctionParameters(source: SourceText): Result<ProductPatte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function parseFunctionName(source: SourceText): Result<FunctionName, ParseError> {
|
export function parseFunctionName(source: SourceRegion): Result<FunctionName, ParseError> {
|
||||||
const cursor = new Cursor(source);
|
const cursor = new Cursor(source);
|
||||||
try {
|
try {
|
||||||
skipWhitespaceAndComments(cursor);
|
skipWhitespaceAndComments(cursor);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ParseError } from "src/lang/parser/parser";
|
import { ParseError } from "src/lang/parser/parser";
|
||||||
import { renderSpan, SourceText } from "source-text";
|
import { renderSpan, SourceRegion } from "source-text";
|
||||||
import { DisplayLineViews } from "./LineView";
|
import { DisplayLineViews } from "./LineView";
|
||||||
|
|
||||||
export function formatErrorMesage(err: ParseError): string {
|
export function formatErrorMesage(err: ParseError): string {
|
||||||
|
|
@ -118,7 +118,7 @@ function formatChar(cp: number | undefined): string {
|
||||||
return `'${s}'`;
|
return `'${s}'`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ShowParseError(props: { text: SourceText, err: ParseError }) {
|
export function ShowParseError(props: { text: SourceRegion, err: ParseError }) {
|
||||||
const msg = () => formatErrorMesage(props.err);
|
const msg = () => formatErrorMesage(props.err);
|
||||||
const views = () => renderSpan(props.text, props.err.span, 3);
|
const views = () => renderSpan(props.text, props.err.span, 3);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { For, Match, Show, Switch } from "solid-js";
|
import { For, Match, Show, Switch } from "solid-js";
|
||||||
import { ParseError } from "src/lang/parser/parser";
|
import { ParseError } from "src/lang/parser/parser";
|
||||||
import { SourceText } from "source-text";
|
import { SourceRegion } from "source-text";
|
||||||
import { ShowParseError } from 'src/ui/Component/ParseError';
|
import { ShowParseError } from 'src/ui/Component/ParseError';
|
||||||
import { Program } from "src/lang/program";
|
import { Program } from "src/lang/program";
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ export type DigithError = {
|
||||||
|
|
||||||
export namespace DigithError {
|
export namespace DigithError {
|
||||||
export type Payload =
|
export type Payload =
|
||||||
| { tag: "Parse", err: ParseError, src: SourceText }
|
| { tag: "Parse", err: ParseError, src: SourceRegion }
|
||||||
| { tag: "Program", err: Program.Error };
|
| { tag: "Program", err: Program.Error };
|
||||||
|
|
||||||
export type Id = string;
|
export type Id = string;
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@ type Input = {
|
||||||
const validator: Validation<Input, Program.UpdateFunction, DigithError> = letValidate(
|
const validator: Validation<Input, Program.UpdateFunction, DigithError> = letValidate(
|
||||||
(input) => ({
|
(input) => ({
|
||||||
parameters: V.elseErr(validateParamsRaw(input.raw_params), err => ({
|
parameters: V.elseErr(validateParamsRaw(input.raw_params), err => ({
|
||||||
payload: { tag: "Parse", field: "params", err, src: sourceText(input.raw_params) },
|
payload: { tag: "Parse", field: "params", err, src: sourceText(input.raw_params).fullRegion() },
|
||||||
ids: ["params"],
|
ids: ["params"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Parameters" },
|
config: { title: "Parameters" },
|
||||||
})),
|
})),
|
||||||
body: V.elseErr(validateExprRaw(input.raw_body), err => ({
|
body: V.elseErr(validateExprRaw(input.raw_body), err => ({
|
||||||
payload: { tag: "Parse", field: "body", err, src: sourceText(input.raw_body) },
|
payload: { tag: "Parse", field: "body", err, src: sourceText(input.raw_body).fullRegion() },
|
||||||
ids: ["body"],
|
ids: ["body"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Function Body" },
|
config: { title: "Function Body" },
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,19 @@ type Input = {
|
||||||
const validator: Validation<Input, Program.CreateFunction, DigithError> = letValidate(
|
const validator: Validation<Input, Program.CreateFunction, DigithError> = letValidate(
|
||||||
(input) =>({
|
(input) =>({
|
||||||
name: V.elseErr(validateNameRaw(input.raw_name), err =>({
|
name: V.elseErr(validateNameRaw(input.raw_name), err =>({
|
||||||
payload: { tag: "Parse", err, src: sourceText(input.raw_name) },
|
payload: { tag: "Parse", err, src: sourceText(input.raw_name).fullRegion() },
|
||||||
ids: ["name"],
|
ids: ["name"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Function Name", display: "flat" },
|
config: { title: "Function Name", display: "flat" },
|
||||||
})),
|
})),
|
||||||
parameters: V.elseErr(validateParamsRaw(input.raw_params), err => ({
|
parameters: V.elseErr(validateParamsRaw(input.raw_params), err => ({
|
||||||
payload: { tag: "Parse", err, src: sourceText(input.raw_params) },
|
payload: { tag: "Parse", err, src: sourceText(input.raw_params).fullRegion() },
|
||||||
ids: ["params"],
|
ids: ["params"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Parameters", display: "flat" },
|
config: { title: "Parameters", display: "flat" },
|
||||||
})),
|
})),
|
||||||
body: V.elseErr(validateExprRaw(input.raw_body), err => ({
|
body: V.elseErr(validateExprRaw(input.raw_body), err => ({
|
||||||
payload: { tag: "Parse", err, src: sourceText(input.raw_body) },
|
payload: { tag: "Parse", err, src: sourceText(input.raw_body).fullRegion() },
|
||||||
ids: ["body"],
|
ids: ["body"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Function Body", display: "flat" },
|
config: { title: "Function Body", display: "flat" },
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useProgram } from 'src/ui/ProgramProvider';
|
||||||
import { eval_start } from 'src/lang/eval/evaluator';
|
import { eval_start } from 'src/lang/eval/evaluator';
|
||||||
import { Value } from 'src/lang/eval/value';
|
import { Value } from 'src/lang/eval/value';
|
||||||
import { RuntimeError } from 'src/lang/eval/error';
|
import { RuntimeError } from 'src/lang/eval/error';
|
||||||
import { SourceText, sourceText } from 'source-text';
|
import { SourceRegion, SourceText, sourceText } from 'source-text';
|
||||||
import { ParseError, parseExpr } from 'src/lang/parser/parser';
|
import { ParseError, parseExpr } from 'src/lang/parser/parser';
|
||||||
import { ShowParseError } from 'src/ui/Component/ParseError';
|
import { ShowParseError } from 'src/ui/Component/ParseError';
|
||||||
import { Val } from 'src/ui/Component/Value';
|
import { Val } from 'src/ui/Component/Value';
|
||||||
|
|
@ -15,7 +15,7 @@ namespace ReplResult {
|
||||||
export type Success =
|
export type Success =
|
||||||
{ tag: "success", value: Value }
|
{ tag: "success", value: Value }
|
||||||
export type Parse_Error =
|
export type Parse_Error =
|
||||||
{ tag: "parse_error", text: SourceText, err: ParseError }
|
{ tag: "parse_error", text: SourceRegion, err: ParseError }
|
||||||
export type Runtime_Error =
|
export type Runtime_Error =
|
||||||
{ tag: "runtime_error", err: RuntimeError }
|
{ tag: "runtime_error", err: RuntimeError }
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +39,7 @@ export function ExprREPL() {
|
||||||
if (input().trim() === "") {
|
if (input().trim() === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const text = sourceText(raw);
|
const text = sourceText(raw).fullRegion();
|
||||||
const parseResult = parseExpr(text);
|
const parseResult = parseExpr(text);
|
||||||
|
|
||||||
if (parseResult.tag === "error") {
|
if (parseResult.tag === "error") {
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@ type Input = {
|
||||||
const validator: Validation<Input, Program.CreateSignal, DigithError> = letValidate(
|
const validator: Validation<Input, Program.CreateSignal, DigithError> = letValidate(
|
||||||
(input) =>({
|
(input) =>({
|
||||||
name: V.elseErr(validateNameRaw(input.raw_name), err =>({
|
name: V.elseErr(validateNameRaw(input.raw_name), err =>({
|
||||||
payload: { tag: "Parse", err, src: sourceText(input.raw_name) },
|
payload: { tag: "Parse", err, src: sourceText(input.raw_name).fullRegion() },
|
||||||
ids: ["name"],
|
ids: ["name"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Signal Name", display: "flat" },
|
config: { title: "Signal Name", display: "flat" },
|
||||||
})),
|
})),
|
||||||
body: V.elseErr(validateSignalExprRaw(input.raw_body), err => ({
|
body: V.elseErr(validateSignalExprRaw(input.raw_body), err => ({
|
||||||
payload: { tag: "Parse", err, src: sourceText(input.raw_body) },
|
payload: { tag: "Parse", err, src: sourceText(input.raw_body).fullRegion() },
|
||||||
ids: ["body"],
|
ids: ["body"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Signal Body", display: "flat" },
|
config: { title: "Signal Body", display: "flat" },
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ type Input = {
|
||||||
const validator: Validation<Input, Program.UpdateSignal, DigithError> = letValidate(
|
const validator: Validation<Input, Program.UpdateSignal, DigithError> = letValidate(
|
||||||
(input) => ({
|
(input) => ({
|
||||||
body: V.elseErr(validateSignalExprRaw(input.raw_body), err => ({
|
body: V.elseErr(validateSignalExprRaw(input.raw_body), err => ({
|
||||||
payload: { tag: "Parse", field: "body", err, src: sourceText(input.raw_body) },
|
payload: { tag: "Parse", field: "body", err, src: sourceText(input.raw_body).fullRegion() },
|
||||||
ids: ["body"],
|
ids: ["body"],
|
||||||
tags: ["footer"],
|
tags: ["footer"],
|
||||||
config: { title: "Signal Body" },
|
config: { title: "Signal Body" },
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,25 @@ import { V } from "./";
|
||||||
|
|
||||||
// === Parser wrappers ===
|
// === Parser wrappers ===
|
||||||
export function validateNameRaw(input: string): V<FunctionName, ParseError> {
|
export function validateNameRaw(input: string): V<FunctionName, ParseError> {
|
||||||
const src = sourceText(input);
|
const src = sourceText(input).fullRegion();
|
||||||
const res = parseFunctionName(src);
|
const res = parseFunctionName(src);
|
||||||
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function validateParamsRaw(input: string): V<ProductPattern[], ParseError> {
|
export function validateParamsRaw(input: string): V<ProductPattern[], ParseError> {
|
||||||
const src = sourceText(input);
|
const src = sourceText(input).fullRegion();
|
||||||
const res = parseFunctionParameters(src);
|
const res = parseFunctionParameters(src);
|
||||||
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function validateExprRaw(input: string): V<Expr, ParseError> {
|
export function validateExprRaw(input: string): V<Expr, ParseError> {
|
||||||
const src = sourceText(input);
|
const src = sourceText(input).fullRegion();
|
||||||
const res = parseExpr(src);
|
const res = parseExpr(src);
|
||||||
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function validateSignalExprRaw(input: string): V<SignalExpr, ParseError> {
|
export function validateSignalExprRaw(input: string): V<SignalExpr, ParseError> {
|
||||||
const src = sourceText(input);
|
const src = sourceText(input).fullRegion();
|
||||||
const res = parseSignalExpr(src);
|
const res = parseSignalExpr(src);
|
||||||
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
return res.tag === "ok" ? V.ok(res.value) : V.errors([res.error]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue