TL;DR
Modèles C ++, inclusions Python, ... il existe une fonctionnalité de langage qui a été complètement maîtrisée par elle-même en raison de la magie noire provoquée par la liberté supplémentaire.
Et ici, nous déclarons que ** go-template a rejoint les rangs de la magie noire **.
En parlant de go-template, il existe une image forte d'un mini langage pour des modèles tels que le HTML de gin
et la mise en forme de la réponse de kubectl
(bien qu'il soit fait avec cette intention dans le nom ~~), Ce qui suit peut être ** tout possible ** [^ 1].
range
―― Branchement conditionnel par bloc ʻif`
--Déclaration et mise à jour des variables (réaffectation)Référence (officielle): template --GoDoc
J'ai donc essayé d'implémenter le système de traitement de brainf \ * ck, qui est la passerelle vers l'exhaustivité de Turing, avec go-template (fonction / syntaxe standard uniquement [^ 2] sans compter sur le langage Go).
Utilisez kubectl
.
Mettez le code source de brainf \ * ck dans le fichier manifeste du pod, et lorsque vous l'obtenez avec kubectl
, utilisez go-template pour mouler (= évaluer avec l'interpréteur brainf \ * ck de go-template). Je suis.
Dépôt: go-template-bf-interpreter
(J'ai utilisé kubectl
parce que je connaissais go-template pour la première fois avec kubectl
. ~~ J'ai écrit au début que" je connais la génération HTML de gin
", mais je suis désolé pour Airp ~~)
Puisque n'importe quelle clé et valeur (chaîne de caractères) peut être stockée dans metadata.annotations
, le code source est stocké ici. Aussi, ajoutons l'entrée standard à brainf \ * ck.
hello.yaml
metadata:
name: bf-source-pod
# add dummies to make annotations long enough to loop (see bf-interpreter.tpl for details)
annotations:
# used for bf stdin
input: ""
# bf source code
src: >
+++++++++[>++++++++>+++++++++++>+++>+<<<<-]>.>++.+++++++..+++.
>+++++.<<+++++++++++++++.>.+++.------.--------.>+.>+.
dummy1: dummy1
dummy2: dummy2
#...
Au fait, la raison pour laquelle j'ai mis beaucoup de clés factices est d'augmenter le nombre de boucles de l'interpréteur (décrit plus loin).
J'ai utilisé le code helloworld de Brainfuck Super Primer --Qiita.
Je n'utilise de toute façon pas le conteneur à dosettes, donc tout va bien. Pour le moment, j'ai réalisé une image alpine qui démarre rapidement.
python
#Construire un cluster k8s(Un exemple est gentil)
$ kind create cluster
#Créez un pod avec le code helloworld ci-dessus
$ kubectl create -f hello.yaml
pod/bf-source-pod created
#informations sur le pod(=Code source)Et son contenu devient un interprète aller-Évaluer avec un modèle
$ kubectl get pods -o go-template-file=bf-interpreter.tpl
Hello World!
L'implémentation de l'interpréteur brainf \ * ck ressemble à ceci. ~~ Retrait de l'enfer. ~~ bf-interpreter.tpl
Ci-dessous, je vais vous présenter les astuces que j'ai utilisées.
Vous pouvez remplir l'espace en dehors des parenthèses en ajoutant -
aux deux extrémités de {{}}
. Si vous utilisez ceci, même si vous mettez des retraits et des sauts de ligne en dehors de {{}}
, ils seront tous ignorés.
** Requis pour la lisibilité ** dans la programmation go-template. ** S'il n'est pas attaché, la reliure sur une seule ligne commencera **.
withspace.tpl
{{if true}}
{{println "got it!"}}
{{else}}
{{println "no..."}}
{{end}}
L'espace gaspillé est sorti tel quel
kubectl get pods -o go-template-file=withspace.tpl
got it!
--Avec trait d'union
trimspace.tpl
{{- if true -}}
{{- println "got it!" -}}
{{- else -}}
{{- println "no..." -}}
{{- end -}}
L'espace gaspillé disparaît
$ kubectl get pods -o go-template-file=trimspace.tpl
got it!
brainf \ * ck nécessite une boucle while. Code source Utilisé pour analyser chaque caractère et sauter lors de l'évaluation de [
, ]
.
Mais malheureusement, string
ne peut pas être itéré avec range
.
De plus, comme les seuls littéraux qui peuvent être créés avec go-template sont des constantes, il n'est pas possible de créer de nouveaux tableaux ou cartes.
python
$ kubectl get pods -o go-template --template '{{range $c := "abc"}}{{println $c}}{{end}}'
...
error: error executing template "{{range $c := \"abc\"}}{{println $c}}{{end}}": template: output:1:14: executing "output" at <"abc">: range can't iterate over abc
Nous utilisons donc les informations de pod metadata.annotations
( map [string] string
) pour la boucle dans range
. Un mannequin est mélangé avec l'annotation afin qu'il puisse être bouclé 16 fois.
hello.yaml
metadata:
name: bf-source-pod
annotations:
# used for bf stdin
input: ""
# bf source code
src: >
+++++++++[>++++++++>+++++++++++>+++>+<<<<-]>.>++.+++++++..+++.
>+++++.<<+++++++++++++++.>.+++.------.--------.>+.>+.
dummy1: dummy1
dummy2: dummy2
#...
dummy14: dummy14
En utilisant cette boucle en plusieurs étapes, l'initialisation de la mémoire et l'analyse du code source sont effectuées.
bf-interpreter.tpl
{{- /*Carte de substitution et utilisation pour le bloc de plage*/ -}}
{{- $Looper := (index .items 0).metadata.annotations -}}
{{- /*Initialisation de la mémoire(len $Looper)^Remplissez 2 octets avec 0) */ -}}
{{- $memory := "" -}}
{{- range $Looper -}}
{{- range $Looper -}}
{{- $memory = print $memory "\x00" -}}
{{- end -}}
{{- end -}}
{{- /*Lire le code source(len $Looper)^Perspective de 3 lettres depuis le début) */ -}}
{{- range $Looper -}}
{{- range $Looper -}}
{{- range $Looper -}}
{{- /* NOTE: exists is implemented only in k8s parser */ -}}
{{- if exists $Source (len $parsingBytePos) -}}
{{- $tokenByte := index $Source (len $parsingBytePos) -}}
{{- $token := printf "%c" $tokenByte -}}
{{- /*Évaluer les jetons (omis)*/ -}}
{{- /* increment pos */ -}}
{{- $parsingBytePos = print $parsingBytePos " " -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
À propos, la raison pour laquelle il boucle 16 fois est d'améliorer les spécifications de l'interpréteur.
--Taille de la mémoire: 256byte
(boucle à 2 étages $ Looper
)
4096 caractères
(boucle en 3 étapes $ Looper
)Malheureusement (deuxième fois), go-template n'a pas de fonctions ou d'opérateurs d'addition / soustraction d'entiers. Cependant, brainf \ * ck nécessite une addition et une soustraction lors de la mise à jour des valeurs de mémoire et des pointeurs.
Donc ** utilisez la longueur de la chaîne au lieu d'un entier **. La longueur de la chaîne de caractères peut être modifiée par combinaison et découpage, et la longueur peut être obtenue sous forme d'entier avec la fonction «len».
--Une addition
inc.tpl
{{- /* go-l'impression de modèle est équivalente au Sprint de Go(Pas d'effets secondaires) */ -}}
{{- $numStr := " " -}}
{{- println (len $numStr) -}}
{{- $numStr = print $numStr " " -}}
{{- println (len $numStr) -}}
python
$ kubectl get pods -o go-template-file=inc.tpl
1
2
--Soustraction
dec.tpl
{{- $numStr := " " -}}
{{- println (len $numStr) -}}
{{- $numStr = slice $numStr 1 -}}
{{- println (len $numStr) -}}
python
$ kubectl get pods -o go-template-file=dec.tpl
1
0
Comme mentionné ci-dessus, vous ne pouvez pas créer de tableau avec go-template. De plus, il n'est pas possible de mettre à jour uniquement les éléments d'un objet existant. Seules les variables peuvent être des rvaleurs dans les expressions d'affectation.
python
$ kubectl get pods -o go-template --template '{{(index .items 0) := "hoge"}}'
error: error parsing template {{(index .items 0) := "hoge"}}, template: output:1: unexpected ":=" in operand
Par conséquent, la chaîne de caractères est utilisée comme mémoire. Dans Go, lors de l'indexation d'une chaîne de caractères, la chaîne de caractères est traitée comme «[] octet», de sorte que la chaîne de caractères elle-même peut être considérée comme une chaîne d'octets.
index des langues
s := "abc"
fmt.Println([]byte(s)) // [97 98 99]
fmt.Println(s[0]) // 97
fmt.Println([]byte(s)[0]) // 97
Et, lors de la mise à jour uniquement d'un certain octet dans la chaîne de caractères avec «+» ou «-» etc., "une nouvelle chaîne de caractères mémoire dans laquelle seul l'octet est remplacé" est créée.
bf-interpreter.tpl
{{- else if eq $token "+" -}}
{{- /* ...Prend la valeur de l'adresse de référence et l'incrémente(réduction) */ -}}
{{- /*Mise à jour de la mémoire*/ -}}
{{- /*Remplacez par une nouvelle mémoire avec uniquement l'adresse de référence remplacée*/ -}}
{{- /*Mémoire avant l'adresse de référence*/ -}}
{{- $former := slice $memory 0 (len $memoryPtr) -}}
{{- /*Mémoire après l'adresse de référence*/ -}}
{{- /* NOTE: (len (print $memoryPtr " ")Est l'adresse de référence+1 */ -}}
{{- $latter := slice $memory (len (print $memoryPtr " ")) -}}
{{- /*Remplacer (Si vous imprimez la valeur d'octet telle quelle, l'entier sera converti en chaîne de caractères, donc printf le convertira en caractère de code ASCII correspondant)*/ -}}
{{- $memory = print $former (printf "%c" $incrementedValue) $latter -}}
{{- end -}}
Ceci est l'introduction du système de traitement go-template brainf \ * ck.
** Allons-y de la programmation par modèle! ** **
[^ 1]: En regardant ça, on a l'impression que "Vous pouvez faire ça avec erb!", Mais si erb peut écrire n'importe quelle expression Ruby, go-template a une grammaire indépendante (seuls les scalaires peuvent être créés, et les fonctions standard de go sont également disponibles). Il existe une liaison que vous ne pouvez pas appeler telle quelle ...
[^ 2]: Certaines fonctions go-template originales de k8 (ʻindex`) sont utilisées. La mise en œuvre est ici
Recommended Posts