51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
/**
|
|
* parser.ts - Unlambda parser.
|
|
*
|
|
* @author CismonX <admin@cismon.net>
|
|
* @license MIT
|
|
*/
|
|
|
|
import { Expression, FuncChar, FuncNoChar, WhiteSpace } from './language';
|
|
|
|
/**
|
|
* Parse result is a tuple `[E, R]`, where `E` is the parsed expression,
|
|
* and `R` is the unparsed code fragment.
|
|
*
|
|
* If `E` is `never`, or `R` is more than whitespaces and comments,
|
|
* the Unlambda code given to the parser is malformed.
|
|
*/
|
|
export type ParseResult = [Expression, string];
|
|
|
|
/**
|
|
* Parse the given Unlambda code. Returns a `ParseResult`.
|
|
*/
|
|
export type Parse<Code extends string> =
|
|
// `C` is the first character of the code, `R` is the rest.
|
|
Code extends `${infer C}${infer R}` ?
|
|
// Trim comment line.
|
|
C extends '#' ? Parse<R extends `${any}\n${infer N}` ? N : ''>
|
|
// Trim whitespace.
|
|
: C extends WhiteSpace ? Parse<R>
|
|
// Apply the result of two consective parse.
|
|
: C extends '`' ? ParseApply<Parse<R>>
|
|
// A single character function.
|
|
: C extends FuncNoChar ? [C, R]
|
|
// A `.x` or `?x` function.
|
|
: R extends `${infer C1}${infer R1}` ?
|
|
`${C}${C1}` extends FuncChar ? [`${C}${C1}`, R1] : [never, R]
|
|
: [never, R]
|
|
: [never, Code];
|
|
|
|
/**
|
|
* Given the left part (the "operator") of an application, parse
|
|
* the right part (the "operand").
|
|
*/
|
|
type ParseApply<L extends ParseResult> = ParseApplyResult<L[0], Parse<L[1]>>;
|
|
|
|
/**
|
|
* Given the parse result of two parts of an application, return
|
|
* the final parse result.
|
|
*/
|
|
type ParseApplyResult<L extends Expression, R extends ParseResult> =
|
|
[[L, R[0]], R[1]];
|