SharpTS Architecture

June 10, 2026 · View on GitHub

SharpTS is a TypeScript interpreter and compiler implemented in C# (.NET 10). It supports two execution modes:

  1. Interpretation - Tree-walking execution of TypeScript code
  2. AOT Compilation - Ahead-of-time compilation to .NET IL assemblies

This document explains how the compiler and interpreter work internally.


Pipeline Overview

flowchart TB
    subgraph Frontend
        A["Source Code (.ts file)"] --> B["Lexer (Lexer.cs)"]
        B --> C["Token Stream (List<Token>)"]
        C --> D["Parser (Parser.cs)"]
        D --> E["AST (List<Stmt>)"]
    end

    E --> F["TypeChecker (TypeChecker.cs)"]

    F --> G{Execution Mode}
    G -->|Interpret| H["Interpreter (Interpreter.cs)"]
    G -->|Compile| I["ILCompiler (ILCompiler.cs)"]

    H --> J[Execute Result]
    I --> K[".NET Assembly (.dll)"]

Entry Point: Program.cs orchestrates the pipeline based on command-line arguments:

  • No arguments → REPL mode
  • <file>.ts → Interpret file
  • --compile <file>.ts → Compile to .NET assembly

Frontend Components

Lexer (Lexer.cs, Token.cs)

The lexer performs single-pass tokenization, converting source text into a stream of tokens.

Token Types (58 total):

  • Keywords: class, function, const, let, if, while, for, return, etc.
  • Operators: +, -, *, /, ==, ===, &&, ||, ?., ??, etc.
  • Literals: NUMBER, STRING, IDENTIFIER
  • Template literals: TEMPLATE_HEAD, TEMPLATE_MIDDLE, TEMPLATE_TAIL

Example:

Input:  const x = 42;
Output: [CONST, IDENTIFIER("x"), EQUAL, NUMBER(42), SEMICOLON, EOF]

Parser (Parser.cs)

A recursive descent parser that builds an Abstract Syntax Tree from tokens.

Key Features:

  • Precedence climbing for expressions
  • Desugaring: for loops → while loops during parsing
  • Destructuring: let [a, b] = arr → temporary variable assignments
  • Arrow function detection with backtracking

Expression Precedence (lowest to highest):

Assignment → Ternary → NullishCoalescing → Or → And → BitwiseOr →
BitwiseXor → BitwiseAnd → Equality → Comparison → Shift → Term →
Factor → Exponentiation → Unary → Call → Primary

AST (AST.cs)

Immutable C# records representing the syntax tree.

Expressions (Expr):

Binary, Unary, Ternary, Logical          // Operators
Variable, Get, GetIndex, Set, SetIndex   // Data access
Literal, ArrayLiteral, ObjectLiteral     // Literals
Call, New, ArrowFunction                 // Functions
This, Super, Assign, CompoundAssign      // Special

Statements (Stmt):

Var, Function, Class, Interface, TypeAlias  // Declarations
If, While, DoWhile, ForOf, Switch           // Control flow
Block, Return, Break, Continue              // Structure
TryCatch, Throw                             // Errors

Type System

SharpTS performs static type checking before execution. Type errors prevent code from running.

flowchart LR
    subgraph "COMPILE-TIME (Types)"
        subgraph TypeEnvironment
            X["x → number"]
            Dog["Dog → Class"]
            Add["add → Func"]
        end
        subgraph TypeInfo
            P["Primitive(TYPE_NUMBER)"]
            C["Class('Dog', ...)"]
            F["Function([num], num)"]
        end
        TypeEnvironment -.-> TypeInfo
    end
    TC["TypeChecker.Check()"] --> TypeEnvironment

TypeInfo (TypeInfo.cs)

Abstract record hierarchy representing types:

TypeDescription
Primitivestring, number, boolean
FunctionParameter types, return type, required param count
ClassMethods, static members, superclass chain
InterfaceMember shapes for structural typing
InstanceReference to a class type
ArrayElement type
RecordObject literal shape {key: type}
Void, AnySpecial types

TypeChecker (TypeChecker.cs)

Validates type correctness using two typing strategies:

  • Nominal typing for classes: Inheritance chain must match
  • Structural typing for interfaces: Shape must match (duck typing)
interface Walkable { walk(): void }
class Dog { walk(): void { } }

let w: Walkable = new Dog();  // OK - Dog has walk() method

TypeEnvironment (TypeEnvironment.cs)

Scoped symbol table for type information. Supports nested scopes via Enclosing property.


Runtime System

Two-Environment Architecture

flowchart TB
    subgraph CT["COMPILE-TIME"]
        TE["TypeEnvironment stores TypeInfo records"]
        TQ["'What type is this variable?'"]
    end

    subgraph RT["RUNTIME"]
        RE["RuntimeEnvironment stores object? values"]
        RQ["'What value does this variable hold?'"]
    end

    CT -.->|"completely separate"| RT

These environments are completely separate. Type checking happens first; runtime never sees type information.

Interpreter (Interpreter.cs)

Tree-walking interpreter that executes validated AST:

  • Execute(Stmt) - Execute statements
  • Evaluate(Expr) - Evaluate expressions to values
  • ExecuteBlock(stmts, env) - Execute with scoped environment

RuntimeEnvironment (RuntimeEnvironment.cs)

Scoped symbol table for runtime values:

  • Define(name, value) - Create variable binding
  • Get(name) - Retrieve value
  • Assign(name, value) - Update existing binding

Runtime Objects

ClassPurpose
SharpTSClassClass metadata, methods, static members
SharpTSInstanceObject instance with field dictionary
SharpTSFunctionFunction with closure environment
SharpTSArrayArray with built-in methods
SharpTSObjectObject literal
SharpTSMathMath singleton

Control Flow

Normal control flow (return/break/continue) is signaled via the lightweight ExecutionResult struct (Execution/ExecutionResult.cs) — a discriminated union returned by statement execution, not exceptions. Two exceptions remain for genuinely non-local unwinding:

  • ThrowException - User-thrown errors (guest throw)
  • YieldException - Generator suspension

IL Compilation

The IL compiler translates TypeScript to .NET assemblies as an alternative to interpretation.

Multi-Phase Pipeline

The compiler runs through approximately 20 phases (with sub-phases) to handle the full complexity of TypeScript compilation:

flowchart TB
    P0["Phase 0: Extract .NET Namespace"] --> P1["Phase 1: Emit Runtime Types"]
    P1 --> P2["Phase 2: Closure Analysis"]
    P2 --> P3["Phase 3: Create $Program Type"]
    P3 --> P4["Phase 4: Define Classes/Functions/Enums"]
    P4 --> P4b["Phase 4.4-4.6: Captures, Interop, Registry"]
    P4b --> P5["Phase 5: Collect Arrow Functions"]
    P5 --> P5b["Phase 5.5-5.6: Class Expressions"]
    P5b --> P6["Phase 6: Emit Arrow Bodies"]
    P6 --> P6b["Phase 6.3-6.7: Methods & State Machines"]
    P6b --> P7["Phase 7: Emit Method Bodies"]
    P7 --> P7b["Phase 7.5: Class Expression Bodies"]
    P7b --> P8["Phase 8: Emit Entry Point"]
    P8 --> P9["Phase 9: Finalize Types"]

Key Phases:

PhaseDescription
0Extract @Namespace directive for .NET namespace
1Emit runtime support types (RuntimeTypes, TSFunction)
2Analyze closures to identify captured variables
3Create $Program container type
4Define all classes, functions, enums, namespaces
4.4-4.6Initialize captures, typed interop, type emitter registry
5Collect and define arrow functions
5.5-5.6Define class expression types and method signatures
6Emit arrow function bodies
6.3-6.7Define class methods, emit async/generator state machines
7Emit all method bodies
7.5Emit class expression bodies
8Emit Main() entry point
9Finalize all types, produce assembly

Key Components

ILCompiler (Compilation/ILCompiler.cs)

  • Main orchestrator running the compilation phases
  • Manages TypeBuilder instances
  • Coordinates closure handling and state machine generation

ILEmitter (Compilation/ILEmitter.cs)

  • Emits IL instructions for statements and expressions
  • Handles special cases: console.log, Math.*, array methods
  • Manages boxing/unboxing for value types

ClosureAnalyzer (Compilation/ClosureAnalyzer.cs)

  • Walks AST to find captured variables
  • Determines which arrows need display classes

RuntimeTypes (Compilation/RuntimeTypes.cs)

  • Emits helper types into the assembly
  • TSFunction: Wraps method references
  • RuntimeTypes: 50+ helper methods for TypeScript semantics

Closure Compilation

Non-capturing arrow → Static method on $Program:

static object? <>Arrow_0(object? x) { return x + 1; }

Capturing arrow → Display class with captured fields:

class <>c__DisplayClass0 {
    public object? capturedVar;
    public object? Invoke(object? arg) { return capturedVar + arg; }
}

Key Architectural Patterns

1. Two-Environment Separation

Types and values never mix:

  • TypeEnvironment + TypeInfo = compile-time
  • RuntimeEnvironment + object? = runtime

2. Discriminated Unions

AST nodes use C# records with pattern matching:

var result = expr switch {
    Expr.Binary b => HandleBinary(b),
    Expr.Call c => HandleCall(c),
    Expr.Variable v => HandleVariable(v),
    _ => throw new Exception("Unknown")
};

3. Visitor-Style Traversal

All phases use switch-based visitors on AST nodes:

  • TypeChecker.Check() / CheckExpr()
  • Interpreter.Execute() / Evaluate()
  • ILEmitter.EmitStatement() / EmitExpression()

4. Exception-Based Control Flow

Return, break, continue, and yield use exceptions for stack unwinding rather than complex state tracking.

5. ISharpTSPropertyAccessor Interface

Unified property access abstraction implemented by SharpTSObject and SharpTSInstance:

public interface ISharpTSPropertyAccessor {
    object? GetProperty(string name);
    void SetProperty(string name, object? value);
    bool HasProperty(string name);
    IEnumerable<string> PropertyNames { get; }
}

This reduces type-specific pattern matching in the interpreter and enables polymorphic property access.

6. State Machine Pattern

Async functions and generators compile to state machines:

  • State stored in generated display classes
  • MoveNext() method advances through suspension points
  • Separate analyzers identify yield/await points and hoisted variables

7. Type Emitter Registry

Pluggable IL emission for type-specific operations:

  • Registered emitters for String, Array, Date, Map, Set, RegExp, etc.
  • Allows specialized IL generation without monolithic switch statements
  • Static emitters for type constructors and static methods

File Reference

Core Pipeline

FilePurpose
Program.csEntry point, orchestrates pipeline
Parsing/Lexer.csTokenization
Parsing/Token.csToken types and representation
Parsing/Parser.csRecursive descent parser (10 partial files)
Parsing/AST.csAST node definitions
TypeSystem/TypeChecker.csStatic type analysis (20 partial files)
TypeSystem/TypeInfo.csType representations
TypeSystem/TypeEnvironment.csCompile-time symbol table
TypeSystem/TypeMap.csType mapping utilities
Execution/Interpreter.csTree-walking execution (see partial classes below)
Runtime/RuntimeEnvironment.csRuntime symbol table

Runtime Objects (31 files)

Core Types:

FilePurpose
SharpTSClass.csClass metadata and methods
SharpTSInstance.csObject instances (implements ISharpTSPropertyAccessor)
SharpTSFunction.csCallable functions with closures
SharpTSArray.csArray implementation
SharpTSObject.csObject literal (implements ISharpTSPropertyAccessor)
SharpTSMath.csMath object singleton
SharpTSEnum.csEnum implementation
ISharpTSPropertyAccessor.csUnified property access interface

Async & Promises:

FilePurpose
SharpTSPromise.csPromise implementation
SharpTSAsyncFunction.csAsync function wrapper

Generators:

FilePurpose
SharpTSGenerator.csGenerator return type
SharpTSGeneratorFunction.csGenerator function wrapper
SharpTSAsyncGenerator.csAsync generator return type
SharpTSAsyncGeneratorFunction.csAsync generator function wrapper
SharpTSIterator.csIterator protocol
SharpTSIteratorResult.csIterator result interface

Collections:

FilePurpose
SharpTSMap.csMap collection
SharpTSSet.csSet collection
SharpTSWeakMap.csWeakMap collection
SharpTSWeakSet.csWeakSet collection

Modern Types:

FilePurpose
SharpTSBigInt.csArbitrary precision integers
SharpTSDate.csDate object
SharpTSRegExp.csRegular expressions
SharpTSSymbol.csSymbol primitive

Other:

FilePurpose
SharpTSNamespace.csNamespace runtime object
ModuleInstance.csModule/namespace instance
SharpTSDecoratorContext.csDecorator metadata context
SharpTSPropertyDescriptor.csProperty descriptor support
ReflectMetadataStore.csReflection metadata storage
ConstEnumValues.csEnum constant values

Built-ins (24 files)

Core Built-ins:

FilePurpose
ArrayBuiltIns.csArray instance methods (push, pop, map, filter, etc.)
ArrayStaticBuiltIns.csArray static methods (Array.from, Array.isArray)
StringBuiltIns.csString methods (charAt, substring, etc.)
ObjectBuiltIns.csObject methods (keys, values, entries, etc.)
MathBuiltIns.csMath functions (sin, cos, sqrt, etc.)
NumberBuiltIns.csNumber static methods
BuiltInMethod.csBase class for built-in methods
BuiltInAsyncMethod.csBase class for async built-in methods
BuiltInTypes.csBuilt-in type definitions
BuiltInRegistry.csRegistry of all built-ins
BuiltInNamespace.csNamespace handling

Async & Generators:

FilePurpose
PromiseBuiltIns.csPromise constructor and methods
GeneratorBuiltIns.csGenerator methods
AsyncGeneratorBuiltIns.csAsync generator methods

Collections:

FilePurpose
MapBuiltIns.csMap methods
SetBuiltIns.csSet methods
WeakMapBuiltIns.csWeakMap methods
WeakSetBuiltIns.csWeakSet methods

Modern Types:

FilePurpose
DateBuiltIns.csDate constructor and methods
RegExpBuiltIns.csRegular expression methods
SymbolBuiltIns.csSymbol methods
JSONBuiltIns.csJSON.parse and JSON.stringify
ReflectBuiltIns.csReflect API methods

Control Flow (2 files)

Return/break/continue use the ExecutionResult struct (Execution/ExecutionResult.cs), not exceptions.

FilePurpose
ThrowException.csUser-thrown exceptions
YieldException.csYield expression control flow

IL Compilation (140+ files)

The compilation directory has grown substantially. Key organizational patterns:

ComponentFilesPurpose
ILCompiler.*.cs13Main orchestrator (partial classes for Classes, Async, Generators, etc.)
ILEmitter.*.cs12+IL emission (Calls, Expressions, Helpers, Modules, etc.)
RuntimeEmitter.*.cs31Runtime code emission (Arrays, Promises, Maps, etc.)
RuntimeTypes.*.cs16Runtime type emission (Arrays, Operators, Promise, etc.)
*MoveNextEmitter.cs20State machine emission for async/generators
*StateAnalyzer.cs3State analysis for async/generator transforms

Module System

FilePurpose
Modules/ModuleResolver.csModule path resolution
Modules/ParsedModule.csParsed module representation

Tooling & IDE Integration

Declaration Generation (Declaration/):

FilePurpose
DeclarationGenerator.cs.d.ts file generation
DotNetTypeMapper.cs.NET to TypeScript type mapping
TypeInspector.csType introspection
TypeScriptEmitter.csTypeScript syntax emission

Language Server Protocol (LspBridge/):

FilePurpose
LspBridge.csMain LSP bridge
Handlers/*.csCommand handlers for IDE features
Protocol/*.csRequest/response models

MSBuild Integration (SharpTS.Sdk.Tasks/):

FilePurpose
ReadTsConfigTask.cstsconfig.json processing
TsConfigModels.csConfiguration models

Partial Class Organization

Large classes are split across multiple files for maintainability:

Parser (Parsing/) - 10 files:

  • Parser.cs, Parser.Classes.cs, Parser.Declarations.cs, Parser.Decorators.cs
  • Parser.Destructuring.cs, Parser.Expressions.cs, Parser.Functions.cs
  • Parser.Modules.cs, Parser.Namespaces.cs, Parser.Statements.cs, Parser.Types.cs

TypeChecker (TypeSystem/) - 20 files:

  • Core: TypeChecker.cs, TypeChecker.Expressions.cs, TypeChecker.Operators.cs
  • Properties: TypeChecker.Properties.cs, TypeChecker.Properties.Index.cs, TypeChecker.Properties.New.cs
  • Statements: TypeChecker.Statements.cs, TypeChecker.Statements.Classes.cs, TypeChecker.Statements.ControlFlow.cs
  • Statements: TypeChecker.Statements.Enums.cs, TypeChecker.Statements.Functions.cs, TypeChecker.Statements.Interfaces.cs
  • Other: TypeChecker.Calls.cs, TypeChecker.Compatibility.cs, TypeChecker.Decorators.cs
  • Other: TypeChecker.Generics.cs, TypeChecker.Namespaces.cs, TypeChecker.Statements.Modules.cs
  • Other: TypeChecker.TypeParsing.cs, TypeChecker.Validation.cs

Interpreter (Execution/) - 11 files:

  • Interpreter.cs, Interpreter.Statements.cs, Interpreter.Expressions.cs
  • Interpreter.Properties.cs, Interpreter.Calls.cs, Interpreter.Operators.cs
  • Interpreter.Async.cs, Interpreter.Decorators.cs, Interpreter.Helpers.cs
  • Interpreter.Namespaces.cs, ExecutionResult.cs

ILEmitter (Compilation/) - 12+ files:

  • ILEmitter.cs, ILEmitter.Statements.cs, ILEmitter.Expressions.cs
  • ILEmitter.Properties.cs, ILEmitter.Calls.cs, ILEmitter.Operators.cs
  • ILEmitter.Helpers.cs, ILEmitter.Modules.cs, ILEmitter.Namespaces.cs
  • ILEmitter.StackTracking.cs, ILEmitter.ValueTypes.cs
  • ILEmitter.Calls.*.cs (multiple sub-files)

Async/Await & Promises

SharpTS supports async/await with a full Promise implementation.

Runtime Components

  • SharpTSPromise - Full Promise implementation with then, catch, finally
  • SharpTSAsyncFunction - Wrapper for async functions
  • PromiseBuiltIns - Static methods like Promise.all(), Promise.race(), Promise.resolve()

Compilation

Async functions compile to state machines:

  • AsyncStateAnalyzer - Analyzes suspension points (await expressions)
  • AsyncMoveNextEmitter - Generates MoveNext() method for state machine
  • State captured in display classes similar to closures

Generators

Full support for sync generators (function*) and async generators (async function*).

Runtime Components

  • SharpTSGenerator - Return type from generator functions
  • SharpTSGeneratorFunction - Generator function wrapper
  • SharpTSAsyncGenerator / SharpTSAsyncGeneratorFunction - Async variants
  • SharpTSIterator / SharpTSIteratorResult - Iterator protocol implementation
  • YieldException - Control flow for yield expressions

Compilation

Generators compile to state machines similar to async functions:

  • GeneratorStateAnalyzer - Identifies yield points and hoisted variables
  • GeneratorMoveNextEmitter - State machine implementation
  • AsyncGeneratorMoveNextEmitter - Combined async + generator state machine

Collections

ES6+ collection types with full method support.

TypeRuntime ClassBuilt-ins
Map<K,V>SharpTSMapMapBuiltIns
Set<T>SharpTSSetSetBuiltIns
WeakMap<K,V>SharpTSWeakMapWeakMapBuiltIns
WeakSet<T>SharpTSWeakSetWeakSetBuiltIns

All collections support iteration via for...of and destructuring.


Modern JavaScript Types

BigInt

  • SharpTSBigInt - Arbitrary precision integer arithmetic
  • Supports all arithmetic and comparison operators

Date

  • SharpTSDate - Full Date object implementation
  • DateBuiltIns - Constructor and instance methods

RegExp

  • SharpTSRegExp - Regular expression support
  • RegExpBuiltIns - test(), exec(), match(), etc.

Symbol

  • SharpTSSymbol - Symbol primitive for unique property keys
  • SymbolBuiltIns - Symbol.for(), Symbol.keyFor(), well-known symbols

JSON

  • JSONBuiltIns - JSON.parse() and JSON.stringify()

Namespaces & Decorators

Namespaces

TypeScript namespace support for organizing code:

  • SharpTSNamespace - Runtime namespace object
  • ModuleInstance - Module/namespace instance container
  • Namespaces can be nested and merged

Decorators

Stage 3 decorator support:

  • SharpTSDecoratorContext - Decorator metadata context
  • ReflectBuiltIns - Reflect API for metadata
  • ReflectMetadataStore - Runtime metadata storage
  • Supports class, method, accessor, and field decorators