Lesson 07-TypeScript Source Code Architecture

TypeScript Compiler Source Code

Compiler Architecture

Core Module Responsibilities:

// Simplified Compiler Architecture Workflow
function compile(program: Program): EmitResult {
  // 1. Parsing Phase
  const sourceFiles = program.getSourceFiles()
  const parser = new Parser(program)
  const syntaxTrees = sourceFiles.map(file => parser.parseFile(file))

  // 2. Type Checking Phase
  const checker = new TypeChecker(program)
  checker.typeCheck(syntaxTrees)

  // 3. Code Generation Phase
  const emitter = new Emitter(program)
  return emitter.emit(syntaxTrees)
}

// Class Diagram Relationships of Compiler Architecture
class Program {
  private sourceFiles: SourceFile[]
  private languageService: LanguageService
  // ...
}

class Parser {
  parseFile(file: SourceFile): SyntaxTree
}

class TypeChecker {
  typeCheck(syntaxTrees: SyntaxTree[]): void
}

class Emitter {
  emit(syntaxTrees: SyntaxTree[]): EmitResult
}

Lexical Analysis and Syntax Analysis

Scanner Implementation Key Code:

// Simplified Scanner Implementation
class Scanner {
  private sourceText: string
  private position: number = 0
  private token: SyntaxKind = SyntaxKind.Unknown

  scan(): SyntaxKind {
    while (this.position < this.sourceText.length) {
      const ch = this.sourceText.charCodeAt(this.position)
      
      switch (ch) {
        case CharacterCodes.Space:
        case CharacterCodes.Tab:
        case CharacterCodes.LineFeed:
          this.position++
          continue
        case CharacterCodes.DoubleQuote:
          return this.scanString()
        case CharacterCodes.IdentifierStart:
          return this.scanIdentifier()
        // ...other character handling
      }
    }
    return SyntaxKind.EndOfFileToken
  }

  private scanString(): SyntaxKind {
    // String literal scanning logic
  }

  private scanIdentifier(): SyntaxKind {
    // Identifier scanning logic
  }
}

Parser Syntax Tree Construction:

// Simplified Parser Implementation
class Parser {
  parseSourceFile(): SourceFile {
    const node = this.createNode(SyntaxKind.SourceFile)
    this.nextToken() // Skip initial token
    
    while (this.token !== SyntaxKind.EndOfFileToken) {
      const statement = this.parseStatement()
      node.statements.push(statement)
    }
    
    return this.finishNode(node)
  }

  private parseStatement(): Statement {
    switch (this.token) {
      case SyntaxKind.VarKeyword:
        return this.parseVariableStatement()
      case SyntaxKind.FunctionKeyword:
        return this.parseFunctionDeclaration()
      // ...other statement types
    }
  }
}

Type Checker

Core Type Checking Logic:

// Simplified Type Checking Workflow
class TypeChecker {
  private typeMap: Map<Node, Type> = new Map()

  typeCheck(node: Node): Type {
    if (this.typeMap.has(node)) {
      return this.typeMap.get(node)!
    }

    let type: Type
    switch (node.kind) {
      case SyntaxKind.Identifier:
        type = this.checkIdentifier(node as Identifier)
        break
      case SyntaxKind.BinaryExpression:
        type = this.checkBinaryExpression(node as BinaryExpression)
        break
      // ...other node types
    }

    this.typeMap.set(node, type)
    return type
  }

  private checkBinaryExpression(node: BinaryExpression): Type {
    const leftType = this.typeCheck(node.left)
    const rightType = this.typeCheck(node.right)
    
    if (!this.isTypeCompatible(leftType, rightType)) {
      this.error(node, DiagnosticMessages.IncompatibleTypes)
    }
    
    return this.getBinaryExpressionType(node.operatorToken, leftType, rightType)
  }
}

Code Generator

Emitter Implementation Key Code:

// Simplified Emitter Implementation
class Emitter {
  emit(sourceFile: SourceFile): EmitResult {
    const writer = new CodeWriter()
    this.emitNode(sourceFile, writer)
    return { outputFiles: writer.getOutputFiles() }
  }

  private emitNode(node: Node, writer: CodeWriter) {
    switch (node.kind) {
      case SyntaxKind.FunctionDeclaration:
        this.emitFunctionDeclaration(node as FunctionDeclaration, writer)
        break
      case SyntaxKind.VariableStatement:
        this.emitVariableStatement(node as VariableStatement, writer)
        break
      // ...other node types
    }
  }

  private emitFunctionDeclaration(node: FunctionDeclaration, writer: CodeWriter) {
    writer.write(`function ${node.name.text}(`)
    this.emitParameters(node.parameters, writer)
    writer.write(') {')
    this.emitBlock(node.body, writer)
    writer.write('}')
  }
}

Error Handling and Reporting

Error Diagnostic System:

// Error Reporting Implementation
class DiagnosticReporter {
  private diagnostics: Diagnostic[] = []

  report(node: Node, message: DiagnosticMessage, ...args: any[]) {
    const diagnostic: Diagnostic = {
      file: node.getSourceFile(),
      start: node.getStart(),
      length: node.getWidth(),
      messageText: formatMessage(message, args),
      category: DiagnosticCategory.Error,
      code: getErrorCode(message)
    }
    this.diagnostics.push(diagnostic)
  }

  getDiagnostics(): Diagnostic[] {
    return this.diagnostics
  }
}

// Error Message Definitions
namespace DiagnosticMessages {
  export const IncompatibleTypes = {
    category: DiagnosticCategory.Error,
    code: 2322,
    message: "Type '{0}' is not assignable to type '{1}'"
  }
  // ...other error messages
}
Share your love