class Steep::Project::SourceFile

def self.parse(source_code, path:, factory:)

def self.parse(source_code, path:, factory:)
  Source.parse(source_code, path: path.to_s, factory: factory, labeling: ASTUtils::Labeling.new)
end

def self.type_check(source, subtyping:)

def self.type_check(source, subtyping:)
  annotations = source.annotations(block: source.node, factory: subtyping.factory, current_module: AST::Namespace.root)
  const_env = TypeInference::ConstantEnv.new(factory: subtyping.factory, context: [AST::Namespace.root])
  type_env = TypeInference::TypeEnv.build(annotations: annotations,
                                          subtyping: subtyping,
                                          const_env: const_env,
                                          signatures: subtyping.factory.env)
  lvar_env = TypeInference::LocalVariableTypeEnv.empty(
    subtyping: subtyping,
    self_type: AST::Builtin::Object.instance_type
  ).annotate(annotations)
  context = TypeInference::Context.new(
    block_context: nil,
    module_context: TypeInference::Context::ModuleContext.new(
      instance_type: nil,
      module_type: nil,
      implement_name: nil,
      current_namespace: AST::Namespace.root,
      const_env: const_env,
      class_name: nil
    ),
    method_context: nil,
    break_context: nil,
    self_type: AST::Builtin::Object.instance_type,
    type_env: type_env,
    lvar_env: lvar_env
  )
  typing = Typing.new(source: source, root_context: context)
  construction = TypeConstruction.new(
    checker: subtyping,
    annotations: annotations,
    source: source,
    context: context,
    typing: typing
  )
  construction.synthesize(source.node) if source.node
  typing
end

def content=(content)

def content=(content)
  if @content != content
    @content_updated_at = Time.now
    @content = content
    @status = nil
  end
end

def errors

def errors
  case status
  when TypeCheckStatus
    status.typing.errors
  else
    []
  end
end

def initialize(path:)

def initialize(path:)
  @path = path
  @content = false
  self.content = ""
end

def parse(factory)

def parse(factory)
  if status.is_a?(TypeCheckStatus)
    yield status.source
  else
    yield self.class.parse(content, path: path, factory: factory)
  end
rescue AnnotationParser::SyntaxError => exn
  Steep.logger.warn { "Annotation syntax error on #{path}: #{exn.inspect}" }
  @status = AnnotationSyntaxErrorStatus.new(error: exn, location: exn.location)
rescue ::Parser::SyntaxError, EncodingError => exn
  Steep.logger.warn { "Source parsing error on #{path}: #{exn.inspect}" }
  @status = ParseErrorStatus.new(error: exn)
end

def type_check(subtyping, env_updated_at)

def type_check(subtyping, env_updated_at)
  # skip type check
  return false if status.is_a?(TypeCheckStatus) && env_updated_at <= status.timestamp
  parse(subtyping.factory) do |source|
    typing = self.class.type_check(source, subtyping: subtyping)
    @status = TypeCheckStatus.new(
      typing: typing,
      source: source,
      timestamp: Time.now
    )
  rescue => exn
    Steep.log_error(exn)
    @status = TypeCheckErrorStatus.new(error: exn)
  end
  true
end