Idiomatically determine all the characters that can be used for symbols: Difference between revisions

→‎{{header|Go}}: Replace with really idiomatic code; the previous code had too many magic numbers
(added Ol)
(→‎{{header|Go}}: Replace with really idiomatic code; the previous code had too many magic numbers)
Line 70:
 
=={{header|Go}}==
 
Go allows the underscore, letters, and digits, with "letters" and "digits" defined by Unicode. The first character must be the underscore or a letter. To be exported, the first character must be an upper case letter, again as defined by Unicode.
Most of the code is concerned with printing the Unicode ranges of the valid characters. The remaining part of the code parses the possible identifier and verifies that it is indeed an identifier.
 
<lang go>package main
 
import (
"fmt"
"go/ast"
"go/parser"
"strings"
"unicode"
)
 
type runeRanges struct {
func main() {
ranges []string
fmt.Println("Unicode version: ", unicode.Version)
hasStart bool
fmt.Println()
start rune
fmt.Println("Underscore: _")
end rune
fmt.Println("ASCII digits: 0123456789")
fmt.Println("ASCII letters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
showRange("Unicode digits: ", unicode.Digit)
showRange("Unicode letters: ", unicode.Letter)
}
 
func (r *runeRanges) add(cp rune) {
const Ω = 52
if !r.hasStart {
r.hasStart = true
r.start = cp
r.end = cp
return
}
 
if cp == r.end+1 {
var n int
r.end = cp
var ряд, 广度一六 int
return
 
func showRange(hdr string, rt *unicode.RangeTable) {
fmt.Print(hdr)
n = 0
r16 := rt.R16
for r16[0].Hi < 128 {
r16 = r16[1:]
}
 
for _, rng := range r16 {
r.writeTo(&r.ranges)
for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
 
fmt.Print(string(r))
r.start = cp
n++
r.end = cp
if n == Ω {
}
fmt.Println("...")
 
return
func (r *runeRanges) writeTo(ranges *[]string) {
}
if r.hasStart {
if r.start == r.end {
*ranges = append(*ranges, fmt.Sprintf("%U", r.end))
} else {
*ranges = append(*ranges, fmt.Sprintf("%U-%U", r.start, r.end))
}
}
}
fmt.Println()
 
for _, rng := range rt.R32 {
func (r *runeRanges) String() string {
for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
ranges := r.ranges
fmt.Print(string(r))
r.writeTo(&ranges)
n++
return strings.Join(ranges, ", ")
if n == Ω {
}
fmt.Println("...")
 
return
func isValidIdentifier(identifier string) bool {
}
node, err := parser.ParseExpr(identifier)
if err != nil {
return false
}
ident, ok := node.(*ast.Ident)
return ok && ident.Name == identifier
}
 
func main() {
var validFirst runeRanges
var validFollow runeRanges
var validOnlyFollow runeRanges
 
for r := rune(0); r <= unicode.MaxRune; r++ {
first := isValidIdentifier(string([]rune{r}))
follow := isValidIdentifier(string([]rune{'_', r}))
if first {
validFirst.add(r)
}
if follow {
validFollow.add(r)
}
if follow && !first {
validOnlyFollow.add(r)
}
}
 
fmt.Println()
_, _ = fmt.Println("Valid first:", validFirst.String())
_, _ = fmt.Println("Valid follow:", validFollow.String())
_, _ = fmt.Println("Only follow:", validOnlyFollow.String())
}</lang>
{{out}}
<pre>
Valid first: U+0041-U+005A, U+005F, U+0061-U+007A, U+00AA, ..., U+00F8-U+02C1, U+02C6-U+02D1, ...
Unicode version: 7.0.0
Valid follow: U+0030-U+0039, U+0041-U+005A, U+005F, U+0061-U+007A, U+00AA, ..., U+00F8-U+02C1, ..., U+2CEB0-U+2EBE0, U+2F800-U+2FA1D
 
Only follow: U+0030-U+0039, U+0660-U+0669, U+06F0-U+06F9, U+07C0-U+07C9, ..., U+1D7CE-U+1D7FF, U+1E950-U+1E959
Underscore: _
ASCII digits: 0123456789
ASCII letters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Unicode digits: ٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९০১২৩৪৫৬৭৮৯੦੧...
Unicode letters: ªµºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñ...
</pre>