Regulární výraz pro funkce a metody v Go

hknmtt

Regulární výraz pro funkce a metody v Go
« kdy: 18. 01. 2023, 17:20:45 »
Poradite regex do Go na najdenie vsetkych funkcii, vratane "metod"?

Teda:
Kód: [Vybrat]
func (t *Time) sec() int64 {
if t.wall&hasMonotonic != 0 {
return wallToInternal + int64(t.wall<<1>>(nsecShift+1))
}
return t.ext
}

a

func Since(t Time) Duration {
var now Time
if t.wall&hasMonotonic != 0 {
// Common case optimization: if t has monotonic time, then Sub will use only it.
now = Time{hasMonotonic, runtimeNano() - startNano, nil}
} else {
now = Now()
}
return now.Sub(t)
}

Nedari sa mi matchnut telo funkcii a regex nie je moje forte. Potrebujem sa len zbavit vsetkych funkcii z vygenerovaneho kodu lebo chcem odtial dostat len structy a je toho prilis vela skratka na manualne ocistenie.
« Poslední změna: 19. 01. 2023, 06:05:06 od Petr Krčmář »


alex6bbc

  • *****
  • 1 751
    • Zobrazit profil
    • E-mail
Re:Regulerny vyraz na Go funkcie a metody
« Odpověď #1 kdy: 18. 01. 2023, 18:27:36 »
vyhledat radky zacinajici func :-)

to je otazka zda telo jde chytit regexem, spis bych udelal skript, ktery najde func a vsecko za tim a do prvni { a pak pricitat nalezene { a odecitat } a az se dospeje k nule tak je konec funkce a to zahodit.

a nebo obdobne s type a jen co je spojeno s type a {} ponechat do vypisu.
« Poslední změna: 18. 01. 2023, 18:31:09 od alex6bbc »

Re:Regulerny vyraz na Go funkcie a metody
« Odpověď #2 kdy: 18. 01. 2023, 18:59:27 »
vyhledat radky zacinajici func :-)

to je otazka zda telo jde chytit regexem, spis bych udelal skript, ktery najde func a vsecko za tim a do prvni { a pak pricitat nalezene { a odecitat } a az se dospeje k nule tak je konec funkce a to zahodit.

a nebo obdobne s type a jen co je spojeno s type a {} ponechat do vypisu.

to ti rozbije jakejkoli zakomentovanej blok nebo jakakoli { v retezci. Jedine pokud je jistota, ze zdrojaky prosly pres gofmt, pak asi hledat ^func a potom nejblizsi ^}

Jde to relativne (RELATIVNE) snadno a hlavne spravne pres AST. Nedavno o tom vysel clanek, Go ma primo v zakladni knihovne podporu pro parsing do AST a z toho uz se snadno vypraskaji ty hledane structy atd.

Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #3 kdy: 18. 01. 2023, 19:14:45 »
Zdrojové kódy běžných programovacích jazyků (jako Go) se nedají zpracovávat regulárním výrazem. Jsou na to potřeba silnější výrazové možnosti (vyšší typ gramatiky).

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #4 kdy: 18. 01. 2023, 19:23:38 »
Ta gramatika bude (přinejmenším) bezkontextová. Jak je zmíněno výše, Go má ve standardní knihovně prostředky pro parsing zdrojáků a práci s AST.


Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #5 kdy: 18. 01. 2023, 19:29:35 »
Jojo, tohle je neco, co by clovek znal, kdyby chodil na VS ;) (narazim na topic https://forum.root.cz/index.php?topic=27090.165)

Programovaci jazyky jsou vetsinou bezkontextove gramatiky, tj. nelze je pokryt regularnimi vyrazy (konecnym automatem), nybrz zasobnikovym automatem, tj. parsovani tak, jak to dela frontend prekladace.

Reseni pomoci AST parseru se zda byt schudne.

Co ale zkusit jednoduchy workaround... gofmt by melo snad srovnat i whitespacy, tudiz bych ocekaval, ze uzaviraci slozena zavorka bude mit pred sebou stejny pocet whitespacu, jako func. Na tom by se nejaky skript uz dal postavit.

Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #6 kdy: 18. 01. 2023, 19:31:22 »
Ta gramatika bude (přinejmenším) bezkontextová. Jak je zmíněno výše, Go má ve standardní knihovně prostředky pro parsing zdrojáků a práci s AST.

No "vic" nez bezkontextova urcite nebude, to by uz byl prirozeny jazyk :D tedy alespon dle Chomskeho hierarchie...

Re:Regulerny vyraz na Go funkcie a metody
« Odpověď #7 kdy: 18. 01. 2023, 19:38:35 »
vyhledat radky zacinajici func :-)

to je otazka zda telo jde chytit regexem, spis bych udelal skript, ktery najde func a vsecko za tim a do prvni { a pak pricitat nalezene { a odecitat } a az se dospeje k nule tak je konec funkce a to zahodit.

a nebo obdobne s type a jen co je spojeno s type a {} ponechat do vypisu.

to ti rozbije jakejkoli zakomentovanej blok nebo jakakoli { v retezci. Jedine pokud je jistota, ze zdrojaky prosly pres gofmt, pak asi hledat ^func a potom nejblizsi ^}

Jde to relativne (RELATIVNE) snadno a hlavne spravne pres AST. Nedavno o tom vysel clanek, Go ma primo v zakladni knihovne podporu pro parsing do AST a z toho uz se snadno vypraskaji ty hledane structy atd.

Az ted jsem si vsiml, ze je to to, co jsem psal ja - sorry.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #8 kdy: 18. 01. 2023, 20:07:40 »
Ta gramatika bude (přinejmenším) bezkontextová. Jak je zmíněno výše, Go má ve standardní knihovně prostředky pro parsing zdrojáků a práci s AST.
No "vic" nez bezkontextova urcite nebude, to by uz byl prirozeny jazyk :D tedy alespon dle Chomskeho hierarchie...
Přirozené jazyky v Chomského hierarchii vůbec nejsou. A programovací jazyky dost často bývají context-sensitive.

hknmtt

Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #9 kdy: 18. 01. 2023, 20:18:44 »
ok, diky za info. nenapadlo by ma ze spravit regex ktory len vyhlada funkciu ktorej telo medzi {} moze byt hocico(tzn len naparuje tu zatvorku) je taky problem.

tak som si spravil skript na to na koniec. na kolene na rychlo ale funguje:
Kód: [Vybrat]
package main

import (
"bufio"
"bytes"
"errors"
"io"
"os"
"path/filepath"
)

func main() {
args := os.Args

if len(args) != 2 {
println("missing file argument")
return
}

src, err := os.OpenFile(filepath.Clean(args[1]), os.O_RDWR, 0666)
if err != nil {
println(err.Error())
return
}

defer func() {
if err := src.Close(); err != nil && errors.Is(err, os.ErrClosed) == false {
println(err.Error())
}
}()

s := bufio.NewScanner(src)
s.Split(bufio.ScanLines)

fTok := []byte("func ")
openTok := []byte{'{'}
closeTok := []byte{'}'}
emptyTok := []byte{'{', '}'}

matches := make([][]byte, 0, 500)
var match bool
for {
if s.Scan() == false {
break
}
if match == false {
if bytes.HasPrefix(s.Bytes(), fTok) && (bytes.HasSuffix(s.Bytes(), openTok) || bytes.HasSuffix(s.Bytes(), emptyTok)) {
matches = append(matches, append(make([]byte, 0, len(s.Bytes())), s.Bytes()...))
matches[len(matches)-1] = append(matches[len(matches)-1], '\n')
match = bytes.HasSuffix(s.Bytes(), openTok)
}
} else {
matches[len(matches)-1] = append(matches[len(matches)-1], s.Bytes()...)
matches[len(matches)-1] = append(matches[len(matches)-1], '\n')
match = bytes.Equal(s.Bytes(), closeTok) == false
}
}

if len(matches) == 0 {
return
}

if _, err := src.Seek(0, io.SeekStart); err != nil {
println(err.Error())
return
}

data, err := io.ReadAll(src)
if err != nil {
println(err.Error())
return
}

for k := range matches {
data = bytes.Replace(data, matches[k], nil, 1)
}

if _, err := src.Seek(0, io.SeekStart); err != nil {
println(err.Error())
return
}

if err := src.Truncate(0); err != nil {
println(err.Error())
return
}

if _, err := src.Write(data); err != nil {
println(err.Error())
return
}
}


Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #10 kdy: 18. 01. 2023, 20:44:36 »
tzn len naparuje tu zatvorku
Jednak pro regulární výrazy je problém už samotné vnořování párových závorek. Za druhé, to právě není pravda, že stačí napárovat závorky – jak už bylo řečeno, to vám rozbije závorka v textovém řetězci nebo v komentáři.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #11 kdy: 18. 01. 2023, 20:56:11 »
ok, diky za info. nenapadlo by ma ze spravit regex ktory len vyhlada funkciu ktorej telo medzi {} moze byt hocico(tzn len naparuje tu zatvorku) je taky problem.

tak som si spravil skript na to na koniec. na kolene na rychlo ale funguje:
Kód: [Vybrat]
package main

import (
"bufio"
"bytes"
"errors"
"io"
"os"
"path/filepath"
)

func main() {
args := os.Args

if len(args) != 2 {
println("missing file argument")
return
}

src, err := os.OpenFile(filepath.Clean(args[1]), os.O_RDWR, 0666)
if err != nil {
println(err.Error())
return
}

defer func() {
if err := src.Close(); err != nil && errors.Is(err, os.ErrClosed) == false {
println(err.Error())
}
}()

s := bufio.NewScanner(src)
s.Split(bufio.ScanLines)

fTok := []byte("func ")
openTok := []byte{'{'}
closeTok := []byte{'}'}
emptyTok := []byte{'{', '}'}

matches := make([][]byte, 0, 500)
var match bool
for {
if s.Scan() == false {
break
}
if match == false {
if bytes.HasPrefix(s.Bytes(), fTok) && (bytes.HasSuffix(s.Bytes(), openTok) || bytes.HasSuffix(s.Bytes(), emptyTok)) {
matches = append(matches, append(make([]byte, 0, len(s.Bytes())), s.Bytes()...))
matches[len(matches)-1] = append(matches[len(matches)-1], '\n')
match = bytes.HasSuffix(s.Bytes(), openTok)
}
} else {
matches[len(matches)-1] = append(matches[len(matches)-1], s.Bytes()...)
matches[len(matches)-1] = append(matches[len(matches)-1], '\n')
match = bytes.Equal(s.Bytes(), closeTok) == false
}
}

if len(matches) == 0 {
return
}

if _, err := src.Seek(0, io.SeekStart); err != nil {
println(err.Error())
return
}

data, err := io.ReadAll(src)
if err != nil {
println(err.Error())
return
}

for k := range matches {
data = bytes.Replace(data, matches[k], nil, 1)
}

if _, err := src.Seek(0, io.SeekStart); err != nil {
println(err.Error())
return
}

if err := src.Truncate(0); err != nil {
println(err.Error())
return
}

if _, err := src.Write(data); err != nil {
println(err.Error())
return
}
}

Pozor na pumping lemma ;)

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #12 kdy: 18. 01. 2023, 20:59:30 »
to by uz byl prirozeny jazyk
Přirozené jazyky bývají dost často bezkontextové, hlavně ty s bohatou morfologií nebo polysyntetické. Jsou výjimky, holandština nebo švýcarská němčina mají konstrukce, které bezkontextově vyjádřit nejdou, ale to jsou spíše netypické příklady.

Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #13 kdy: 18. 01. 2023, 22:39:11 »
tzn len naparuje tu zatvorku
Jednak pro regulární výrazy je problém už samotné vnořování párových závorek. Za druhé, to právě není pravda, že stačí napárovat závorky – jak už bylo řečeno, to vám rozbije závorka v textovém řetězci nebo v komentáři.


Koukám, že jdu rozbíjet hračky pozdě.
https://go.dev/play/p/pB7As-_tqmN

Re:Regulérní výraz pro funkce a metody v Go
« Odpověď #14 kdy: 18. 01. 2023, 23:40:08 »
Ta gramatika bude (přinejmenším) bezkontextová. Jak je zmíněno výše, Go má ve standardní knihovně prostředky pro parsing zdrojáků a práci s AST.
No "vic" nez bezkontextova urcite nebude, to by uz byl prirozeny jazyk :D tedy alespon dle Chomskeho hierarchie...
Přirozené jazyky v Chomského hierarchii vůbec nejsou. A programovací jazyky dost často bývají context-sensitive.

OK, vidim svoji chybu, uznavam, prirozene jazyky tam vubec nepatri, Chomskeho hierarchie jsou pouze formalismy, uz je to nejaky ten cas od automatu a gramatik...

Nicmene, troufam si tvrdit, ze je fer mluvit o drtive vetsine programovacich jazyku jako o bezkontextovych - parser funguje nad gramatikou a ta je IMO bezkontextova takrka vzdy. Zbytek jsou uz semanticka pravidla aplikovana v jine fazi, neni-liz pravda?