Voici l'idée d'un algorithme. Vous devrez l'améliorer et le compléter.
Définissez une classe ExpressionFinder
pour trouver l'expression appropriée dans votre texte.
Dans mon sketch cette classe a les Ivars suivantes
string
: la chaîne complète dans le volet (aire de jeux/transcription/whatever)
compiler
: le compilateur utilisé par votre fenêtre pour évaluer le texte
lines
: la collection d'associations pos->line
, où pos
est la position du line
à l'intérieur de string
index
: indice de courant à la collection lines
utilisée par l'algorithme
interval
: l'intervalle de sortie le cas échéant, sinon nil
Supposons que vous avez la string
, la compiler
et la position
actuelle du curseur au string
. Effectuez les opérations suivantes:
string: aString position: anInteger compiler: aCompiler
string := aString.
compiler := aCompiler.
self computeLines.
index := lines findLast: [:assoc | assoc key <= anInteger]
Voici comment vous calculer la collection de lignes:
computeLines
| reader |
lines := OrderedCollection new.
reader := string readStream.
[reader atEnd]
whileFalse: [lines add: reader position + 1 -> reader nextLine]
Avec tout cela, vous avez tout ce dont vous avez besoin pour trouver le fragment approprié.Voici une idée simple (que vous devez améliorer):
Commencez à l'index de ligne en cours et recherchez le fragment en ajoutant une ligne à la fois. Si trouvé, fin. Si ce n'est pas le cas, diminuez l'index et réessayez à partir de la ligne ci-dessus.
Voici le code
find
| i |
i := index.
[
i <= 0 ifTrue: [^self].
assoc := lines at: i.
self findFrom: assoc key]
whileFalse: [i := i - 1]
où
findFrom: start
| i end success |
i := index.
[| assoc fragment |
assoc := lines at: i + 1 ifAbsent: [string size + 1 -> nil].
end := assoc key - 1.
fragment := string copyFrom: start to: end.
success := self canCompile: fragment.
success not and: [end < string size]]
whileTrue: [i := i + 1].
success ifTrue: [interval := start to: end].
^success
Le code canCompile: fragment
dépend du dialecte, sur les lignes de
canCompile: fragment
^(compiler compileExpression: fragment) notNil
Si vos signaux de compilateur CompilationErrors
, vous devrez mettre un gestionnaire au canCompile:
pour les éviter. Aussi, vous pourriez profiter de ces erreurs. Par exemple, si l'erreur de compilation fait référence à une variable non déclarée, vous savez que vous ne trouverez pas sa définition dans les lignes ci-dessous, donc vous devriez quitter la boucle en findFrom:
afin d'essayer avec la ligne ci-dessus et ainsi de suite.
Salut Grigory, pour moi, il est souvent logique d'exécuter la ligne en cours. Par exemple, lors de l'exécution de l'exécution dans le débogueur, j'inspecte souvent la ligne avant de faire un pas. Et pour cela, il est utile de ne pas sélectionner la ligne manuellement. Ou si vous avez un script plus long, et que vous voulez exécuter et inspecter cette ligne par ligne. –
@NicolaiHess Je suis d'accord. Notez cependant que l'algorithme que j'ai esquissé dans [ma réponse] (http://stackoverflow.com/a/40071982/4081336) commencera avec la ligne courante et ajoutera seulement plus de lignes si la ligne courante ne compile pas. –