tstosc
Version:
A transpiler that convert TypeScript to SuperCollider's SCLang.
171 lines (168 loc) • 7.29 kB
TypeScript
import ts from 'typescript';
import { UserTranspileIntention } from '../../cli/args.js';
/**
*
* ### Warning
*
* Do NOT try to add any getter/setter here.
* Generator context uses spread syntax to copy, so setter and getter are not copied.
* Since it is used as a data class (a plain object), maybe it should be better if it remains simple.
*/
type GeneratorContext = {
/** The compiler program of the TypeScript Compiler API. */
readonly compiler_program: ts.Program;
/** The user option passed from command line. */
readonly transpiler_option: TranspilerOption;
/**
* Level of indent. Used for generating space for SCLang (**not** indent level in TypeScript).
*
* ### Guidelines for Indentation (advise from ChatGPT)
*
* * Always Explicit: Add indentation explicitly at the root of each converter,
* only if `is_standalone_statement` is true.
* * Child Responsibility: Nested converters should not add indentation;
* they assume the parent already handled it.
*/
indent_level: number;
/**
* If generating contents inside a class, this
*/
class_info: {
/** Name of current class. */
name: string;
/** Name of the super class. */
super_class_name: string;
};
/**
* Whether generating a SuperCollider's class method.
* Since in SCLang, method can have `^` as `return` in TypeScript.
*/
is_generating_method: boolean;
/**
* Whether generating a SuperCollider's class constructor.
* Since in SCLang, constructor must return the instance built.
*
* Related `tstosc` tags: `tstosc__built_instance`.
*/
is_generating_constructor: boolean;
/**
* Whether the identifier is a class.
*/
is_generating_class_name: boolean;
/**
* Whether generating a property/method object literal in TypeScript.
*/
is_generating_member_of_object_literal: boolean;
/**
* Whether in a function body that contains an early-return.
* Notice that this value is `false` when inside a method.
*/
with_early_return: boolean;
/**
* Whether a loop has `continue` or `break` statement.
*
* `null` if current context is not in a loop body,
* so no need to check.
*/
with_loop_interrupt: boolean | null;
/**
* The label of current statement.
* Will be empty (`""`) if no available label.
*/
statement_label: string;
/**
* This will affect the generation of statement in label ending condition.
* If current loop is a nested loop (inner loop), then use `loop_end.()` to exit, else `^nil`.
*/
is_nested_loop: boolean;
/**
* Semantic meaning of `break`.
*/
break_means: "nothing" | "end_switch_case" | "stop_a_loop";
/**
* Semantic meaning of `super`.
*/
super_means: "nothing" | "constructor" | "class_name" | "as_it_is";
/**
* This affects how `this` is converted:
* * `"parameter"`: `tstosc__this_param`.
* * `"built_instance"`: `tstosc__built_instance`
* * `"itself"`: `this`.
*/
this_coming_from: "nothing" | "object_literal_parameter" | "built_instance" | "itself";
/**
* A dictionary storing the `tstosc` generated temporary name for some expression,
* such as for postfix-self-increment (e.g. `a++`).
* When transpiling, expression that stores in this dict, when condition fulfilled,
* should be replaced by the name stored in this dict (and/or with some additional process).
*
* TODO: Should be cleared after leaving a scope.
*/
expression_temporise_dict: Map<ts.Expression, string>;
/**
* Whether stand-alone as a statement occupying one or more lines. Opposite to `at_value_position`.
* When stand-alone, in most condition, it occupies the whole line, or multiple lines.
* Indentation should be made at that time.
*
* Will be `true` at the initial state of generating.
*/
is_standalone_statement: boolean;
/** Create a new context with `indent_level` plus `level` (default `1`). */
indent: (level?: number) => GeneratorContext;
/** Create a new context with `indent_level` minus `level` (default `1`). */
outdent: (level?: number) => GeneratorContext;
/**
* Create a new context with
* `class_info: { name: info.name, super_class_name: returnUndefIfEmpty(info.super_class_name) ?? "Object" }`.
*/
withClassInfo: (info: {
name: string;
super_class_name?: string;
}) => GeneratorContext;
/** Create a new context with `at_value_position = value ?? true`. */
atValuePosition: (value?: boolean) => GeneratorContext;
/** Create a new context with `is_standalone_statement = value ?? true`. */
isStandalongStatement: (value?: boolean) => GeneratorContext;
/** Create a new context with `is_generating_method = value ?? true`. */
willGenerateMethod: (value?: boolean) => GeneratorContext;
/** Create a new context with `is_generating_constructor = value ?? true`. */
willGenerateConstructor: (value?: boolean) => GeneratorContext;
/** Create a new context with `is_generating_class_name = value ?? true`. */
willGenerateClassName: (value?: boolean) => GeneratorContext;
/** Create a new context with `is_generating_object_literal = value ?? true`. */
willGenerateMemberOfObjectLiteral: (value?: boolean) => GeneratorContext;
/** Create a new context with `with_early_return = value ?? true`. */
withEarlyReturn: (value?: boolean) => GeneratorContext;
/** Create a new context with `with_loop_interrupt = value ?? true`. */
withLoopInterrupt: (value?: boolean) => GeneratorContext;
/** Create a new context with `statement_label = value`. */
withStatementLabel: (value: string) => GeneratorContext;
/** Create a new context with `statement_label = ""`. */
clearedStatementLabel: () => GeneratorContext;
/** Create a new context with `is_nested_loop = value ?? true`. */
isNestedLoop: (value?: boolean) => GeneratorContext;
/** Create a new context with `break_means = value`. */
makeBreakMeans: (value: GeneratorContext["break_means"]) => GeneratorContext;
/** Create a new context with `super_means = value`. */
makeSuperMeans: (value: GeneratorContext["super_means"]) => GeneratorContext;
/** Create a new context with `this_coming_from = value`. */
makeThisComingFrom: (value: GeneratorContext["this_coming_from"]) => GeneratorContext;
} & ExceptionalSyntax;
type ExceptionalSyntax = {
/**
* Whether this file contains unhandled self-increment or self-decrement operator usage,
* such as `a++` or `--a`.
*
* If wrap-content is generated, this should be set to `false`.
*/
has_unhandled_self_indecr_operator: boolean;
};
type TranspilerOption = Omit<UserTranspileIntention, "type">;
declare const default_transpiler_option: TranspilerOption;
/**
* ### Warning
*
* Notice that default context's `compiler_program` is a empty program.
*/
declare const default_generator_context: GeneratorContext;
export { type ExceptionalSyntax, type GeneratorContext, type TranspilerOption, default_generator_context, default_transpiler_option };