~temp1
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt
index a18c26c..d1ecf47 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt
@@ -87,7 +87,7 @@
         val useSiteSession = analysisSession.useSiteSession
         if (classSymbol is KtFirScriptSymbol) {
             return KtFirDelegatingNamesAwareScope(
-                FirScriptDeclarationsScope(useSiteSession, classSymbol.firSymbol.fir),
+                FirScriptCodeFragmentDeclarationsScope(useSiteSession, classSymbol.firSymbol.fir),
                 builder,
             )
         }
@@ -242,7 +242,7 @@
         is FirDefaultSimpleImportingScope -> KtScopeKind.DefaultSimpleImportingScope(indexInTower)
         is FirDefaultStarImportingScope -> KtScopeKind.DefaultStarImportingScope(indexInTower)
 
-        is FirScriptDeclarationsScope -> KtScopeKind.ScriptMemberScope(indexInTower)
+        is FirScriptCodeFragmentDeclarationsScope -> KtScopeKind.ScriptMemberScope(indexInTower)
 
         else -> unexpectedElementError("scope", firScope)
     }
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirResolveTargetVisitor.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirResolveTargetVisitor.kt
index c9d2278..3a70a33 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirResolveTargetVisitor.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/targets/LLFirResolveTargetVisitor.kt
@@ -9,6 +9,7 @@
 import org.jetbrains.kotlin.fir.declarations.FirFile
 import org.jetbrains.kotlin.fir.declarations.FirRegularClass
 import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 
 /**
  * This interface describes how to process nested declarations.
@@ -32,6 +33,9 @@
      */
     fun withScript(firScript: FirScript, action: () -> Unit): Unit = action()
 
+
+    fun withSnippet(firSnippet: FirSnippet, action: () -> Unit): Unit = action()
+
     /**
      * This method will be performed on some target element depends on [LLFirResolveTarget] implementation.
      */
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAbstractBodyTargetResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAbstractBodyTargetResolver.kt
index 7556bb7..959166f 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAbstractBodyTargetResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAbstractBodyTargetResolver.kt
@@ -53,6 +53,10 @@
         transformer.context.withScript(firScript, transformer.components, action)
     }
 
+    override fun withSnippet(firSnippet: FirSnippet, action: () -> Unit) {
+        transformer.context.withSnippet(firSnippet, transformer.components, action)
+    }
+
     override fun withFile(firFile: FirFile, action: () -> Unit) {
         transformer.context.withFile(firFile, transformer.components, action)
     }
@@ -78,9 +82,12 @@
         target.transformSingle(transformer, ResolutionMode.ContextIndependent)
     }
 
-    protected fun resolveScript(script: FirScript) {
-        transformer.declarationsTransformer?.withScript(script) {
-            script.parameters.forEach { it.transformSingle(transformer, ResolutionMode.ContextIndependent) }
+
+    protected fun resolveScriptCodeFragment(script: FirScriptCodeFragment) {
+        transformer.declarationsTransformer?.withScriptCodeFragment(script) {
+            if (script is FirScript) {
+                script.parameters.forEach { it.transformSingle(transformer, ResolutionMode.ContextIndependent) }
+            }
             script.transformStatements(
                 transformer = object : FirTransformer<Any?>() {
                     override fun <E : FirElement> transformElement(element: E, data: Any?): E {
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAnnotationArgumentsLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAnnotationArgumentsLazyResolver.kt
index 057e09a..bab0133 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAnnotationArgumentsLazyResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirAnnotationArgumentsLazyResolver.kt
@@ -73,6 +73,14 @@
         super.withScript(firScript, actionWithCollector)
     }
 
+    override fun withSnippet(firSnippet: FirSnippet, action: () -> Unit) {
+        val actionWithCollector = actionWithContextCollector(action) { collector, context ->
+            collector.addDeclarationContext(firSnippet, context)
+        }
+
+        super.withSnippet(firSnippet, actionWithCollector)
+    }
+
     override fun withFile(firFile: FirFile, action: () -> Unit) {
         val actionWithCollector = actionWithContextCollector(action) { collector, context ->
             collector.addFileContext(firFile, context.towerDataContext)
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt
index 64339f4..ff98915 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt
@@ -254,7 +254,7 @@
 
     override fun rawResolve(target: FirElementWithResolveState) {
         when (target) {
-            is FirScript -> target.takeUnless(FirScript::isCertainlyResolved)?.let(::resolveScript)
+            is FirScriptCodeFragment -> target.takeUnless(FirScriptCodeFragment::isCertainlyResolved)?.let(::resolveScriptCodeFragment)
             else -> super.rawResolve(target)
         }
     }
@@ -414,11 +414,11 @@
     }
 }
 
-private fun FirScript.findResultProperty(): FirProperty? = statements.findIsInstanceAnd<FirProperty> {
+private fun FirScriptCodeFragment.findResultProperty(): FirProperty? = statements.findIsInstanceAnd<FirProperty> {
     it.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty
 }
 
-private val FirScript.isCertainlyResolved: Boolean
+private val FirScriptCodeFragment.isCertainlyResolved: Boolean
     get() {
         val dependentProperty = findResultProperty() ?: return false
 
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt
index c577797..734be0d 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt
@@ -90,7 +90,7 @@
     }
 
     override fun rawResolve(target: FirElementWithResolveState): Unit = when {
-        target is FirScript -> resolveScript(target)
+        target is FirScriptCodeFragment -> resolveScriptCodeFragment(target)
         target is FirCallableDeclaration && target.attributes.fakeOverrideSubstitution != null -> {
             transformer.returnTypeCalculator.fakeOverrideTypeCalculator.computeReturnType(target)
             Unit
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt
index 1f34733..b618528 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirTargetResolver.kt
@@ -9,10 +9,7 @@
 import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
 import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
 import org.jetbrains.kotlin.fir.FirElementWithResolveState
-import org.jetbrains.kotlin.fir.declarations.FirFile
-import org.jetbrains.kotlin.fir.declarations.FirRegularClass
-import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
-import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.*
 
 internal abstract class LLFirTargetResolver(
     protected val resolveTarget: LLFirResolveTarget,
@@ -43,6 +40,10 @@
         action()
     }
 
+    override fun withSnippet(firSnippet: FirSnippet, action: () -> Unit) {
+        action()
+    }
+
     @Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
     protected open fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
         action()
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt
index 3cb6982..cbb6b43 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt
@@ -239,7 +239,7 @@
 internal val FirStatement.isScriptDependentDeclaration: Boolean
     get() = this is FirDeclaration && origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty
 
-internal inline fun FirScript.forEachDependentDeclaration(action: (FirDeclaration) -> Unit) {
+internal inline fun FirScriptCodeFragment.forEachDependentDeclaration(action: (FirDeclaration) -> Unit) {
     for (statement in statements) {
         if (statement !is FirDeclaration || !statement.isScriptDependentDeclaration) continue
         action(statement)
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt
index 7c71753..ffb962b 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt
@@ -162,7 +162,7 @@
                 fir.loadCallableSpecificExperimentalities(this, context, visited, fromSetter, dispatchReceiverType, result)
             is FirClassLikeDeclaration ->
                 fir.loadClassLikeSpecificExperimentalities(this, context, visited, result)
-            is FirAnonymousInitializer, is FirDanglingModifierList, is FirFile, is FirTypeParameter, is FirScript, is FirCodeFragment -> {}
+            is FirAnonymousInitializer, is FirDanglingModifierList, is FirFile, is FirTypeParameter, is FirScriptCodeFragment, is FirCodeFragment -> {}
         }
 
         fir.loadExperimentalitiesFromAnnotationTo(session, result, fromSupertype)
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt
index bbf0c50..b70063b 100644
--- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt
@@ -11,6 +11,7 @@
 import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
 import org.jetbrains.kotlin.fir.backend.Fir2IrScriptConfiguratorExtension
 import org.jetbrains.kotlin.fir.builder.FirScriptConfiguratorExtension
+import org.jetbrains.kotlin.fir.builder.FirSnippetConfiguratorExtension
 import org.jetbrains.kotlin.fir.resolve.FirSamConversionTransformerExtension
 import kotlin.reflect.KClass
 
@@ -98,6 +99,16 @@
             registerExtension(FirScriptConfiguratorExtension::class, this)
         }
 
+        @JvmName("plusSnippetConfiguratorExtension")
+        operator fun (FirSnippetConfiguratorExtension.Factory).unaryPlus() {
+            registerExtension(FirSnippetConfiguratorExtension::class, this)
+        }
+
+        @JvmName("plusSnippetScopesExtension")
+        operator fun (FirSnippetScopesExtension.Factory).unaryPlus() {
+            registerExtension(FirSnippetScopesExtension::class, this)
+        }
+
         @JvmName("plusFir2IrScriptConfiguratorExtension")
         operator fun (Fir2IrScriptConfiguratorExtension.Factory).unaryPlus() {
             registerExtension(Fir2IrScriptConfiguratorExtension::class, this)
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSnippetScopesExtension.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSnippetScopesExtension.kt
new file mode 100644
index 0000000..5d44a75
--- /dev/null
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSnippetScopesExtension.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.extensions
+
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.FirDeclaration
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
+import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
+import org.jetbrains.kotlin.name.Name
+import kotlin.reflect.KClass
+
+abstract class FirSnippetScopesExtension(
+    session: FirSession,
+) : FirExtension(session) {
+    companion object {
+        val NAME = FirExtensionPointName("SnippetScopesConfigurator")
+    }
+
+    final override val name: FirExtensionPointName
+        get() = NAME
+
+    final override val extensionType: KClass<out FirExtension> = FirSnippetScopesExtension::class
+
+    fun interface Factory : FirExtension.Factory<FirSnippetScopesExtension>
+
+    abstract fun contributeVariablesToReplScope(name: Name, processor: (FirVariableSymbol<*>) -> Unit)
+
+    abstract fun contributeClassifiersToReplScope(name: Name, processor: (FirClassifierSymbol<*>) -> Unit)
+
+    abstract fun contributeFunctionsToReplScope(name: Name, processor: (FirNamedFunctionSymbol) -> Unit)
+
+    abstract fun registerVariables(firSnippet: FirSnippet, variables: List<FirVariableSymbol<*>>)
+}
+
+val FirExtensionService.snippetScopesConfigurators: List<FirSnippetScopesExtension> by FirExtensionService.registeredExtensions()
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt
index f25c351..bfd9697 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt
@@ -9,6 +9,7 @@
 import org.jetbrains.kotlin.fakeElement
 import org.jetbrains.kotlin.fir.FirSession
 import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
 import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
 import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -28,6 +29,7 @@
 import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirSnippetSymbol
 import org.jetbrains.kotlin.fir.types.ConeErrorType
 import org.jetbrains.kotlin.fir.types.ConeKotlinType
 import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
@@ -325,3 +327,19 @@
         ImplicitReceiverValueForScript(boundSymbol, type, labelName, useSiteSession, scopeSession, mutable = false, contextReceiverNumber)
 }
 
+
+class ImplicitReceiverValueForSnippet(
+    boundSymbol: FirSnippetSymbol,
+    type: ConeKotlinType,
+    labelName: Name?,
+    useSiteSession: FirSession,
+    scopeSession: ScopeSession,
+    mutable: Boolean = true,
+    contextReceiverNumber: Int,
+) : ContextReceiverValue<FirSnippetSymbol>(
+    boundSymbol, type, labelName, useSiteSession, scopeSession, mutable, contextReceiverNumber
+) {
+    override fun createSnapshot(): ContextReceiverValue<FirSnippetSymbol> =
+        ImplicitReceiverValueForSnippet(boundSymbol, type, labelName, useSiteSession, scopeSession, mutable = false, contextReceiverNumber)
+}
+
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirScriptDeclarationsScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirScriptCodeFragmentDeclarationsScope.kt
similarity index 92%
rename from compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirScriptDeclarationsScope.kt
rename to compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirScriptCodeFragmentDeclarationsScope.kt
index 307e0d5..b65e1a8 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirScriptDeclarationsScope.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirScriptCodeFragmentDeclarationsScope.kt
@@ -15,14 +15,14 @@
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.name.SpecialNames
 
-class FirScriptDeclarationsScope(
+class FirScriptCodeFragmentDeclarationsScope(
     val useSiteSession: FirSession,
-    val script: FirScript,
+    private val scriptCodeFragment: FirScriptCodeFragment,
 ) : FirContainingNamesAwareScope() {
 
     private val callablesIndex: Map<Name, List<FirCallableSymbol<*>>> = run {
         val result = mutableMapOf<Name, MutableList<FirCallableSymbol<*>>>()
-        loop@ for (statement in script.statements) {
+        loop@ for (statement in scriptCodeFragment.statements) {
             if (statement is FirCallableDeclaration) {
                 val name = when (statement) {
                     is FirVariable -> if (statement.isSynthetic) continue@loop else statement.name
@@ -38,7 +38,7 @@
 
     private val classIndex: Map<Name, FirRegularClassSymbol> = run {
         val result = mutableMapOf<Name, FirRegularClassSymbol>()
-        for (declaration in script.statements) {
+        for (declaration in scriptCodeFragment.statements) {
             if (declaration is FirRegularClass) {
                 result[declaration.name] = declaration.symbol
             }
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirSnippetFromReplScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirSnippetFromReplScope.kt
new file mode 100644
index 0000000..201458e
--- /dev/null
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirSnippetFromReplScope.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.scopes.impl
+
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.extensions.extensionService
+import org.jetbrains.kotlin.fir.extensions.snippetScopesConfigurators
+import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
+import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
+import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
+import org.jetbrains.kotlin.name.Name
+
+class FirSnippetFromReplScope(
+    private val useSiteSession: FirSession,
+) : FirContainingNamesAwareScope() {
+
+    override fun getCallableNames(): Set<Name> {
+        return emptySet()
+    }
+
+    override fun getClassifierNames(): Set<Name> {
+        return emptySet()
+    }
+
+    override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
+        for (configurator in useSiteSession.extensionService.snippetScopesConfigurators) {
+            // TODO: unclear semantics
+            configurator.contributeVariablesToReplScope(name, processor)
+        }
+    }
+}
+
+class FirSnippetDeclarationsScope(
+    private val useSiteSession: FirSession,
+) : FirContainingNamesAwareScope() {
+    override fun getCallableNames(): Set<Name> {
+        return emptySet()
+    }
+
+    override fun getClassifierNames(): Set<Name> {
+        return emptySet()
+    }
+
+    override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
+        for (configurator in useSiteSession.extensionService.snippetScopesConfigurators) {
+            configurator.contributeClassifiersToReplScope(name) { processor(it, ConeSubstitutor.Empty) }
+        }
+    }
+
+    override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
+        for (configurator in useSiteSession.extensionService.snippetScopesConfigurators) {
+            configurator.contributeFunctionsToReplScope(name) { processor(it) }
+        }
+    }
+}
+
diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt
index 30b34c5..d65c476 100644
--- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt
+++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt
@@ -1132,6 +1132,41 @@
                 BodyBuildingMode.NORMAL -> file.packageFqNameByTree
                 BodyBuildingMode.LAZY_BODIES -> file.packageFqName
             }
+
+            val configureFileDeclarations: FirFileBuilder.() -> Unit = {
+                if (file is KtCodeFragment) {
+                    declarations += convertCodeFragment(file)
+                } else {
+                    for (declaration in file.declarations) {
+                        declarations += when (declaration) {
+                            is KtScript -> {
+                                requireWithAttachment(
+                                    file.declarations.size == 1,
+                                    message = { "Expect the script to be the only declaration in the file" },
+                                ) {
+                                    withEntry("fileName", file.name)
+                                }
+
+                                convertScript(declaration, declaration.declarations, name, sourceFile,this)
+                            }
+                            is KtDestructuringDeclaration -> listOf(buildErrorTopLevelDestructuringDeclaration(declaration.toFirSourceElement()))
+                            else -> listOf(declaration.convert())
+                        }
+                    }
+
+                    for (danglingModifierList in file.danglingModifierLists) {
+                        declarations += buildErrorTopLevelDeclarationForDanglingModifierList(danglingModifierList)
+                    }
+                }
+            }
+
+            return convertFile(file, configureFileDeclarations)
+        }
+
+        private fun convertFile(
+            file: KtFile,
+            configureDeclarations: FirFileBuilder.() -> Unit
+        ): FirFile {
             return buildFile {
                 symbol = FirFileSymbol()
                 source = file.toFirSourceElement()
@@ -1169,87 +1204,89 @@
                     }
                 }
 
-                if (file is KtCodeFragment) {
-                    declarations += convertCodeFragment(file)
-                } else {
-                    for (declaration in file.declarations) {
-                        declarations += when (declaration) {
-                            is KtScript -> {
-                                requireWithAttachment(
-                                    file.declarations.size == 1,
-                                    message = { "Expect the script to be the only declaration in the file" },
-                                ) {
-                                    withEntry("fileName", file.name)
-                                }
-
-                                convertScript(declaration, name, sourceFile) {
-                                    for (configurator in baseSession.extensionService.scriptConfigurators) {
-                                        with(configurator) { configureContainingFile(this@buildFile) }
-                                    }
-                                }
-                            }
-                            is KtDestructuringDeclaration -> buildErrorTopLevelDestructuringDeclaration(declaration.toFirSourceElement())
-                            else -> declaration.convert()
-                        }
-                    }
-
-                    for (danglingModifierList in file.danglingModifierLists) {
-                        declarations += buildErrorTopLevelDeclarationForDanglingModifierList(danglingModifierList)
-                    }
-                }
+                configureDeclarations()
             }
         }
 
         private fun convertScript(
             script: KtScript,
+            scriptDeclarations: List<KtDeclaration>,
             fileName: String,
             sourceFile: KtSourceFile?,
-            setup: FirScriptBuilder.() -> Unit = {},
-        ): FirScript {
-            return buildScript {
-                source = script.toFirSourceElement()
-                moduleData = baseModuleData
-                origin = FirDeclarationOrigin.Source
-                name = Name.special("<script-$fileName>")
-                symbol = FirScriptSymbol(context.packageFqName.child(name))
-                for (declaration in script.declarations) {
-                    when (declaration) {
-                        is KtScriptInitializer -> {
-                            declaration.body?.let { statements.add(it.toFirStatement()) }
-                        }
-                        is KtDestructuringDeclaration -> {
-                            val destructuringContainerVar = generateTemporaryVariable(
-                                baseModuleData,
-                                declaration.toFirSourceElement(),
-                                "destruct",
-                                declaration.initializer.toFirExpression { ConeSyntaxDiagnostic("Initializer required for destructuring declaration") },
-                                extractAnnotationsTo = { extractAnnotationsTo(it) }
-                            ).apply {
-                                isDestructuringDeclarationContainerVariable = true
-                            }
-                            val destructuringBlock = generateDestructuringBlock(
-                                baseModuleData,
-                                declaration,
-                                destructuringContainerVar,
-                                tmpVariable = false,
-                                localEntries = false,
-                            ).apply {
-                                statements.forEach {
-                                    (it as FirProperty).destructuringDeclarationContainerVariable = destructuringContainerVar.symbol
-                                }
-                            }
-                            statements.add(destructuringContainerVar)
-                            statements.addAll(destructuringBlock.statements)
-                        }
-                        else -> {
-                            statements.add(declaration.toFirStatement())
-                        }
+            containingFile: FirFileBuilder?,
+        ): List<FirScriptCodeFragment> {
+            // TODO: we will need an extension on session
+            if (fileName.endsWith("jupyter.kts")) {
+                return scriptDeclarations.map { declaration ->
+                    buildSnippet {
+                        origin = FirDeclarationOrigin.Source
+                        symbol = FirSnippetSymbol()
+                        source = script.toFirSourceElement()
+                        configureScriptCodeFragment(listOf(declaration))
+                        configureWithConfigurators(sourceFile, containingFile, baseSession.extensionService.snippetConfigurators)
                     }
                 }
-                setup()
-                if (sourceFile != null) {
-                    for (configurator in baseSession.extensionService.scriptConfigurators) {
-                        with(configurator) { configure(sourceFile) }
+            } else {
+                return listOf(buildScript {
+                    origin = FirDeclarationOrigin.Source
+                    name = Name.special("<script-$fileName>")
+                    symbol = FirScriptSymbol(context.packageFqName.child(name))
+                    source = script.toFirSourceElement()
+                    configureScriptCodeFragment(scriptDeclarations)
+                    configureWithConfigurators(sourceFile, containingFile, baseSession.extensionService.scriptConfigurators)
+                })
+            }
+        }
+
+        private fun FirScriptCodeFragmentBuilder.configureWithConfigurators(sourceFile: KtSourceFile?,
+                                                                            containingFile: FirFileBuilder?,
+                                                                            configurators: List<FirScriptCodeFragmentExtension<*>>) {
+            if (sourceFile != null) {
+                for (configurator in configurators) {
+                    with(configurator) {
+                        this as FirScriptCodeFragmentExtension<FirScriptCodeFragmentBuilder>
+                        if (containingFile != null) {
+                            configureContainingFile(containingFile)
+                        }
+                        configure(sourceFile)
+                    }
+                }
+            }
+        }
+
+        private fun FirScriptCodeFragmentBuilder.configureScriptCodeFragment(declarations: List<KtDeclaration>) {
+            moduleData = baseModuleData
+            for (declaration in declarations) {
+                when (declaration) {
+                    is KtScriptInitializer -> {
+                        declaration.body?.let { statements.add(it.toFirStatement()) }
+                    }
+                    is KtDestructuringDeclaration -> {
+                        val destructuringContainerVar = generateTemporaryVariable(
+                            baseModuleData,
+                            declaration.toFirSourceElement(),
+                            "destruct",
+                            declaration.initializer.toFirExpression { ConeSyntaxDiagnostic("Initializer required for destructuring declaration") },
+                            extractAnnotationsTo = { extractAnnotationsTo(it) }
+                        ).apply {
+                            isDestructuringDeclarationContainerVariable = true
+                        }
+                        val destructuringBlock = generateDestructuringBlock(
+                            baseModuleData,
+                            declaration,
+                            destructuringContainerVar,
+                            tmpVariable = false,
+                            localEntries = false,
+                        ).apply {
+                            statements.forEach {
+                                (it as FirProperty).destructuringDeclarationContainerVariable = destructuringContainerVar.symbol
+                            }
+                        }
+                        statements.add(destructuringContainerVar)
+                        statements.addAll(destructuringBlock.statements)
+                    }
+                    else -> {
+                        statements.add(declaration.toFirStatement())
                     }
                 }
             }
@@ -1275,7 +1312,9 @@
             val ktFile = script.containingKtFile
             val fileName = ktFile.name
             val fileForSource = (data as? FirScript)?.psi?.containingFile as? KtFile ?: ktFile
-            return convertScript(script, fileName, KtPsiSourceFile(fileForSource))
+
+            // TODO: What to do with it
+            return convertScript(script, script.declarations, fileName, KtPsiSourceFile(fileForSource), containingFile = null).single()
         }
 
         protected fun KtEnumEntry.toFirEnumEntry(
diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptCodeFragmentExtension.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptCodeFragmentExtension.kt
new file mode 100644
index 0000000..72a5b88
--- /dev/null
+++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptCodeFragmentExtension.kt
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.builder
+
+import org.jetbrains.kotlin.KtSourceFile
+import org.jetbrains.kotlin.fir.declarations.builder.FirFileBuilder
+import org.jetbrains.kotlin.fir.declarations.builder.FirScriptCodeFragmentBuilder
+import org.jetbrains.kotlin.fir.declarations.builder.FirSnippetBuilder
+
+interface FirScriptCodeFragmentExtension<in Builder: FirScriptCodeFragmentBuilder> {
+    fun Builder.configureContainingFile(fileBuilder: FirFileBuilder)
+    fun Builder.configure(sourceFile: KtSourceFile)
+}
diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptConfiguratorExtension.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptConfiguratorExtension.kt
index b483c2f..3cca38e 100644
--- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptConfiguratorExtension.kt
+++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirScriptConfiguratorExtension.kt
@@ -16,7 +16,7 @@
 
 abstract class FirScriptConfiguratorExtension(
     session: FirSession,
-) : FirExtension(session) {
+) : FirScriptCodeFragmentExtension<FirScriptBuilder>, FirExtension(session) {
     companion object {
         val NAME = FirExtensionPointName("ScriptConfigurator")
     }
@@ -27,9 +27,6 @@
     final override val extensionType: KClass<out FirExtension> = FirScriptConfiguratorExtension::class
 
     fun interface Factory : FirExtension.Factory<FirScriptConfiguratorExtension>
-
-    abstract fun FirScriptBuilder.configureContainingFile(fileBuilder: FirFileBuilder)
-    abstract fun FirScriptBuilder.configure(sourceFile: KtSourceFile)
 }
 
 val FirExtensionService.scriptConfigurators: List<FirScriptConfiguratorExtension> by FirExtensionService.registeredExtensions()
diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirSnippetConfiguratorExtension.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirSnippetConfiguratorExtension.kt
new file mode 100644
index 0000000..e5c6bb9
--- /dev/null
+++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/FirSnippetConfiguratorExtension.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.builder
+
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.builder.FirSnippetBuilder
+import org.jetbrains.kotlin.fir.extensions.FirExtension
+import org.jetbrains.kotlin.fir.extensions.FirExtensionPointName
+import org.jetbrains.kotlin.fir.extensions.FirExtensionService
+import kotlin.reflect.KClass
+
+abstract class FirSnippetConfiguratorExtension(
+    session: FirSession,
+) : FirExtension(session), FirScriptCodeFragmentExtension<FirSnippetBuilder> {
+    companion object {
+        val NAME = FirExtensionPointName("SnippetConfigurator")
+    }
+
+    final override val name: FirExtensionPointName get() = NAME
+
+    final override val extensionType: KClass<out FirExtension> = FirSnippetConfiguratorExtension::class
+
+    fun interface Factory : FirExtension.Factory<FirSnippetConfiguratorExtension>
+
+}
+
+val FirExtensionService.snippetConfigurators: List<FirSnippetConfiguratorExtension> by FirExtensionService.registeredExtensions()
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt
index 3a691a9..a149f7e 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt
@@ -250,6 +250,18 @@
         return graph
     }
 
+    // ----------------------------------- Snippets ------------------------------------------
+
+    fun enterSnippet(snippet: FirSnippet) {
+        graphBuilder.enterSnippet(snippet).mergeIncomingFlow()
+    }
+
+    fun exitSnippet(): ControlFlowGraph {
+        val (node, graph) = graphBuilder.exitSnippet()
+        node.mergeIncomingFlow()
+        return graph
+    }
+
     // ----------------------------------- Code Fragment ------------------------------------------
 
     fun enterCodeFragment(codeFragment: FirCodeFragment) {
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt
index 74a4928..a964aa6 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt
@@ -629,6 +629,17 @@
         return exitGraph()
     }
 
+    fun enterSnippet(snippet: FirSnippet): SnippetEnterNode {
+        // TODO: is it really function?
+        return enterGraph(snippet, "SNIPPET_GRAPH", ControlFlowGraph.Kind.Function) {
+            createSnippetEnterNode(it) to createSnippetExitNode(it)
+        }
+    }
+
+    fun exitSnippet(): Pair<ScriptExitNode, ControlFlowGraph> {
+        return exitGraph()
+    }
+
     fun enterCodeFragment(codeFragment: FirCodeFragment): CodeFragmentEnterNode {
         return enterGraph(codeFragment, "CODE_FRAGMENT_GRAPH", ControlFlowGraph.Kind.Function) {
             createCodeFragmentEnterNode(it) to createCodeFragmentExitNode(it)
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt
index 350a7ea..f0e7a1e 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt
@@ -223,6 +223,12 @@
 fun ControlFlowGraphBuilder.createScriptExitNode(fir: FirScript): ScriptExitNode =
     ScriptExitNode(currentGraph, fir, levelCounter)
 
+fun ControlFlowGraphBuilder.createSnippetEnterNode(fir: FirSnippet): SnippetEnterNode =
+    SnippetEnterNode(currentGraph, fir, levelCounter)
+
+fun ControlFlowGraphBuilder.createSnippetExitNode(fir: FirSnippet): SnippetExitNode =
+    SnippetExitNode(currentGraph, fir, levelCounter)
+
 fun ControlFlowGraphBuilder.createCodeFragmentEnterNode(fir: FirCodeFragment): CodeFragmentEnterNode =
     CodeFragmentEnterNode(currentGraph, fir, levelCounter)
 
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt
index 39a7f9a..da35196 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt
@@ -33,6 +33,7 @@
 import org.jetbrains.kotlin.fir.scopes.createImportingScopes
 import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
 import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
+import org.jetbrains.kotlin.fir.scopes.impl.FirSnippetDeclarationsScope
 import org.jetbrains.kotlin.fir.scopes.impl.FirWhenSubjectImportingScope
 import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
@@ -575,6 +576,37 @@
     }
 
     @OptIn(PrivateForInline::class)
+    fun <T> withSnippet(snippet: FirSnippet, holder: SessionHolder, f: () -> T): T {
+        val towerElementsForScript = holder.collectTowerDataElementsForSnippet(snippet)
+
+        val statics = towerDataContext
+            .addNonLocalScopeIfNotNull(towerElementsForScript.staticScope)
+            .addNonLocalScopeIfNotNull(FirSnippetDeclarationsScope(holder.session))
+
+
+        val forMembersResolution =
+            statics
+                .addContextReceiverGroup(towerElementsForScript.implicitReceivers)
+
+        val newContexts = FirRegularTowerDataContexts(
+            regular = forMembersResolution,
+            forClassHeaderAnnotations = towerDataContext,
+            forNestedClasses = forMembersResolution,
+            forCompanionObject = statics,
+            forConstructorHeaders = null,
+            forEnumEntries = null,
+            primaryConstructorPureParametersScope = null,
+            primaryConstructorAllParametersScope = null
+        )
+
+        return withTowerDataContexts(newContexts) {
+            withContainer(snippet) {
+                f()
+            }
+        }
+    }
+
+    @OptIn(PrivateForInline::class)
     inline fun <T> withWhenSubjectType(
         subjectType: ConeKotlinType?,
         sessionHolder: SessionHolder,
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
index 313d0a6..0c4191e 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
@@ -25,6 +25,8 @@
 import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
 import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
 import org.jetbrains.kotlin.fir.expressions.*
+import org.jetbrains.kotlin.fir.extensions.extensionService
+import org.jetbrains.kotlin.fir.extensions.snippetScopesConfigurators
 import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
 import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
 import org.jetbrains.kotlin.fir.resolve.*
@@ -616,6 +618,13 @@
             }
         }
 
+    fun withScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment, action: () -> FirScriptCodeFragment): FirScriptCodeFragment {
+        return when (scriptCodeFragment) {
+            is FirScript -> withScript(scriptCodeFragment) { action() as FirScript }
+            is FirSnippet -> withSnippet(scriptCodeFragment) { action() as FirSnippet }
+        }
+    }
+
     fun withScript(script: FirScript, action: () -> FirScript): FirScript {
         dataFlowAnalyzer.enterScript(script)
         val result = context.withScript(script, components) {
@@ -625,10 +634,31 @@
         return result
     }
 
+    fun withSnippet(snippet: FirSnippet, action: () -> FirSnippet): FirSnippet {
+        dataFlowAnalyzer.enterSnippet(snippet)
+        val result = context.withSnippet(snippet, components) {
+            action()
+        }
+
+        session.extensionService.snippetScopesConfigurators.forEach {
+            it.registerVariables(result.statements.filterIsInstance(FirVariable::class.java).map { it.symbol })
+        }
+
+        // Pass
+
+
+        dataFlowAnalyzer.exitSnippet() // TODO: FirSnippet should be a FirControlFlowGraphOwner, KT-???
+        return result
+    }
+
     override fun transformScript(script: FirScript, data: ResolutionMode): FirScript = withScript(script) {
         transformDeclarationContent(script, data) as FirScript
     }
 
+    override fun transformSnippet(snippet: FirSnippet, data: ResolutionMode): FirSnippet = withSnippet(snippet) {
+        transformDeclarationContent(snippet, data) as FirSnippet
+    }
+
     override fun transformCodeFragment(codeFragment: FirCodeFragment, data: ResolutionMode): FirCodeFragment {
         dataFlowAnalyzer.enterCodeFragment(codeFragment)
         context.withCodeFragment(codeFragment, components) {
diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ScriptScopes.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ScriptScopes.kt
index 74973cc..b023d75 100644
--- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ScriptScopes.kt
+++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ScriptScopes.kt
@@ -9,7 +9,7 @@
 import org.jetbrains.kotlin.fir.resolve.SessionHolder
 import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValueForScript
 import org.jetbrains.kotlin.fir.scopes.FirScope
-import org.jetbrains.kotlin.fir.scopes.impl.FirScriptDeclarationsScope
+import org.jetbrains.kotlin.fir.scopes.impl.FirScriptCodeFragmentDeclarationsScope
 import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
 import org.jetbrains.kotlin.fir.types.coneType
 
@@ -30,6 +30,6 @@
 
     return TowerElementsForScript(
         contextReceivers,
-        FirScriptDeclarationsScope(session, owner),
+        FirScriptCodeFragmentDeclarationsScope(session, owner),
     )
 }
diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/SnippetScopes.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/SnippetScopes.kt
new file mode 100644
index 0000000..e9efe3e
--- /dev/null
+++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/SnippetScopes.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.declarations
+
+import org.jetbrains.kotlin.fir.labelName
+import org.jetbrains.kotlin.fir.resolve.SessionHolder
+import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValueForSnippet
+import org.jetbrains.kotlin.fir.scopes.FirScope
+import org.jetbrains.kotlin.fir.scopes.impl.FirSnippetFromReplScope
+import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
+import org.jetbrains.kotlin.fir.types.coneType
+
+class TowerElementsForSnippet(
+    val implicitReceivers: List<ImplicitReceiverValueForSnippet>,
+    val staticScope: FirScope?,
+)
+
+// TODO: remove this abstraction
+fun SessionHolder.collectTowerDataElementsForSnippet(owner: FirSnippet): TowerElementsForSnippet {
+    owner.lazyResolveToPhase(FirResolvePhase.TYPES)
+
+    val contextReceivers = owner.contextReceivers.mapIndexed { index, receiver ->
+        ImplicitReceiverValueForSnippet(
+            owner.symbol, receiver.typeRef.coneType, receiver.labelName, session, scopeSession,
+            contextReceiverNumber = index,
+        )
+    }
+
+    return TowerElementsForSnippet(
+        contextReceivers,
+        FirSnippetFromReplScope(session),
+    )
+}
diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt
index b13ff91..aa7dcd8 100644
--- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt
+++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt
@@ -365,6 +365,20 @@
     }
 }
 
+// ----------------------------------- Snippets ----------------------------------------
+
+class SnippetEnterNode(owner: ControlFlowGraph, override val fir: FirSnippet, level: Int) : CFGNode<FirSnippet>(owner, level), GraphEnterNodeMarker {
+    override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
+        return visitor.visitSnippetEnterNode(this, data)
+    }
+}
+
+class SnippetExitNode(owner: ControlFlowGraph, override val fir: FirSnippet, level: Int) : CFGNode<FirSnippet>(owner, level), GraphExitNodeMarker {
+    override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
+        return visitor.visitSnippetExitNode(this, data)
+    }
+}
+
 // ----------------------------------- Code Fragments ------------------------------------------
 
 class CodeFragmentEnterNode(owner: ControlFlowGraph, override val fir: FirCodeFragment, level: Int) : CFGNode<FirCodeFragment>(owner, level), GraphEnterNodeMarker {
diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt
index 2f1ed70b..6901596 100644
--- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt
+++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt
@@ -110,6 +110,9 @@
                 is ScriptEnterNode -> "Enter class ${fir.name}"
                 is ScriptExitNode -> "Exit class ${fir.name}"
 
+                is SnippetEnterNode -> "Enter class ${fir.name}"
+                is SnippetExitNode -> "Exit class ${fir.name}"
+
                 is CodeFragmentEnterNode -> "Enter code fragment"
                 is CodeFragmentExitNode -> "Exit code fragment"
 
diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt
index 182f5d7..792ab47 100644
--- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt
+++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt
@@ -100,6 +100,16 @@
         return visitNode(node, data)
     }
 
+    // ----------------------------------- Snippets ------------------------------------------
+
+    open fun visitSnippetEnterNode(node: SnippetEnterNode, data: D): R {
+        return visitNode(node, data)
+    }
+
+    open fun visitSnippetExitNode(node: SnippetExitNode, data: D): R {
+        return visitNode(node, data)
+    }
+
     // ----------------------------------- Code Fragments ------------------------------------------
 
     open fun visitCodeFragmentEnterNode(node: CodeFragmentEnterNode, data: D): R {
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScript.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScript.kt
index b27815d..1adffda 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScript.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScript.kt
@@ -20,18 +20,18 @@
  * DO NOT MODIFY IT MANUALLY
  */
 
-abstract class FirScript : FirDeclaration() {
+abstract class FirScript : FirScriptCodeFragment() {
     abstract override val source: KtSourceElement?
     abstract override val annotations: List<FirAnnotation>
     abstract override val moduleData: FirModuleData
     abstract override val origin: FirDeclarationOrigin
     abstract override val attributes: FirDeclarationAttributes
+    abstract override val statements: List<FirStatement>
+    abstract override val resultPropertyName: Name?
+    abstract override val contextReceivers: List<FirContextReceiver>
     abstract val name: Name
-    abstract val statements: List<FirStatement>
     abstract override val symbol: FirScriptSymbol
     abstract val parameters: List<FirVariable>
-    abstract val contextReceivers: List<FirContextReceiver>
-    abstract val resultPropertyName: Name?
 
     override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitScript(this, data)
 
@@ -41,9 +41,9 @@
 
     abstract override fun replaceAnnotations(newAnnotations: List<FirAnnotation>)
 
-    abstract fun replaceStatements(newStatements: List<FirStatement>)
+    abstract override fun replaceStatements(newStatements: List<FirStatement>)
 
     abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirScript
 
-    abstract fun <D> transformStatements(transformer: FirTransformer<D>, data: D): FirScript
+    abstract override fun <D> transformStatements(transformer: FirTransformer<D>, data: D): FirScript
 }
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScriptCodeFragment.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScriptCodeFragment.kt
new file mode 100644
index 0000000..27215dc
--- /dev/null
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirScriptCodeFragment.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.declarations
+
+import org.jetbrains.kotlin.KtSourceElement
+import org.jetbrains.kotlin.fir.FirElement
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.fir.visitors.*
+import org.jetbrains.kotlin.fir.declarations.ResolveStateAccess
+
+/*
+ * This file was generated automatically
+ * DO NOT MODIFY IT MANUALLY
+ */
+
+sealed class FirScriptCodeFragment : FirDeclaration() {
+    abstract override val source: KtSourceElement?
+    abstract override val annotations: List<FirAnnotation>
+    abstract override val symbol: FirBasedSymbol<out FirDeclaration>
+    abstract override val moduleData: FirModuleData
+    abstract override val origin: FirDeclarationOrigin
+    abstract override val attributes: FirDeclarationAttributes
+    abstract val statements: List<FirStatement>
+    abstract val resultPropertyName: Name?
+    abstract val contextReceivers: List<FirContextReceiver>
+
+    override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitScriptCodeFragment(this, data)
+
+    @Suppress("UNCHECKED_CAST")
+    override fun <E : FirElement, D> transform(transformer: FirTransformer<D>, data: D): E =
+        transformer.transformScriptCodeFragment(this, data) as E
+
+    abstract override fun replaceAnnotations(newAnnotations: List<FirAnnotation>)
+
+    abstract fun replaceStatements(newStatements: List<FirStatement>)
+
+    abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirScriptCodeFragment
+
+    abstract fun <D> transformStatements(transformer: FirTransformer<D>, data: D): FirScriptCodeFragment
+}
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirSnippet.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirSnippet.kt
new file mode 100644
index 0000000..0ba0e01
--- /dev/null
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirSnippet.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.declarations
+
+import org.jetbrains.kotlin.KtSourceElement
+import org.jetbrains.kotlin.fir.FirElement
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.symbols.impl.FirSnippetSymbol
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.fir.visitors.*
+import org.jetbrains.kotlin.fir.declarations.ResolveStateAccess
+
+/*
+ * This file was generated automatically
+ * DO NOT MODIFY IT MANUALLY
+ */
+
+abstract class FirSnippet : FirScriptCodeFragment() {
+    abstract override val source: KtSourceElement?
+    abstract override val annotations: List<FirAnnotation>
+    abstract override val moduleData: FirModuleData
+    abstract override val origin: FirDeclarationOrigin
+    abstract override val attributes: FirDeclarationAttributes
+    abstract override val statements: List<FirStatement>
+    abstract override val resultPropertyName: Name?
+    abstract override val contextReceivers: List<FirContextReceiver>
+    abstract override val symbol: FirSnippetSymbol
+    abstract val replName: Name
+
+    override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitSnippet(this, data)
+
+    @Suppress("UNCHECKED_CAST")
+    override fun <E : FirElement, D> transform(transformer: FirTransformer<D>, data: D): E =
+        transformer.transformSnippet(this, data) as E
+
+    abstract override fun replaceAnnotations(newAnnotations: List<FirAnnotation>)
+
+    abstract override fun replaceStatements(newStatements: List<FirStatement>)
+
+    abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirSnippet
+
+    abstract override fun <D> transformStatements(transformer: FirTransformer<D>, data: D): FirSnippet
+}
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptBuilder.kt
index 4c6366e..896fe42 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptBuilder.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptBuilder.kt
@@ -22,8 +22,8 @@
 import org.jetbrains.kotlin.fir.declarations.FirVariable
 import org.jetbrains.kotlin.fir.declarations.ResolveStateAccess
 import org.jetbrains.kotlin.fir.declarations.asResolveState
+import org.jetbrains.kotlin.fir.declarations.builder.FirScriptCodeFragmentBuilder
 import org.jetbrains.kotlin.fir.declarations.impl.FirScriptImpl
-import org.jetbrains.kotlin.fir.declarations.resolvePhase
 import org.jetbrains.kotlin.fir.expressions.FirAnnotation
 import org.jetbrains.kotlin.fir.expressions.FirStatement
 import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
@@ -36,19 +36,19 @@
  */
 
 @FirBuilderDsl
-class FirScriptBuilder : FirAnnotationContainerBuilder {
+class FirScriptBuilder : FirScriptCodeFragmentBuilder, FirAnnotationContainerBuilder {
     override var source: KtSourceElement? = null
-    var resolvePhase: FirResolvePhase = FirResolvePhase.RAW_FIR
+    override var resolvePhase: FirResolvePhase = FirResolvePhase.RAW_FIR
     override val annotations: MutableList<FirAnnotation> = mutableListOf()
-    lateinit var moduleData: FirModuleData
-    lateinit var origin: FirDeclarationOrigin
-    var attributes: FirDeclarationAttributes = FirDeclarationAttributes()
+    override lateinit var moduleData: FirModuleData
+    override lateinit var origin: FirDeclarationOrigin
+    override var attributes: FirDeclarationAttributes = FirDeclarationAttributes()
+    override val statements: MutableList<FirStatement> = mutableListOf()
+    override var resultPropertyName: Name? = null
+    override val contextReceivers: MutableList<FirContextReceiver> = mutableListOf()
     lateinit var name: Name
-    val statements: MutableList<FirStatement> = mutableListOf()
     lateinit var symbol: FirScriptSymbol
     val parameters: MutableList<FirVariable> = mutableListOf()
-    val contextReceivers: MutableList<FirContextReceiver> = mutableListOf()
-    var resultPropertyName: Name? = null
 
     override fun build(): FirScript {
         return FirScriptImpl(
@@ -58,12 +58,12 @@
             moduleData,
             origin,
             attributes,
-            name,
             statements.toMutableOrEmpty(),
+            resultPropertyName,
+            contextReceivers.toMutableOrEmpty(),
+            name,
             symbol,
             parameters,
-            contextReceivers.toMutableOrEmpty(),
-            resultPropertyName,
         )
     }
 
@@ -76,24 +76,3 @@
     }
     return FirScriptBuilder().apply(init).build()
 }
-
-@OptIn(ExperimentalContracts::class)
-inline fun buildScriptCopy(original: FirScript, init: FirScriptBuilder.() -> Unit): FirScript {
-    contract {
-        callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
-    }
-    val copyBuilder = FirScriptBuilder()
-    copyBuilder.source = original.source
-    copyBuilder.resolvePhase = original.resolvePhase
-    copyBuilder.annotations.addAll(original.annotations)
-    copyBuilder.moduleData = original.moduleData
-    copyBuilder.origin = original.origin
-    copyBuilder.attributes = original.attributes.copy()
-    copyBuilder.name = original.name
-    copyBuilder.statements.addAll(original.statements)
-    copyBuilder.symbol = original.symbol
-    copyBuilder.parameters.addAll(original.parameters)
-    copyBuilder.contextReceivers.addAll(original.contextReceivers)
-    copyBuilder.resultPropertyName = original.resultPropertyName
-    return copyBuilder.apply(init).build()
-}
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptCodeFragmentBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptCodeFragmentBuilder.kt
new file mode 100644
index 0000000..01e18f8
--- /dev/null
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirScriptCodeFragmentBuilder.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("DuplicatedCode", "unused")
+
+package org.jetbrains.kotlin.fir.declarations.builder
+
+import org.jetbrains.kotlin.KtSourceElement
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
+import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationAttributes
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
+import org.jetbrains.kotlin.fir.declarations.FirScriptCodeFragment
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.visitors.*
+import org.jetbrains.kotlin.name.Name
+
+/*
+ * This file was generated automatically
+ * DO NOT MODIFY IT MANUALLY
+ */
+
+@FirBuilderDsl
+interface FirScriptCodeFragmentBuilder {
+    abstract var source: KtSourceElement?
+    abstract var resolvePhase: FirResolvePhase
+    abstract val annotations: MutableList<FirAnnotation>
+    abstract var moduleData: FirModuleData
+    abstract var origin: FirDeclarationOrigin
+    abstract var attributes: FirDeclarationAttributes
+    abstract val statements: MutableList<FirStatement>
+    abstract var resultPropertyName: Name?
+    abstract val contextReceivers: MutableList<FirContextReceiver>
+
+    fun build(): FirScriptCodeFragment
+}
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirSnippetBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirSnippetBuilder.kt
new file mode 100644
index 0000000..c3aff46
--- /dev/null
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirSnippetBuilder.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("DuplicatedCode", "unused")
+
+package org.jetbrains.kotlin.fir.declarations.builder
+
+import kotlin.contracts.*
+import org.jetbrains.kotlin.KtSourceElement
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
+import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
+import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
+import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationAttributes
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
+import org.jetbrains.kotlin.fir.declarations.FirResolveState
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
+import org.jetbrains.kotlin.fir.declarations.ResolveStateAccess
+import org.jetbrains.kotlin.fir.declarations.asResolveState
+import org.jetbrains.kotlin.fir.declarations.builder.FirScriptCodeFragmentBuilder
+import org.jetbrains.kotlin.fir.declarations.impl.FirSnippetImpl
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.symbols.impl.FirSnippetSymbol
+import org.jetbrains.kotlin.fir.visitors.*
+import org.jetbrains.kotlin.name.Name
+
+/*
+ * This file was generated automatically
+ * DO NOT MODIFY IT MANUALLY
+ */
+
+@FirBuilderDsl
+class FirSnippetBuilder : FirScriptCodeFragmentBuilder, FirAnnotationContainerBuilder {
+    override var source: KtSourceElement? = null
+    override var resolvePhase: FirResolvePhase = FirResolvePhase.RAW_FIR
+    override val annotations: MutableList<FirAnnotation> = mutableListOf()
+    override lateinit var moduleData: FirModuleData
+    override lateinit var origin: FirDeclarationOrigin
+    override var attributes: FirDeclarationAttributes = FirDeclarationAttributes()
+    override val statements: MutableList<FirStatement> = mutableListOf()
+    override var resultPropertyName: Name? = null
+    override val contextReceivers: MutableList<FirContextReceiver> = mutableListOf()
+    lateinit var symbol: FirSnippetSymbol
+    lateinit var replName: Name
+
+    override fun build(): FirSnippet {
+        return FirSnippetImpl(
+            source,
+            resolvePhase,
+            annotations.toMutableOrEmpty(),
+            moduleData,
+            origin,
+            attributes,
+            statements.toMutableOrEmpty(),
+            resultPropertyName,
+            contextReceivers.toMutableOrEmpty(),
+            symbol,
+            replName,
+        )
+    }
+
+}
+
+@OptIn(ExperimentalContracts::class)
+inline fun buildSnippet(init: FirSnippetBuilder.() -> Unit): FirSnippet {
+    contract {
+        callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
+    }
+    return FirSnippetBuilder().apply(init).build()
+}
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirScriptImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirScriptImpl.kt
index fe80262..f027df2 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirScriptImpl.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirScriptImpl.kt
@@ -38,12 +38,12 @@
     override val moduleData: FirModuleData,
     override val origin: FirDeclarationOrigin,
     override val attributes: FirDeclarationAttributes,
-    override val name: Name,
     override var statements: MutableOrEmptyList<FirStatement>,
+    override val resultPropertyName: Name?,
+    override var contextReceivers: MutableOrEmptyList<FirContextReceiver>,
+    override val name: Name,
     override val symbol: FirScriptSymbol,
     override val parameters: MutableList<FirVariable>,
-    override var contextReceivers: MutableOrEmptyList<FirContextReceiver>,
-    override val resultPropertyName: Name?,
 ) : FirScript() {
     init {
         symbol.bind(this)
@@ -54,15 +54,15 @@
     override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
         annotations.forEach { it.accept(visitor, data) }
         statements.forEach { it.accept(visitor, data) }
-        parameters.forEach { it.accept(visitor, data) }
         contextReceivers.forEach { it.accept(visitor, data) }
+        parameters.forEach { it.accept(visitor, data) }
     }
 
     override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirScriptImpl {
         transformAnnotations(transformer, data)
         transformStatements(transformer, data)
-        parameters.transformInplace(transformer, data)
         contextReceivers.transformInplace(transformer, data)
+        parameters.transformInplace(transformer, data)
         return this
     }
 
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirSnippetImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirSnippetImpl.kt
new file mode 100644
index 0000000..3120bb0
--- /dev/null
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirSnippetImpl.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("DuplicatedCode", "unused")
+
+package org.jetbrains.kotlin.fir.declarations.impl
+
+import org.jetbrains.kotlin.KtSourceElement
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationAttributes
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
+import org.jetbrains.kotlin.fir.declarations.FirResolveState
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
+import org.jetbrains.kotlin.fir.declarations.asResolveState
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.symbols.impl.FirSnippetSymbol
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.fir.visitors.*
+import org.jetbrains.kotlin.fir.MutableOrEmptyList
+import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
+import org.jetbrains.kotlin.fir.declarations.ResolveStateAccess
+
+/*
+ * This file was generated automatically
+ * DO NOT MODIFY IT MANUALLY
+ */
+
+internal class FirSnippetImpl(
+    override val source: KtSourceElement?,
+    resolvePhase: FirResolvePhase,
+    override var annotations: MutableOrEmptyList<FirAnnotation>,
+    override val moduleData: FirModuleData,
+    override val origin: FirDeclarationOrigin,
+    override val attributes: FirDeclarationAttributes,
+    override var statements: MutableOrEmptyList<FirStatement>,
+    override val resultPropertyName: Name?,
+    override var contextReceivers: MutableOrEmptyList<FirContextReceiver>,
+    override val symbol: FirSnippetSymbol,
+    override val replName: Name,
+) : FirSnippet() {
+    init {
+        symbol.bind(this)
+        @OptIn(ResolveStateAccess::class)
+        resolveState = resolvePhase.asResolveState()
+    }
+
+    override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
+        annotations.forEach { it.accept(visitor, data) }
+        statements.forEach { it.accept(visitor, data) }
+        contextReceivers.forEach { it.accept(visitor, data) }
+    }
+
+    override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirSnippetImpl {
+        transformAnnotations(transformer, data)
+        transformStatements(transformer, data)
+        contextReceivers.transformInplace(transformer, data)
+        return this
+    }
+
+    override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirSnippetImpl {
+        annotations.transformInplace(transformer, data)
+        return this
+    }
+
+    override fun <D> transformStatements(transformer: FirTransformer<D>, data: D): FirSnippetImpl {
+        statements.transformInplace(transformer, data)
+        return this
+    }
+
+    override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) {
+        annotations = newAnnotations.toMutableOrEmpty()
+    }
+
+    override fun replaceStatements(newStatements: List<FirStatement>) {
+        statements = newStatements.toMutableOrEmpty()
+    }
+}
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt
index b1fa5cdb..77e3dd1 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt
@@ -49,7 +49,9 @@
 import org.jetbrains.kotlin.fir.declarations.FirBackingField
 import org.jetbrains.kotlin.fir.declarations.FirConstructor
 import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.declarations.FirScriptCodeFragment
 import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 import org.jetbrains.kotlin.fir.declarations.FirCodeFragment
 import org.jetbrains.kotlin.fir.FirPackageDirective
 import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
@@ -192,7 +194,11 @@
 
     override fun visitRegularClass(regularClass: FirRegularClass, data: D): R  = visitClass(regularClass, data)
 
-    override fun visitScript(script: FirScript, data: D): R  = visitDeclaration(script, data)
+    override fun visitScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment, data: D): R  = visitDeclaration(scriptCodeFragment, data)
+
+    override fun visitScript(script: FirScript, data: D): R  = visitScriptCodeFragment(script, data)
+
+    override fun visitSnippet(snippet: FirSnippet, data: D): R  = visitScriptCodeFragment(snippet, data)
 
     override fun visitCodeFragment(codeFragment: FirCodeFragment, data: D): R  = visitDeclaration(codeFragment, data)
 
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt
index 213a85a..34b5801 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt
@@ -49,7 +49,9 @@
 import org.jetbrains.kotlin.fir.declarations.FirBackingField
 import org.jetbrains.kotlin.fir.declarations.FirConstructor
 import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.declarations.FirScriptCodeFragment
 import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 import org.jetbrains.kotlin.fir.declarations.FirCodeFragment
 import org.jetbrains.kotlin.fir.FirPackageDirective
 import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
@@ -192,7 +194,11 @@
 
     override fun visitRegularClass(regularClass: FirRegularClass)  = visitClass(regularClass)
 
-    override fun visitScript(script: FirScript)  = visitDeclaration(script)
+    override fun visitScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment)  = visitDeclaration(scriptCodeFragment)
+
+    override fun visitScript(script: FirScript)  = visitScriptCodeFragment(script)
+
+    override fun visitSnippet(snippet: FirSnippet)  = visitScriptCodeFragment(snippet)
 
     override fun visitCodeFragment(codeFragment: FirCodeFragment)  = visitDeclaration(codeFragment)
 
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt
index 9431b68..f7a3556 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt
@@ -49,7 +49,9 @@
 import org.jetbrains.kotlin.fir.declarations.FirBackingField
 import org.jetbrains.kotlin.fir.declarations.FirConstructor
 import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.declarations.FirScriptCodeFragment
 import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 import org.jetbrains.kotlin.fir.declarations.FirCodeFragment
 import org.jetbrains.kotlin.fir.FirPackageDirective
 import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
@@ -343,10 +345,18 @@
         return transformElement(file, data)
     }
 
+    open fun transformScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment, data: D): FirScriptCodeFragment {
+        return transformElement(scriptCodeFragment, data)
+    }
+
     open fun transformScript(script: FirScript, data: D): FirScript {
         return transformElement(script, data)
     }
 
+    open fun transformSnippet(snippet: FirSnippet, data: D): FirSnippet {
+        return transformElement(snippet, data)
+    }
+
     open fun transformCodeFragment(codeFragment: FirCodeFragment, data: D): FirCodeFragment {
         return transformElement(codeFragment, data)
     }
@@ -967,10 +977,18 @@
         return transformFile(file, data)
     }
 
+    final override fun visitScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment, data: D): FirScriptCodeFragment {
+        return transformScriptCodeFragment(scriptCodeFragment, data)
+    }
+
     final override fun visitScript(script: FirScript, data: D): FirScript {
         return transformScript(script, data)
     }
 
+    final override fun visitSnippet(snippet: FirSnippet, data: D): FirSnippet {
+        return transformSnippet(snippet, data)
+    }
+
     final override fun visitCodeFragment(codeFragment: FirCodeFragment, data: D): FirCodeFragment {
         return transformCodeFragment(codeFragment, data)
     }
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt
index 250df3a..3240f3d 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt
@@ -49,7 +49,9 @@
 import org.jetbrains.kotlin.fir.declarations.FirBackingField
 import org.jetbrains.kotlin.fir.declarations.FirConstructor
 import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.declarations.FirScriptCodeFragment
 import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 import org.jetbrains.kotlin.fir.declarations.FirCodeFragment
 import org.jetbrains.kotlin.fir.FirPackageDirective
 import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
@@ -256,8 +258,12 @@
 
     open fun visitFile(file: FirFile, data: D): R  = visitElement(file, data)
 
+    open fun visitScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment, data: D): R  = visitElement(scriptCodeFragment, data)
+
     open fun visitScript(script: FirScript, data: D): R  = visitElement(script, data)
 
+    open fun visitSnippet(snippet: FirSnippet, data: D): R  = visitElement(snippet, data)
+
     open fun visitCodeFragment(codeFragment: FirCodeFragment, data: D): R  = visitElement(codeFragment, data)
 
     open fun visitPackageDirective(packageDirective: FirPackageDirective, data: D): R  = visitElement(packageDirective, data)
diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt
index b3aa0d5..297eb11 100644
--- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt
+++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt
@@ -49,7 +49,9 @@
 import org.jetbrains.kotlin.fir.declarations.FirBackingField
 import org.jetbrains.kotlin.fir.declarations.FirConstructor
 import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.declarations.FirScriptCodeFragment
 import org.jetbrains.kotlin.fir.declarations.FirScript
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
 import org.jetbrains.kotlin.fir.declarations.FirCodeFragment
 import org.jetbrains.kotlin.fir.FirPackageDirective
 import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
@@ -342,10 +344,18 @@
         visitElement(file)
     }
 
+    open fun visitScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment) {
+        visitElement(scriptCodeFragment)
+    }
+
     open fun visitScript(script: FirScript) {
         visitElement(script)
     }
 
+    open fun visitSnippet(snippet: FirSnippet) {
+        visitElement(snippet)
+    }
+
     open fun visitCodeFragment(codeFragment: FirCodeFragment) {
         visitElement(codeFragment)
     }
@@ -966,10 +976,18 @@
         visitFile(file)
     }
 
+    final override fun visitScriptCodeFragment(scriptCodeFragment: FirScriptCodeFragment, data: Nothing?) {
+        visitScriptCodeFragment(scriptCodeFragment)
+    }
+
     final override fun visitScript(script: FirScript, data: Nothing?) {
         visitScript(script)
     }
 
+    final override fun visitSnippet(snippet: FirSnippet, data: Nothing?) {
+        visitSnippet(snippet)
+    }
+
     final override fun visitCodeFragment(codeFragment: FirCodeFragment, data: Nothing?) {
         visitCodeFragment(codeFragment)
     }
diff --git a/compiler/fir/tree/rm.md b/compiler/fir/tree/rm.md
new file mode 100644
index 0000000..8f3d66d
--- /dev/null
+++ b/compiler/fir/tree/rm.md
@@ -0,0 +1,160 @@
+# K2 REPL design proposal
+
+This document describes the in-detail design of the REPL compiler in K2.
+
+
+## Preliminary knowledge
+
+Previous documents:
+
+https://docs.google.com/document/d/1giu97BIMOGryg9_SQtOyHHL5td7mv7UXV7DbBbFzt_0/edit#heading=h.jbfis5ki3dlk
+https://docs.google.com/document/d/1XU8LgeExGXR6q0TMAt3ttS9ZdjGQ92rZYjoL1dYllj4/edit?pli=1
+
+
+
+**Snippet** is a script-like Kotlin code fragment that can be executed inside the **REPL session**. Snippets can only be analyzed and executed inside the corresponding session. Snippets can be executed only sequentially, the order of analysis doesn’t matter. The sequence of already executed snippets inside the session forms the **REPL session state**. The state is divided into compile-time and runtime parts. Compile-time part is used during snippet compilation, runtime part is used when the compiled snippet is executed.
+
+
+## Compilation Process
+
+User wants to execute two snippets:
+
+#1
+```kotlin
+val a = 1
+val b = 2
+fun f(k: Int) = k.toString()
+a + b
+```
+
+#2
+```kotlin
+val a = "123"
+a + f(b)
+```
+
+REPL initializes empty state. It also initializes compiler environment and FIR session.
+All these are living until the end of the session.
+
+### 1: Source -> PSI
+
+First snippet is parsed into PSI the same way scripts are parsed:
+```
+<KtFile>
+    <Preamble></Preamble> // Imports and file annotations go there
+    <KtScript>
+        <block>
+            <statement>val a = 1</statement>
+            <statement>val b = 2</statement>
+            <statement>fun f(k: Int) = k.toString()</statement>
+            <statement>a + b</statement>
+        </block>
+    </KtScript>
+</KtFile>
+```
+
+### 2: PSI -> Raw FIR
+
+Then, PSI is converted into raw FIR. **Each statement is converted into separate snippet.**
+Reasons for it are described below.
+Psi2Fir conversion also adds package directive to the containing file.
+
+```
+<FirFile>
+    <Preamble>
+        package myrepl.snippet1
+    </Preamble>
+    <FirSnippet>
+        <statement>val a = 1</statement>
+    </FirSnippet>
+    <FirSnippet>
+        <statement>val b = 2</statement>
+    </FirSnippet>
+    <FirSnippet>
+        <statement>fun f(k: Int) = k.toString()</statement>
+    </FirSnippet>
+    <FirSnippet>
+        <statement>a + b</statement>
+    </FirSnippet>
+</FirFile>
+```
+
+### 3: Raw FIR postprocessing
+
+Then, FIR tree is converted into multiple files: each file has common preamble and a single snippet inside
+
+```
+<FirFile>
+    <Preamble>
+        package myrepl.snippet1
+    </Preamble>
+    <FirSnippet>
+        <statement>val a = 1</statement>
+    </FirSnippet>
+</FirFile>
+```
+
+```
+<FirFile>
+    <Preamble>
+        package myrepl.snippet1
+    </Preamble>
+    <FirSnippet>
+        <statement>val b = 2</statement>
+    </FirSnippet>
+</FirFile>
+```
+(the rest 2 snippets are extracted in the same way)
+
+All subsequent phases of compilation are performed separately for each of the extracted `FirFile`s.
+
+### 4: FIR Resolve
+
+We run the FIR transformations that are done the same way they are done for the
+regular files. However, we need to add special scopes for resolving symbols from the
+*REPL state*. We do it on the body resolve phase. We add a FIR session extension that holds the state
+and constructs the scopes.
+
+NB! We can only have one top-level declaration inside the snippet, see (3).
+
+#### Callables and classes resolve
+Callables and classes are already inside the FIR session, fully resolved.
+However, they are each inside its own package. We can't import all the packages because we
+will get the ambiguity for any declarations repeated more than once. We also can't import selected
+packages because we may have several declarations inside each snippet package. That's why we create
+special scope for callables and classes resolution. Inside these scopes, we search for the symbols
+in all snippets packages in reversed direction. The list of packages is stored inside the REPL state.
+
+#### Properties resolve
+We could do the same thing for properties, but we suppose that properties' types could be
+enhanced after the evaluation. That's why we store property names along with their types (TODO: types of these types)
+inside the REPL state, and also provide them in the special resolution scope.
+(TODO: some reasoning is missing here)
+
+### 5: Resolve results collection
+
+After the body resolve, we store all the resolved top-level variables
+(there could be several variables in case of destructing assignment, also there could
+be a result property in case if it's the last sub-snippet that contains expression-statement)
+inside the REPL state to reuse them later
+
+### 6: Checkers
+
+After the resolve we should run FIR checkers
+
+#### Control flow analysis
+
+(TODO) We probably should unite all the snippets together again to do build correct control flow graph.
+In particular, we need it for cases like this:
+
+```kotlin
+val x: Any = 1
+x as Int
+x + 1
+```
+
+### 7: FIR -> IR
+
+### 8: IR lowerings
+
+### 9: IR -> Bytecode
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirSnippetSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirSnippetSymbol.kt
new file mode 100644
index 0000000..e041d8d
--- /dev/null
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirSnippetSymbol.kt
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.symbols.impl
+
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
+
+class FirSnippetSymbol: FirBasedSymbol<FirSnippet>()
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ReplId.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ReplId.kt
new file mode 100644
index 0000000..73a21af
--- /dev/null
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ReplId.kt
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.fir.types
+
+data class ReplId(val id: String)
diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt
index 2e831a7..461cd54 100644
--- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt
+++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt
@@ -380,8 +380,16 @@
             fields from resolvedQualifier
         }
 
+        val scriptCodeFragmentBuilder by builder {
+            fields from scriptCodeFragment without "symbol"
+        }
+
         builder(script) {
-            withCopy()
+            parents += scriptCodeFragmentBuilder
+        }
+
+        builder(snippet) {
+            parents += scriptCodeFragmentBuilder
         }
 
         builder(codeFragment) {
diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt
index 3964545..3e896bb 100644
--- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt
+++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt
@@ -16,7 +16,6 @@
 import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeParameterRef
 import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeProjection
 import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeRef
-import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.valueParameter
 import org.jetbrains.kotlin.fir.tree.generator.context.type
 import org.jetbrains.kotlin.fir.tree.generator.model.*
 
@@ -87,4 +86,6 @@
     val scopeProvider by lazy { field("scopeProvider", firScopeProviderType) }
 
     val smartcastStability by lazy { field(smartcastStabilityType) }
+
+    val replName by lazy { field("replName", nameType) }
 }
diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt
index 6d4ad3c..914f549 100644
--- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt
+++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt
@@ -65,7 +65,9 @@
     val backingField by element(Declaration, variable, typeParametersOwner, statement)
     val constructor by element(Declaration, function, typeParameterRefsOwner, contractDescriptionOwner)
     val file by element(Declaration, declaration, controlFlowGraphOwner)
-    val script by element(Declaration, declaration)
+    val scriptCodeFragment by sealedElement(Declaration, declaration)
+    val script by element(Declaration, scriptCodeFragment)
+    val snippet by element(Declaration, scriptCodeFragment)
     val codeFragment by element(Declaration, declaration)
     val packageDirective by element(Other)
 
diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt
index 3cf9d70d..b6523f2 100644
--- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt
+++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt
@@ -17,6 +17,7 @@
 import org.jetbrains.kotlin.fir.tree.generator.FieldSets.modality
 import org.jetbrains.kotlin.fir.tree.generator.FieldSets.name
 import org.jetbrains.kotlin.fir.tree.generator.FieldSets.receivers
+import org.jetbrains.kotlin.fir.tree.generator.FieldSets.replName
 import org.jetbrains.kotlin.fir.tree.generator.FieldSets.returnTypeRef
 import org.jetbrains.kotlin.fir.tree.generator.FieldSets.scopeProvider
 import org.jetbrains.kotlin.fir.tree.generator.FieldSets.smartcastStability
@@ -485,13 +486,21 @@
             +symbol("FirFileSymbol")
         }
 
+        scriptCodeFragment.configure {
+            +fieldList(statement, withReplace = true, useMutableOrEmpty = true).withTransform()
+            +field("resultPropertyName", nameType, nullable = true)
+            +fieldList(contextReceiver, useMutableOrEmpty = true)
+        }
+
         script.configure {
             +name
-            +fieldList(statement, withReplace = true, useMutableOrEmpty = true).withTransform()
             +symbol("FirScriptSymbol")
             +fieldList("parameters", variable, withReplace = false)
-            +fieldList(contextReceiver, useMutableOrEmpty = true)
-            +field("resultPropertyName", nameType, nullable = true)
+        }
+
+        snippet.configure {
+            +symbol("FirSnippetSymbol")
+            +replName
         }
 
         codeFragment.configure {
diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt
index bfbed71..6b9e1b7 100644
--- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt
+++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt
@@ -177,6 +177,9 @@
  */
 val ScriptCompilationConfigurationKeys.isStandalone by PropertiesCollection.key<Boolean>(true)
 
+
+val ScriptCompilationConfigurationKeys.isReplSnippet by PropertiesCollection.key<Boolean>(false)
+
 /**
  * The sub-builder DSL for configuring refinement callbacks
  */
diff --git a/plugins/scripting/scripting-compiler/build.gradle.kts b/plugins/scripting/scripting-compiler/build.gradle.kts
index 6399f16..b43657a 100644
--- a/plugins/scripting/scripting-compiler/build.gradle.kts
+++ b/plugins/scripting/scripting-compiler/build.gradle.kts
@@ -11,6 +11,7 @@
     compileOnly(project(":compiler:psi"))
     compileOnly(project(":compiler:plugin-api"))
     compileOnly(project(":compiler:fir:entrypoint"))
+    compileOnly(project(":compiler:fir:providers"))
     compileOnly(project(":compiler:fir:raw-fir:raw-fir.common"))
     compileOnly(project(":compiler:fir:tree"))
     compileOnly(project(":compiler:cli"))
diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/FirReplRegistrar.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/FirReplRegistrar.kt
new file mode 100644
index 0000000..86a804a
--- /dev/null
+++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/FirReplRegistrar.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.scripting.compiler.plugin
+
+import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
+import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ReplState
+import org.jetbrains.kotlin.scripting.compiler.plugin.services.FirSnippetConfigurationExtensionImpl
+import org.jetbrains.kotlin.scripting.compiler.plugin.services.FirSnippetScopesExtensionImpl
+
+class FirReplRegistrar(private val replState: ReplState): FirExtensionRegistrar() {
+    override fun ExtensionRegistrarContext.configurePlugin() {
+        +FirSnippetConfigurationExtensionImpl.getFactory(replState)
+        +FirSnippetScopesExtensionImpl.getFactory(replState)
+    }
+}
\ No newline at end of file
diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/K2JvmReplCompiler.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/K2JvmReplCompiler.kt
new file mode 100644
index 0000000..018a69f
--- /dev/null
+++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/K2JvmReplCompiler.kt
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.scripting.compiler.plugin.impl
+
+import org.jetbrains.kotlin.KtPsiSourceFile
+import org.jetbrains.kotlin.cli.common.*
+import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
+import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector
+import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
+import org.jetbrains.kotlin.cli.common.messages.MessageCollectorBasedReporter
+import org.jetbrains.kotlin.cli.common.repl.LineId
+import org.jetbrains.kotlin.cli.jvm.compiler.VfsBasedProjectEnvironment
+import org.jetbrains.kotlin.cli.jvm.compiler.createLibraryListForJvm
+import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.*
+import org.jetbrains.kotlin.cli.jvm.compiler.toAbstractProjectEnvironment
+import org.jetbrains.kotlin.config.CommonConfigurationKeys
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
+import org.jetbrains.kotlin.fir.declarations.FirVariable
+import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
+import org.jetbrains.kotlin.fir.pipeline.*
+import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
+import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
+import org.jetbrains.kotlin.modules.TargetId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.platform.CommonPlatforms
+import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.scripting.compiler.plugin.FirReplRegistrar
+import kotlin.script.experimental.api.*
+import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
+import kotlin.script.experimental.util.PropertiesCollection
+
+class K2JvmReplCompiler {
+
+    private val replState = ReplStateImpl(FqName("myRepl"))
+
+    suspend fun compile(
+        snippets: Iterable<SourceCode>,
+        configuration: ScriptCompilationConfiguration
+    ): ResultWithDiagnostics<List<KJvmCompiledScript>> {
+        val context = provideCompilationContext(configuration)
+
+        val result = snippets.flatMapSuccess { snippet ->
+            withMessageCollector(snippet) { messageCollector ->
+                compileImpl(snippet, messageCollector, configuration, context)
+            }
+        }
+
+        //TODO: remove
+        return result
+    }
+
+    private suspend fun compileImpl(
+        snippet: SourceCode,
+        messageCollector: ScriptDiagnosticsMessageCollector,
+        configuration: ScriptCompilationConfiguration,
+        context: SharedScriptCompilationContext,
+    ): ResultWithDiagnostics<List<KJvmCompiledScript>> {
+        val initialConfiguration = configuration.refineBeforeParsing(snippet).valueOr { return it }
+
+        val errorHolder = object : MessageCollectorBasedReporter {
+            override val messageCollector = messageCollector
+        }
+        val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter()
+
+        val ktFile = prepareForAnalyze(snippet, errorHolder, context, failOnSyntaxErrors = true).valueOr { return it }
+        collectRefinedSourcesAndUpdateEnvironment(
+            context,
+            ktFile,
+            initialConfiguration,
+            messageCollector
+        )
+
+        val sourceFiles = listOf(ktFile)
+
+        // TODO: is it needed?
+        checkKotlinPackageUsageForPsi(context.environment.configuration, sourceFiles, messageCollector)
+
+        if (messageCollector.hasErrors()) return failure(messageCollector)
+
+        val lineId = LineId(replState.nextSnippetId(), 0, snippet.hashCode())
+
+        val rootModuleName = "snippet_${lineId.no}"
+        val kotlinCompilerConfiguration = context.environment.configuration
+        val renderDiagnosticName = kotlinCompilerConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
+
+        val projectEnvironment = context.environment.toAbstractProjectEnvironment()
+        val compilerEnvironment = ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
+
+        val librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
+        val libraryList = createLibraryListForJvm(
+            rootModuleName,
+            kotlinCompilerConfiguration,
+            friendPaths = emptyList()
+        )
+
+        val extensionRegistrars = (projectEnvironment as? VfsBasedProjectEnvironment)
+            ?.let { FirExtensionRegistrar.getInstances(it.project) }
+            .orEmpty() + FirReplRegistrar(replState)
+
+        val targetId = TargetId(
+            kotlinCompilerConfiguration[CommonConfigurationKeys.MODULE_NAME] ?: JvmProtoBufUtil.DEFAULT_MODULE_NAME,
+            "java-production"
+        )
+
+        val sources = sourceFiles.map { KtPsiSourceFile(it) }
+
+        val compilerInput = ModuleCompilerInput(
+            targetId,
+            GroupedKtSources(platformSources = sources, commonSources = emptySet(), sourcesByModuleName = emptyMap()),
+            CommonPlatforms.defaultCommonPlatform,
+            JvmPlatforms.unspecifiedJvmPlatform,
+            kotlinCompilerConfiguration
+        )
+
+        val session = prepareJvmSessions(
+            sourceFiles, kotlinCompilerConfiguration, projectEnvironment, Name.special("<$rootModuleName>"), extensionRegistrars = extensionRegistrars,
+            librariesScope, libraryList, isCommonSourceForPsi, fileBelongsToModuleForPsi,
+            createProviderAndScopeForIncrementalCompilation = { files ->
+                // TODO: something else?
+                null
+            }
+        ).single().session
+
+        val rawFir = session.buildFirFromKtFiles(sourceFiles)
+
+        val compiledScripts = mutableListOf<KJvmCompiledScript>()
+
+        for (firFile in rawFir) {
+            val (scopeSession, fir) = session.runResolution(listOf(firFile))
+            // checkers
+            session.runCheckers(scopeSession, fir, diagnosticsReporter)
+
+            // Collect variables from snippets here
+
+
+            val analysisResults = FirResult(listOf(ModuleCompilerAnalyzedOutput(session, scopeSession, fir)))
+
+            if (diagnosticsReporter.hasErrors) {
+                diagnosticsReporter.reportToMessageCollector(messageCollector, renderDiagnosticName)
+                return failure(messageCollector)
+            }
+
+            val irInput = convertAnalyzedFirToIr(compilerInput, analysisResults, compilerEnvironment)
+
+            val codegenOutput = generateCodeFromIr(irInput, compilerEnvironment, null)
+
+            diagnosticsReporter.reportToMessageCollector(messageCollector, renderDiagnosticName)
+
+            if (diagnosticsReporter.hasErrors) {
+                return failure(messageCollector)
+            }
+
+            val compiledScript = makeCompiledScript(
+                codegenOutput.generationState,
+                snippet,
+                ktFile,
+                emptyList(),
+                { initialConfiguration } // TODO: provide refined configuration?
+            )
+            when (compiledScript) {
+                is ResultWithDiagnostics.Success<KJvmCompiledScript> -> compiledScripts.add(compiledScript.value)
+                is ResultWithDiagnostics.Failure -> return compiledScript
+            }
+        }
+
+        //TODO: remove
+        return ResultWithDiagnostics.Success(compiledScripts, messageCollector.diagnostics)
+    }
+
+    protected fun prepareForAnalyze(
+        snippet: SourceCode,
+        errorHolder: MessageCollectorBasedReporter,
+        context: SharedScriptCompilationContext,
+        failOnSyntaxErrors: Boolean
+    ): ResultWithDiagnostics<KtFile> =
+        withMessageCollector(
+            snippet,
+            errorHolder.messageCollector
+        ) { messageCollector ->
+            setIdeaIoUseFallback()
+
+            val snippetKtFile =
+                getScriptKtFile(
+                    snippet,
+                    context.baseScriptCompilationConfiguration,
+                    context.environment.project,
+                    messageCollector
+                )
+                    .valueOr { return it }
+
+            val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(snippetKtFile, errorHolder)
+            if (syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof) {
+                messageCollector.report(ScriptDiagnostic(ScriptDiagnostic.incompleteCode, "Incomplete code"))
+            }
+            if (failOnSyntaxErrors && syntaxErrorReport.isHasErrors) return failure(messageCollector)
+
+            return snippetKtFile.asSuccess()
+        }
+
+    private fun provideCompilationContext(configuration: ScriptCompilationConfiguration): SharedScriptCompilationContext {
+        // It's not clear if we wish to recreate context every time or reuse the existing one
+        TODO()
+    }
+}
+
+interface ReplVariable {
+    val symbol: FirVariableSymbol<*>
+
+    val enhancedProperty: FirVariable?
+    val enhancedType: String?
+    val value: Any?
+    val hasValue: Boolean
+
+    fun setValue(value: Any?)
+}
+
+interface ReplState {
+    val name: FqName
+
+    val variables: MutableMap<Name, ReplVariable>
+    fun nextSnippetId(): Int
+
+    fun addDeclaration(symbol: FirVariableSymbol<*>)
+
+    //fun setValueForDeclaration(snippetName: Name, symbol: FirVariableSymbol<*>, value: Any?)
+
+    fun addPackage(packageName: FqName)
+
+    fun processPackages(processor: (packageName: FqName) -> Boolean)
+
+    fun findVariable(name: Name): ReplVariable?
+}
+
+class ReplVariableImpl(
+    override val symbol: FirVariableSymbol<*>,
+): ReplVariable {
+
+    override var enhancedProperty: FirVariable? = null
+    override var enhancedType: String? = null
+
+    private var _value: Any? = null
+
+    override val value: Any? get() = _value
+
+    private var _isInitialized = false
+
+    override val hasValue: Boolean
+        get() = _isInitialized
+
+    override fun setValue(value: Any?) {
+        _value = value
+        _isInitialized = true
+    }
+}
+
+class ReplStateImpl(
+    override val name: FqName
+): ReplState {
+    private val _variables: MutableMap<Name, ReplVariable> = HashMap()
+    //private val variableByFullName: MutableMap<String, ReplVariable> = mutableMapOf()
+    private var _nextSnippetId = 1
+    private val packages = ArrayList<FqName>()
+
+    override val variables: MutableMap<Name, ReplVariable> = _variables
+    override fun nextSnippetId(): Int {
+        return (_nextSnippetId++)
+    }
+
+//    private fun getFullName(snippetName: Name, name: Name): String {
+//        return "snippet_${snippetName}_${name.asString()}"
+//    }
+
+    override fun addDeclaration(symbol: FirVariableSymbol<*>) {
+        //val fullName = getFullName(snippetName, symbol.name)
+        val variable = ReplVariableImpl(symbol)
+        //variableByFullName[fullName] = variable
+        _variables[symbol.name] = variable
+    }
+
+//    override fun setValueForDeclaration(snippetName: Name, symbol: FirVariableSymbol<*>, value: Any?) {
+//        val fullName = getFullName(snippetName, symbol.name)
+//        val variable = variableByFullName[fullName] ?: return
+//        variable.setValue(value)
+//    }
+
+    override fun addPackage(packageName: FqName) {
+        packages.add(packageName)
+    }
+
+    override fun processPackages(processor: (packageName: FqName) -> Boolean) {
+        for (packageName in packages.asReversed()) {
+            if (!processor(packageName)) return
+        }
+    }
+
+    override fun findVariable(name: Name): ReplVariable? {
+        // TODO: optimize search
+        return variables[name]
+    }
+}
+
+val ScriptCompilationConfigurationKeys.replState by PropertiesCollection.key<ReplState?>(null)
diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt
index 25f55d7..2a274ba 100644
--- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt
+++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt
@@ -89,6 +89,9 @@
                     messageCollector
                 )
 
+                assert(sourceFiles.size == 1)
+                assert(sourceDependencies.size == 0)
+
                 val firstFailure = sourceDependencies.firstOrNull { it.sourceDependencies is ResultWithDiagnostics.Failure }
                     ?.let { it.sourceDependencies as ResultWithDiagnostics.Failure }
 
diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt
index 928b6b3..8626c98e 100644
--- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt
+++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt
@@ -54,10 +54,7 @@
     @OptIn(SymbolInternals::class)
     override fun FirScriptBuilder.configureContainingFile(fileBuilder: FirFileBuilder) {
         val sourceFile = fileBuilder.sourceFile ?: return
-        val configuration = getOrLoadConfiguration(sourceFile) ?: run {
-            log.warn("Configuration for ${sourceFile.asString()} wasn't found. FirScriptBuilder wasn't configured.")
-            return
-        }
+        val configuration = getOrLoadConfigurationReporting(sourceFile) ?: return
 
         configuration[ScriptCompilationConfiguration.defaultImports]?.forEach { defaultImport ->
             val trimmed = defaultImport.trim()
@@ -173,6 +170,13 @@
 
     private fun KtSourceFile.asString() = path ?: name
 
+    private fun getOrLoadConfigurationReporting(file: KtSourceFile): ScriptCompilationConfiguration? {
+        return getOrLoadConfiguration(file) ?: run {
+            log.warn("Configuration for ${file.asString()} wasn't found. FirScriptBuilder wasn't configured.")
+            return null
+        }
+    }
+
     private fun getOrLoadConfiguration(file: KtSourceFile): ScriptCompilationConfiguration? {
         val service = checkNotNull(session.scriptDefinitionProviderService)
         val sourceCode = file.toSourceCode()
diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirSnippetConfigurationExtensionImpl.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirSnippetConfigurationExtensionImpl.kt
new file mode 100644
index 0000000..bb04399
--- /dev/null
+++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirSnippetConfigurationExtensionImpl.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.scripting.compiler.plugin.services
+
+import org.jetbrains.kotlin.KtSourceFile
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.builder.FirScriptConfiguratorExtension
+import org.jetbrains.kotlin.fir.builder.FirSnippetConfiguratorExtension
+import org.jetbrains.kotlin.fir.builder.buildPackageDirective
+import org.jetbrains.kotlin.fir.declarations.builder.FirFileBuilder
+import org.jetbrains.kotlin.fir.declarations.builder.FirSnippetBuilder
+import org.jetbrains.kotlin.fir.extensions.extensionService
+import org.jetbrains.kotlin.fir.extensions.snippetScopesConfigurators
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ReplState
+import kotlin.script.experimental.host.ScriptingHostConfiguration
+
+class FirSnippetConfigurationExtensionImpl(
+    session: FirSession,
+    val replState: ReplState,
+): FirSnippetConfiguratorExtension(session) {
+    override fun FirSnippetBuilder.configure(sourceFile: KtSourceFile) {
+        TODO("Not yet implemented")
+    }
+
+    override fun FirSnippetBuilder.configureContainingFile(fileBuilder: FirFileBuilder) {
+        fileBuilder.packageDirective = buildPackageDirective {
+            // TODO: generate reliable names
+            val directive = replState.name.child(Name.identifier(fileBuilder.name))
+
+            this.packageFqName = directive
+
+            session.extensionService.snippetScopesConfigurators
+        }
+    }
+
+    companion object {
+        fun getFactory(replState: ReplState): Factory {
+            return Factory { session -> FirSnippetConfigurationExtensionImpl(session, replState) }
+        }
+    }
+}
diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirSnippetScopesExtensionImpl.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirSnippetScopesExtensionImpl.kt
new file mode 100644
index 0000000..145cb9f
--- /dev/null
+++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirSnippetScopesExtensionImpl.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.scripting.compiler.plugin.services
+
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.FirSnippet
+import org.jetbrains.kotlin.fir.extensions.FirSnippetScopesExtension
+import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
+import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ReplState
+
+class FirSnippetScopesExtensionImpl(session: FirSession, private val replState: ReplState) : FirSnippetScopesExtension(session) {
+    override fun contributeVariablesToReplScope(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
+        replState.findVariable(name)?.let { processor(it.symbol) }
+    }
+
+    override fun contributeClassifiersToReplScope(name: Name, processor: (FirClassifierSymbol<*>) -> Unit) {
+        replState.processPackages { packageName ->
+            val symbol = session.symbolProvider.getClassLikeSymbolByClassId(ClassId(packageName, name))
+
+            if (symbol == null) return@processPackages true
+
+            processor(symbol)
+            false
+        }
+    }
+
+    override fun contributeFunctionsToReplScope(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
+        replState.processPackages { packageName ->
+            val symbols = session.symbolProvider.getTopLevelFunctionSymbols(packageName, name)
+
+            // TODO: resolve ambiguity
+            symbols.forEach(processor)
+            true
+        }
+    }
+
+    override fun registerVariables(firSnippet: FirSnippet, variables: List<FirVariableSymbol<*>>) {
+        variables.forEach { replState.addDeclaration(it) }
+    }
+
+    companion object {
+        fun getFactory(replState: ReplState): Factory {
+            return Factory { session -> FirSnippetScopesExtensionImpl(session, replState) }
+        }
+    }
+}
\ No newline at end of file