Change record syntax, fix a few bugs
This commit is contained in:
parent
13a66f2d16
commit
e389e46852
7 changed files with 212 additions and 114 deletions
|
|
@ -47,7 +47,7 @@ const DELIMITER_CHARS = ["(", ")", "{", "}", ".", ",", "@", "$", "#", '"', "\\"]
|
|||
export type Delimiter = typeof DELIMITER_CHARS[number];
|
||||
const DELIMITER_SET: Set<CodePoint> = new Set(DELIMITER_CHARS.map(c => char(c)));
|
||||
|
||||
const KEYWORD_LIST = ["let" , "fn" , "match" , "apply" , "=" , "|" , "!"] as const;
|
||||
const KEYWORD_LIST = ["let" , "fn" , "match" , "apply" , "=" , "|" , "!", ":"] as const;
|
||||
export type Keyword = typeof KEYWORD_LIST[number];
|
||||
const KEYWORD_SET: Set<string> = new Set(KEYWORD_LIST);
|
||||
|
||||
|
|
@ -61,13 +61,14 @@ export type ExprScanError =
|
|||
|
||||
// What kind of identifier were we trying to parse?
|
||||
export type IdentifierKind =
|
||||
| "identifier"
|
||||
| "variable_use"
|
||||
| "field_name"
|
||||
| "tag_construction"
|
||||
| "function_call"
|
||||
| "pattern_binding";
|
||||
|
||||
export type IdentifierErrorReason =
|
||||
| { tag: "Empty" }
|
||||
| { tag: "StartsWithDigit" }
|
||||
| { tag: "IsKeyword", kw: Keyword }
|
||||
|
||||
|
|
@ -80,7 +81,6 @@ export type ExprStartToken =
|
|||
| { tag: "variable_use", name: string, span: Span }
|
||||
| { tag: "tag", name: string, span: Span }
|
||||
| { tag: "tuple_start", span: Span }
|
||||
| { tag: "record_start", span: Span }
|
||||
| { tag: "keyword", kw: Keyword, span: Span }
|
||||
// TODO: ger rid of EOF
|
||||
| { tag: "EOF", span: Span }
|
||||
|
|
@ -89,7 +89,7 @@ export type PatternStartToken =
|
|||
| { tag: "pattern_binding", name: string, span: Span }
|
||||
| { tag: "tag", name: string, span: Span }
|
||||
| { tag: "tuple_start", span: Span }
|
||||
| { tag: "record_start", span: Span }
|
||||
| { tag: "keyword", kw: Keyword, span: Span }
|
||||
// TODO: ger rid of EOF
|
||||
| { tag: "EOF", span: Span };
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ function rawIdentifier(cursor: Cursor): string {
|
|||
// Scans raw identifier,
|
||||
// checks if it is a keyword,
|
||||
// if it ain't, validates it into a proper identifier.
|
||||
function identifierOrKeyword(
|
||||
function identifierOrKeywordScanner(
|
||||
cursor: Cursor,
|
||||
kind: IdentifierKind,
|
||||
): { tag: "keyword", kw: Keyword, span: Span }
|
||||
|
|
@ -124,6 +124,15 @@ function identifierOrKeyword(
|
|||
const start = cursor.currentLocation();
|
||||
const text = rawIdentifier(cursor);
|
||||
const span = cursor.makeSpan(start);
|
||||
if (text.length === 0) {
|
||||
throw ({
|
||||
tag: "InvalidIdentifier",
|
||||
text,
|
||||
kind,
|
||||
reason: { tag: "Empty" },
|
||||
span
|
||||
} as ExprScanError);
|
||||
}
|
||||
|
||||
if (KEYWORD_SET.has(text)) {
|
||||
return { tag: "keyword", kw: text as Keyword, span };
|
||||
|
|
@ -142,8 +151,8 @@ function identifierOrKeyword(
|
|||
return { tag: "identifier", name: text, span };
|
||||
}
|
||||
|
||||
export function identifier(cursor: Cursor, kind: IdentifierKind): { name: string, span: Span } {
|
||||
const res = identifierOrKeyword(cursor, kind);
|
||||
export function identifierScanner(cursor: Cursor, kind: IdentifierKind): { name: string, span: Span } {
|
||||
const res = identifierOrKeywordScanner(cursor, kind);
|
||||
|
||||
if (res.tag === "keyword") {
|
||||
throw ({
|
||||
|
|
@ -201,14 +210,14 @@ export function exprStart(cursor: Cursor): ExprStartToken {
|
|||
// === variable use ===
|
||||
if (c === char('$')) {
|
||||
cursor.next();
|
||||
const { name } = identifier(cursor, 'variable_use');
|
||||
const { name } = identifierScanner(cursor, 'variable_use');
|
||||
return { tag: "variable_use", name, span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
// === tags ===
|
||||
if (c === char('#')) {
|
||||
cursor.next();
|
||||
const { name } = identifier(cursor, 'tag_construction');
|
||||
const { name } = identifierScanner(cursor, 'tag_construction');
|
||||
return { tag: "tag", name, span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
|
|
@ -219,15 +228,9 @@ export function exprStart(cursor: Cursor): ExprStartToken {
|
|||
return { tag: "tuple_start", span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
// === records ===
|
||||
if (c === char('{')) {
|
||||
cursor.next();
|
||||
return { tag: "record_start", span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
// === keywords & identifiers ===
|
||||
// Fallthrough: it must be a keyword or a function call
|
||||
const result = identifierOrKeyword(cursor, 'function_call');
|
||||
const result = identifierOrKeywordScanner(cursor, 'function_call');
|
||||
switch (result.tag) {
|
||||
case "keyword":
|
||||
return result;
|
||||
|
|
@ -250,16 +253,10 @@ export function patternStart(cursor: Cursor): PatternStartToken {
|
|||
return { tag: "tuple_start", span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
// === record ===
|
||||
if (c === char('{')) {
|
||||
cursor.next();
|
||||
return { tag: "record_start", span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
// === tag ===
|
||||
if (c === char('#')) {
|
||||
cursor.next();
|
||||
const { name } = identifier(cursor, 'tag_construction');
|
||||
const { name } = identifierScanner(cursor, 'tag_construction');
|
||||
return { tag: "tag", name, span: cursor.makeSpan(start) };
|
||||
}
|
||||
|
||||
|
|
@ -274,8 +271,14 @@ export function patternStart(cursor: Cursor): PatternStartToken {
|
|||
}
|
||||
|
||||
// === pattern binding ===
|
||||
const { name } = identifier(cursor, 'pattern_binding');
|
||||
return { tag: "pattern_binding", name, span: cursor.makeSpan(start) };
|
||||
// Fallthrough: it must be a keyword or a pattern-variable
|
||||
const result = identifierOrKeywordScanner(cursor, 'function_call');
|
||||
switch (result.tag) {
|
||||
case "keyword":
|
||||
return result;
|
||||
case "identifier":
|
||||
return { tag: "pattern_binding", name: result.name, span: result.span };
|
||||
}
|
||||
}
|
||||
|
||||
export function isNextTokenExprStart(cursor: Cursor): boolean {
|
||||
|
|
@ -289,7 +292,6 @@ export function isNextTokenExprStart(cursor: Cursor): boolean {
|
|||
case "variable_use":
|
||||
case "tag":
|
||||
case "tuple_start":
|
||||
case "record_start":
|
||||
case "function_name": // e.g. my_func(x)
|
||||
return true;
|
||||
|
||||
|
|
@ -299,6 +301,7 @@ export function isNextTokenExprStart(cursor: Cursor): boolean {
|
|||
case "fn":
|
||||
case "match":
|
||||
case "apply":
|
||||
case ":":
|
||||
return true;
|
||||
case "=":
|
||||
case "|":
|
||||
|
|
@ -327,8 +330,21 @@ export function isNextTokenProductPatternStart(cursor: Cursor): boolean {
|
|||
switch (token.tag) {
|
||||
case "pattern_binding":
|
||||
case "tuple_start":
|
||||
case "record_start":
|
||||
return true;
|
||||
|
||||
case "keyword":
|
||||
switch (token.kw) {
|
||||
case ":":
|
||||
return true;
|
||||
case "let":
|
||||
case "fn":
|
||||
case "match":
|
||||
case "apply":
|
||||
case "=":
|
||||
case "|":
|
||||
case "!":
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue