// Stat calculates statistics for all runes read from r. func (m *Main) Stat(r io.RuneReader) (Stats, error) { var stats Stats for { // Read next character. ch, sz, err := r.ReadRune() if err == io.EOF { break } else if err != nil { return stats, err } // Calculate stats. stats.TotalN++ if unicode.IsControl(ch) { stats.ControlN++ } if unicode.IsDigit(ch) { stats.DigitN++ } if unicode.IsGraphic(ch) { stats.GraphicN++ } if unicode.IsLetter(ch) { stats.LetterN++ } if unicode.IsLower(ch) { stats.LowerN++ } if unicode.IsMark(ch) { stats.MarkN++ } if unicode.IsNumber(ch) { stats.NumberN++ } if unicode.IsPrint(ch) { stats.PrintN++ } if unicode.IsPunct(ch) { stats.PunctN++ } if unicode.IsSpace(ch) { stats.SpaceN++ } if unicode.IsSymbol(ch) { stats.SymbolN++ } if unicode.IsTitle(ch) { stats.TitleN++ } if unicode.IsUpper(ch) { stats.UpperN++ } if sz > 1 { stats.MultiByteN++ } } return stats, nil }
// CharType returns a string representing the unicode type of a rune func CharType(r rune) string { switch { case unicode.IsLetter(r): return "letter" case unicode.IsSpace(r): return "space" case unicode.IsPunct(r): return "punct" case unicode.IsNumber(r): return "number" case unicode.IsSymbol(r): return "symbol" case unicode.IsMark(r): return "mark" case unicode.IsDigit(r): return "digit" case unicode.IsPrint(r): return "print" case unicode.IsControl(r): return "control" case unicode.IsGraphic(r): return "graphic" default: return "invalid" } }
// CharCount scans a *bufio.Reader and returns a map of the counts of its // Unicode character types. func CharCount(in *bufio.Reader) map[string]int { counts := make(map[string]int) // counts of Unicode character types for { r, n, err := in.ReadRune() // returns rune, nbytes, error if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "charcount: %v\n", err) os.Exit(1) } switch { case r == unicode.ReplacementChar && n == 1: counts["invalid"]++ case unicode.IsControl(r): counts["control"]++ case unicode.IsLetter(r): counts["letter"]++ case unicode.IsMark(r): counts["mark"]++ case unicode.IsNumber(r): counts["number"]++ case unicode.IsPunct(r): counts["punct"]++ case unicode.IsSpace(r): counts["space"]++ case unicode.IsSymbol(r): counts["symbol"]++ } } return counts }
func incrementCount(r rune, counts map[int]int) { switch { case unicode.IsControl(r): counts[isControl]++ case unicode.IsNumber(r): counts[isNumber]++ case unicode.IsDigit(r): counts[isDigit]++ case unicode.IsLetter(r): counts[isLetter]++ case unicode.IsMark(r): counts[isMark]++ case unicode.IsPunct(r): counts[isPunct]++ case unicode.IsSpace(r): counts[isSpace]++ case unicode.IsSymbol(r): counts[isSymbol]++ case unicode.IsPrint(r): counts[isPrint]++ case unicode.IsGraphic(r): counts[isGraphic]++ } }
func TestRune_IsIndependent(t *testing.T) { numbers := make([]rune, 0) letters := make([]rune, 0) marks := make([]rune, 0) symbols := make([]rune, 0) puncts := make([]rune, 0) others := make([]rune, 0) for _, r := range unicode.Myanmar.R16 { for c := r.Lo; c <= r.Hi; c++ { switch mr := rune(c); true { case unicode.IsLetter(mr): letters = append(letters, mr) case unicode.IsNumber(mr): numbers = append(numbers, mr) case unicode.IsMark(mr): marks = append(marks, mr) case unicode.IsPunct(mr): puncts = append(puncts, mr) case unicode.IsSymbol(mr): symbols = append(symbols, mr) default: others = append(others, mr) } } } independents := string(letters) + string(numbers) + string(puncts) + " \t\r\n" for _, consonant := range independents { if ok, _ := Rune(consonant).IsIndependent(); !ok { t.Errorf("[%U] expected result is true, but it returns false", consonant) } } }
func scanFrac(l *CommonLexer, ch rune) (stateFn, syms.SymbolID) { if unicode.IsDigit(ch) { return scanFrac, syms.NUM } if ch == '.' || unicode.IsLetter(ch) || unicode.IsNumber(ch) || unicode.IsMark(ch) { return scanIllegal, syms.ERROR } return nil, syms.NUM }
func Sanitize(r rune) rune { switch { case unicode.IsPunct(r): return ' ' case unicode.IsMark(r): return ' ' case unicode.IsSymbol(r): return ' ' } return r }
func scanHex(l *CommonLexer, ch rune) (stateFn, syms.SymbolID) { if unicode.IsDigit(ch) || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' { return scanHex, syms.HEXNUM } if ch == '.' || unicode.IsLetter(ch) || unicode.IsNumber(ch) || unicode.IsMark(ch) { return scanIllegal, syms.ERROR } return nil, syms.HEXNUM }
func main() { counts := make(map[string]int) var utflen [utf8.UTFMax + 1]int invalid := 0 in := bufio.NewReader(os.Stdin) for { r, n, err := in.ReadRune() if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "charcount: %v\n", err) os.Exit(1) } if r == unicode.ReplacementChar && n == 1 { invalid++ continue } utflen[n]++ switch { case unicode.IsLetter(r): counts["Letter"]++ case unicode.IsMark(r): counts["Mark"]++ case unicode.IsNumber(r): counts["Number"]++ case unicode.IsPunct(r): counts["Punct"]++ case unicode.IsSymbol(r): counts["Symbol"]++ case unicode.IsSpace(r): counts["Space"]++ default: counts["Other"]++ } } fmt.Printf("rune\tcount\n") for c, n := range counts { fmt.Printf("%s\t%d\n", c, n) } fmt.Print("\nlen\tcount\n") for i, n := range utflen { if i > 0 { fmt.Printf("%d\t%d\n", i, n) } } if invalid > 0 { fmt.Printf("\n%d invalid UTF-8 characters\n", invalid) } }
func main() { counts := make(map[rune]int) // counts of Unicode characters var utflen [utf8.UTFMax]int // count of lengths of UTF-8 encodings invalid := 0 // count of invalid UTF-8 characters cats := make(map[string]int) // counts of Unicode categories // In a terminal, use CTRL+Z at line start to signal EOF with ENTER. in := bufio.NewReader(os.Stdin) for { r, n, err := in.ReadRune() // returns rune, nbytes, error if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "charcount: %v\n", err) os.Exit(1) } if r == unicode.ReplacementChar && n == 1 { invalid++ continue } switch { case unicode.IsLetter(r): cats["letter"]++ case unicode.IsDigit(r): cats["digit"]++ case unicode.IsControl(r): cats["control"]++ case unicode.IsMark(r): cats["mark"]++ case unicode.IsPunct(r): cats["punct"]++ case unicode.IsSymbol(r): cats["symbol"]++ } counts[r]++ utflen[n-1]++ } fmt.Printf("rune\tcount\n") for c, n := range counts { fmt.Printf("%q\t%d\n", c, n) } fmt.Print("\nlen\tcount\n") for i, n := range utflen { fmt.Printf("%d\t%d\n", i+1, n) } fmt.Print("\ncat\tcount\n") for s, n := range cats { fmt.Printf("%v\t%d\n", s, n) } fmt.Printf("\n%d invalid UTF-8 characters\n", invalid) }
func main() { in := bufio.NewReader(os.Stdin) counts := make(map[string]int) // counts of Unicode character types var utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings invalid := 0 // count of invalid UTF-8 characters for { r, n, err := in.ReadRune() // returns rune, nbytes, error if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "charcount: %v\n", err) os.Exit(1) } if r == unicode.ReplacementChar && n == 1 { invalid++ continue } switch { case unicode.IsControl(r): counts["control"]++ case unicode.IsLetter(r): counts["letter"]++ case unicode.IsMark(r): counts["mark"]++ case unicode.IsNumber(r): counts["number"]++ case unicode.IsPunct(r): counts["punct"]++ case unicode.IsSpace(r): counts["space"]++ case unicode.IsSymbol(r): counts["symbol"]++ } utflen[n]++ } fmt.Printf("rune\tcount\n") for c, n := range counts { fmt.Printf("%q\t%d\n", c, n) } fmt.Print("\nlen\tcount\n") for i, n := range utflen { if i > 0 { fmt.Printf("%d\t%d\n", i, n) } } if invalid > 0 { fmt.Printf("\n%d invalid UTF-8 characters\n", invalid) } }
func printChars(chars map[rune]int) { keys := sortRuneKeys(chars) var p [utf8.UTFMax]byte for _, key := range keys { char := key if !unicode.IsPrint(key) || unicode.IsMark(key) { char = ' ' } var cat string for name, rng := range unicode.Categories { if unicode.In(key, rng) && len(name) > 1 { cat = name } } utf8.EncodeRune(p[:], key) fmt.Printf("%c (%-2s %U 0x%x) %d\n", char, cat, key, p, chars[key]) } }
// scanIdentifier returns the extent of the prefix of the string that // represents a valid identifier, along with the length of that prefix // in runes. // // Identifiers may contain utf8-encoded non-Latin letters, which will // cause the returned "rune length" to be shorter than the byte length // of the returned string. func scanIdentifier(s string) (string, int) { byteLen := 0 runeLen := 0 for { if byteLen >= len(s) { break } nextRune, size := utf8.DecodeRuneInString(s[byteLen:]) if !(nextRune == '_' || nextRune == '-' || nextRune == '.' || nextRune == '*' || unicode.IsNumber(nextRune) || unicode.IsLetter(nextRune) || unicode.IsMark(nextRune)) { break } // If we reach a star, it must be between periods to be part // of the same identifier. if nextRune == '*' && s[byteLen-1] != '.' { break } // If our previous character was a star, then the current must // be period. Otherwise, undo that and exit. if byteLen > 0 && s[byteLen-1] == '*' && nextRune != '.' { byteLen-- if s[byteLen-1] == '.' { byteLen-- } break } byteLen = byteLen + size runeLen = runeLen + 1 } return s[:byteLen], runeLen }
// Rewrite string to remove non-standard path characters func UnicodeSanitize(s string) string { source := []rune(s) target := make([]rune, 0, len(source)) for _, r := range source { if unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsMark(r) || r == '.' || r == '/' || r == '\\' || r == '_' || r == '-' || r == '%' || r == ' ' || r == '#' { target = append(target, r) } } return string(target) }
// UnicodeSanitize sanitizes string to be used in Hugo URL's, allowing only // a predefined set of special Unicode characters. // If RemovePathAccents configuration flag is enabled, Uniccode accents // are also removed. func UnicodeSanitize(s string) string { source := []rune(s) target := make([]rune, 0, len(source)) for _, r := range source { if unicode.IsLetter(r) || unicode.IsDigit(r) || unicode.IsMark(r) || r == '%' || r == '.' || r == '/' || r == '\\' || r == '_' || r == '-' || r == '#' || r == '+' { target = append(target, r) } } var result string if viper.GetBool("RemovePathAccents") { // remove accents - see https://blog.golang.org/normalization t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC) result, _, _ = transform.String(t, string(target)) } else { result = string(target) } return result }
func lexArticle(l *lexer) stateFn { switch r := l.next(); { case r == eof: l.emit(itemEOF) return nil case r == '{' && l.peek() == '{': l.next() l.emit(itemLeftMeta) return lexArticle case r == '}' && l.peek() == '}': l.next() l.emit(itemRightMeta) return lexArticle case r == '[' && l.peek() == '[': l.next() l.emit(itemLeftTag) return lexArticle case r == ']' && l.peek() == ']': l.next() l.emit(itemRightTag) return lexArticle case r == '\'': return lexQuote case r == '<': l.backup() return lexXML case r == '=': return lexTitle case isSpace(r): return lexSpace case unicode.IsMark(r) || unicode.IsSymbol(r) || unicode.IsPunct(r): l.emit(itemMark) return lexArticle case isAlphaNumeric(r): return lexWord } return lexArticle }
func print_rune_types(char rune) { if unicode.IsControl(char) { fmt.Println(" Control") } if unicode.IsDigit(char) { fmt.Println(" Digit") } if unicode.IsGraphic(char) { fmt.Println(" Graphic") } if unicode.IsLetter(char) { fmt.Println(" Letter") } if unicode.IsLower(char) { fmt.Println(" Lower") } if unicode.IsMark(char) { fmt.Println(" Mark") } if unicode.IsPrint(char) { fmt.Println(" Print") } if unicode.IsPunct(char) { fmt.Println(" Punct") } if unicode.IsSpace(char) { fmt.Println(" Space") } if unicode.IsSymbol(char) { fmt.Println(" Symbol") } if unicode.IsTitle(char) { fmt.Println(" Title") } if unicode.IsUpper(char) { fmt.Println(" Upper") } }
// scanIdentifier returns the extent of the prefix of the string that // represents a valid identifier, along with the length of that prefix // in runes. // // Identifiers may contain utf8-encoded non-Latin letters, which will // cause the returned "rune length" to be shorter than the byte length // of the returned string. func scanIdentifier(s string) (string, int) { byteLen := 0 runeLen := 0 for { if byteLen >= len(s) { break } nextRune, size := utf8.DecodeRuneInString(s[byteLen:]) if !(nextRune == '_' || nextRune == '-' || unicode.IsNumber(nextRune) || unicode.IsLetter(nextRune) || unicode.IsMark(nextRune)) { break } byteLen = byteLen + size runeLen = runeLen + 1 } return s[:byteLen], runeLen }
func main() { fmt.Println(unicode.IsGraphic('1')) // true: 1은 화면에 표시되는 숫자이므로 true fmt.Println(unicode.IsGraphic('a')) // true: a는 화면에 표시되는 문자이므로 true fmt.Println(unicode.IsGraphic('한')) // true: '한'은 화면에 표시되는 문자이므로 true fmt.Println(unicode.IsGraphic('漢')) // true: '漢'은 화면에 표시되는 문자이므로 true fmt.Println(unicode.IsGraphic('\n')) // false: \n 화면에 표시되는 문자가 아니므로 false fmt.Println(unicode.IsLetter('a')) // true: a는 문자이므로 true fmt.Println(unicode.IsLetter('1')) // false: 1은 문자가 아니므로 false fmt.Println(unicode.IsDigit('1')) // true: 1은 숫자이므로 true fmt.Println(unicode.IsControl('\n')) // true: \n은 제어 문자이므로 true fmt.Println(unicode.IsMark('\u17c9')) // true: \u17c9는 마크이므로 true fmt.Println(unicode.IsPrint('1')) // true: 1은 Go 언어에서 표시할 수 있으므로 true fmt.Println(unicode.IsPunct('.')) // true: .은 문장 부호이므로 true fmt.Println(unicode.IsSpace(' ')) // true: ' '는 공백이므로 true fmt.Println(unicode.IsSymbol('♥')) // true: ♥는 심볼이므로 true fmt.Println(unicode.IsUpper('A')) // true: A는 대문자이므로 true fmt.Println(unicode.IsLower('a')) // true: a는 소문자이므로 true }
func bindStringPredicates(e *Env) { e.Method("is-control", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsControl(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-digit", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsDigit(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-graphic", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsGraphic(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-letter", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsLetter(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-lower", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsLower(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-mark", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsMark(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-print", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsPrint(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-punct", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsPunct(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-space", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsSpace(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-symbol", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsSymbol(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-title", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsTitle(c) { return t.Return(False) } } return t.Return(True) }) e.Method("is-upper", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) for _, c := range s { if !unicode.IsUpper(c) { return t.Return(False) } } return t.Return(True) }) e.Method("to-lower", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) return t.Return(NewString(t, strings.ToLower(s))) }) e.Method("to-title", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) return t.Return(NewString(t, strings.ToTitle(s))) }) e.Method("to-upper", func(t *Task, args Cell) bool { s := raw(toString(Car(t.Scratch).(Binding).Self())) return t.Return(NewString(t, strings.ToUpper(s))) }) }
func isIdentifierPart(r rune) bool { return (unicode.IsLetter(r) || unicode.IsMark(r) || unicode.IsDigit(r) || unicode.IsPunct(r)) && !strings.ContainsRune("{}[]:,", r) }
func OneOrMore(definitions ...interface{}) token { tok := Compile(definitions) if tok.err != nil { return tok } instrs := make([]instruction, 0) // [tok], JMP instrs = append(instrs, tok.instructions...) instrs = append(instrs, instruction{INSTR_JUMP, 1, -int32(len(tok.instructions))}) return token{instrs, nil} } func ZeroOrMore(definitions ...interface{}) token { return Opt(OneOrMore(definitions...)) } var ( ULetter = Compile(func(r, n rune) bool { return unicode.IsLetter(r) }) UMark = Compile(func(r, n rune) bool { return unicode.IsMark(r) }) UNumber = Compile(func(r, n rune) bool { return unicode.IsNumber(r) }) USpace = Compile(func(r, n rune) bool { return unicode.IsSpace(r) }) UControl = Compile(func(r, n rune) bool { return unicode.IsControl(r) }) UPunct = Compile(func(r, n rune) bool { return unicode.IsPunct(r) }) Digit = Range('0', '9') DigitNon0 = Range('1', '9') HexDigit = Any(Range('0', '9'), Any(Range('a', 'f'), Range('A', 'F'))) )
func main() { counts := make(map[rune]int) // counts of Unicode characters var utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings invalid := 0 // count of invalid UTF-8 characters categories := map[string]int{ "letter": 0, "mark": 0, "number": 0, "punct": 0, "space": 0} counters := []func(rune){ func(r rune) { if unicode.IsLetter(r) { categories["letter"]++ } }, func(r rune) { if unicode.IsMark(r) { categories["mark"]++ } }, func(r rune) { if unicode.IsNumber(r) { categories["number"]++ } }, func(r rune) { if unicode.IsPunct(r) { categories["punct"]++ } }, func(r rune) { if unicode.IsSpace(r) { categories["space"]++ } }} in := bufio.NewReader(os.Stdin) for { r, n, err := in.ReadRune() // returns rune, nbytes, error if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "charcount: %v\n", err) os.Exit(1) } if r == unicode.ReplacementChar && n == 1 { invalid++ continue } counts[r]++ utflen[n]++ for _, counter := range counters { counter(r) } } fmt.Printf("rune\tcount\n") for c, n := range counts { fmt.Printf("%q\t%d\n", c, n) } fmt.Print("\nlen\tcount\n") for i, n := range utflen { if i > 0 { fmt.Printf("%d\t%d\n", i, n) } } fmt.Print("\ncategory count\n") for k, v := range categories { fmt.Printf("%-8s %d\n", k, v) } if invalid > 0 { fmt.Printf("\n%d invalid UTF-8 characters\n", invalid) } }
func Start() { proc0 = NewProcess(psNone, nil, nil) proc0.Scratch = Cons(NewStatus(0), proc0.Scratch) e, s := proc0.Dynamic, proc0.Lexical.Expose() e.Add(NewSymbol("$stdin"), channel(proc0, os.Stdin, nil)) e.Add(NewSymbol("$stdout"), channel(proc0, nil, os.Stdout)) e.Add(NewSymbol("$stderr"), channel(proc0, nil, os.Stderr)) if wd, err := os.Getwd(); err == nil { e.Add(NewSymbol("$cwd"), NewSymbol(wd)) } s.PrivateState("and", psAnd) s.PrivateState("block", psBlock) s.PrivateState("backtick", psBacktick) s.PrivateState("define", psDefine) s.PrivateState("dynamic", psDynamic) s.PrivateState("for", psFor) s.PrivateState("builtin", psBuiltin) s.PrivateState("if", psIf) s.PrivateState("import", psImport) s.PrivateState("source", psSource) s.PrivateState("method", psMethod) s.PrivateState("object", psObject) s.PrivateState("or", psOr) s.PrivateState("quote", psQuote) s.PrivateState("set", psSet) s.PrivateState("setenv", psSetenv) s.PrivateState("spawn", psSpawn) s.PrivateState("splice", psSplice) s.PrivateState("while", psWhile) s.PublicState("public", psPublic) s.PrivateState("background", psBackground) s.PrivateState("pipe-stdout", psPipeStdout) s.PrivateState("pipe-stderr", psPipeStderr) s.PrivateState("redirect-stdin", psRedirectStdin) s.PrivateState("redirect-stdout", psRedirectStdout) s.PrivateState("redirect-stderr", psRedirectStderr) s.PrivateState("append-stdout", psAppendStdout) s.PrivateState("append-stderr", psAppendStderr) s.PrivateState("andf", psAndf) s.PrivateState("orf", psOrf) /* Builtins. */ s.PrivateFunction("cd", func(p *Process, args Cell) bool { err, status := os.Chdir(Raw(Car(args))), 0 if err != nil { status = int(err.(*os.PathError).Error.(os.Errno)) } SetCar(p.Scratch, NewStatus(int64(status))) if wd, err := os.Getwd(); err == nil { p.Dynamic.Add(NewSymbol("$cwd"), NewSymbol(wd)) } return false }) s.PrivateFunction("debug", func(p *Process, args Cell) bool { debug(p, "debug") return false }) s.PrivateFunction("exit", func(p *Process, args Cell) bool { var status int64 = 0 a, ok := Car(args).(Atom) if ok { status = a.Status() } p.Scratch = List(NewStatus(status)) p.Stack = Null return true }) s.PublicMethod("child", func(p *Process, args Cell) bool { o := Car(p.Scratch).(*Method).Self.Expose() SetCar(p.Scratch, NewObject(NewScope(o))) return false }) s.PublicMethod("clone", func(p *Process, args Cell) bool { o := Car(p.Scratch).(*Method).Self.Expose() SetCar(p.Scratch, NewObject(o.Copy())) return false }) s.PrivateMethod("apply", func(p *Process, args Cell) bool { SetCar(p.Scratch, Car(args)) next(p) p.Scratch = Cons(nil, p.Scratch) for args = Cdr(args); args != Null; args = Cdr(args) { p.Scratch = Cons(Car(args), p.Scratch) } return true }) s.PrivateMethod("append", func(p *Process, args Cell) bool { /* * NOTE: Our append works differently than Scheme's append. * To mimic Scheme's behavior used append l1 @l2 ... @ln */ /* TODO: We should just copy this list: ... */ l := Car(args) /* TODO: ... and then set it's cdr to cdr(args). */ argv := make([]Cell, 0) for args = Cdr(args); args != Null; args = Cdr(args) { argv = append(argv, Car(args)) } SetCar(p.Scratch, Append(l, argv...)) return false }) s.PrivateMethod("car", func(p *Process, args Cell) bool { SetCar(p.Scratch, Caar(args)) return false }) s.PrivateMethod("cdr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdar(args)) return false }) s.PrivateMethod("caar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Caaar(args)) return false }) s.PrivateMethod("cadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cadar(args)) return false }) s.PrivateMethod("cdar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdaar(args)) return false }) s.PrivateMethod("cddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cddar(args)) return false }) s.PrivateMethod("caaar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Car(Caaar(args))) return false }) s.PrivateMethod("caadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Car(Cadar(args))) return false }) s.PrivateMethod("cadar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Car(Cdaar(args))) return false }) s.PrivateMethod("caddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Car(Cddar(args))) return false }) s.PrivateMethod("cdaar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdr(Caaar(args))) return false }) s.PrivateMethod("cdadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdr(Cadar(args))) return false }) s.PrivateMethod("cddar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdr(Cdaar(args))) return false }) s.PrivateMethod("cdddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdr(Cddar(args))) return false }) s.PrivateMethod("caaaar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Caar(Caaar(args))) return false }) s.PrivateMethod("caaadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Caar(Cadar(args))) return false }) s.PrivateMethod("caadar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Caar(Cdaar(args))) return false }) s.PrivateMethod("caaddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Caar(Cddar(args))) return false }) s.PrivateMethod("cadaar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cadr(Caaar(args))) return false }) s.PrivateMethod("cadadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cadr(Cadar(args))) return false }) s.PrivateMethod("caddar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cadr(Cdaar(args))) return false }) s.PrivateMethod("cadddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cadr(Cddar(args))) return false }) s.PrivateMethod("cdaaar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdar(Caaar(args))) return false }) s.PrivateMethod("cdaadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdar(Cadar(args))) return false }) s.PrivateMethod("cdadar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdar(Cdaar(args))) return false }) s.PrivateMethod("cdaddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cdar(Cddar(args))) return false }) s.PrivateMethod("cddaar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cddr(Caaar(args))) return false }) s.PrivateMethod("cddadr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cddr(Cadar(args))) return false }) s.PrivateMethod("cdddar", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cddr(Cdaar(args))) return false }) s.PrivateMethod("cddddr", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cddr(Cddar(args))) return false }) s.PrivateMethod("cons", func(p *Process, args Cell) bool { SetCar(p.Scratch, Cons(Car(args), Cadr(args))) return false }) s.PrivateMethod("eval", func(p *Process, args Cell) bool { p.ReplaceState(psEvalCommand) p.Code = Car(args) p.Scratch = Cdr(p.Scratch) return true }) s.PrivateMethod("length", func(p *Process, args Cell) bool { var l int64 = 0 switch c := Car(args); c.(type) { case *String, *Symbol: l = int64(len(Raw(c))) default: l = Length(c) } SetCar(p.Scratch, NewInteger(l)) return false }) s.PrivateMethod("is-control", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsControl(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-digit", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsDigit(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-graphic", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsGraphic(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-letter", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsLetter(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-lower", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsLower(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-mark", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsMark(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-print", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsPrint(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-punct", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsPunct(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-space", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsSpace(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-symbol", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsSymbol(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-title", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsTitle(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("is-upper", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsUpper(int(t.Int()))) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("list", func(p *Process, args Cell) bool { SetCar(p.Scratch, args) return false }) s.PrivateMethod("list-to-string", func(p *Process, args Cell) bool { s := "" for l := Car(args); l != Null; l = Cdr(l) { s = fmt.Sprintf("%s%c", s, int(Car(l).(Atom).Int())) } SetCar(p.Scratch, NewString(s)) return false }) s.PrivateMethod("list-to-symbol", func(p *Process, args Cell) bool { s := "" for l := Car(args); l != Null; l = Cdr(l) { s = fmt.Sprintf("%s%c", s, int(Car(l).(Atom).Int())) } SetCar(p.Scratch, NewSymbol(s)) return false }) s.PrivateMethod("open", func(p *Process, args Cell) bool { name := Raw(Car(args)) mode := Raw(Cadr(args)) flags := os.O_CREATE if strings.IndexAny(mode, "r") != -1 { flags |= os.O_WRONLY } else if strings.IndexAny(mode, "aw") != -1 { flags |= os.O_RDONLY } else { flags |= os.O_RDWR } if strings.IndexAny(mode, "a") != -1 { flags |= os.O_APPEND } f, err := os.OpenFile(name, flags, 0666) if err != nil { panic(err) } SetCar(p.Scratch, channel(p, f, f)) return false }) s.PrivateMethod("reverse", func(p *Process, args Cell) bool { SetCar(p.Scratch, Reverse(Car(args))) return false }) s.PrivateMethod("set-car", func(p *Process, args Cell) bool { SetCar(Car(args), Cadr(args)) SetCar(p.Scratch, Cadr(args)) return false }) s.PrivateMethod("set-cdr", func(p *Process, args Cell) bool { SetCdr(Car(args), Cadr(args)) SetCar(p.Scratch, Cadr(args)) return false }) s.PrivateMethod("sprintf", func(p *Process, args Cell) bool { f := Raw(Car(args)) argv := []interface{}{} for l := Cdr(args); l != Null; l = Cdr(l) { switch t := Car(l).(type) { case *Boolean: argv = append(argv, *t) case *Integer: argv = append(argv, *t) case *Status: argv = append(argv, *t) case *Float: argv = append(argv, *t) default: argv = append(argv, Raw(t)) } } s := fmt.Sprintf(f, argv...) SetCar(p.Scratch, NewString(s)) return false }) s.PrivateMethod("substring", func(p *Process, args Cell) bool { var r Cell s := []int(Raw(Car(args))) start := int(Cadr(args).(Atom).Int()) end := len(s) if Cddr(args) != Null { end = int(Caddr(args).(Atom).Int()) } switch t := Car(args).(type) { case *String: r = NewString(string(s[start:end])) case *Symbol: r = NewSymbol(string(s[start:end])) default: r = Null } SetCar(p.Scratch, r) return false }) s.PrivateMethod("text-to-list", func(p *Process, args Cell) bool { l := Null for _, char := range Raw(Car(args)) { l = Cons(NewInteger(int64(char)), l) } SetCar(p.Scratch, Reverse(l)) return false }) s.PrivateMethod("to-lower", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewInteger(int64(unicode.ToLower(int(t.Int())))) case *String: r = NewString(strings.ToLower(Raw(t))) case *Symbol: r = NewSymbol(strings.ToLower(Raw(t))) default: r = NewInteger(0) } SetCar(p.Scratch, r) return false }) s.PrivateMethod("to-title", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewInteger(int64(unicode.ToTitle(int(t.Int())))) case *String: r = NewString(strings.ToTitle(Raw(t))) case *Symbol: r = NewSymbol(strings.ToTitle(Raw(t))) default: r = NewInteger(0) } SetCar(p.Scratch, r) return false }) s.PrivateMethod("to-upper", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewInteger(int64(unicode.ToUpper(int(t.Int())))) case *String: r = NewString(strings.ToUpper(Raw(t))) case *Symbol: r = NewSymbol(strings.ToUpper(Raw(t))) default: r = NewInteger(0) } SetCar(p.Scratch, r) return false }) /* Predicates. */ s.PrivateMethod("is-atom", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewBoolean(IsAtom(Car(args)))) return false }) s.PrivateMethod("is-boolean", func(p *Process, args Cell) bool { _, ok := Car(args).(*Boolean) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-channel", func(p *Process, args Cell) bool { o, ok := Car(args).(Interface) if ok { ok = false c := Resolve(o.Expose(), nil, NewSymbol("guts")) if c != nil { _, ok = c.GetValue().(*Channel) } } SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-cons", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewBoolean(IsCons(Car(args)))) return false }) s.PrivateMethod("is-float", func(p *Process, args Cell) bool { _, ok := Car(args).(*Float) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-integer", func(p *Process, args Cell) bool { _, ok := Car(args).(*Integer) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-list", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewBoolean(IsList(Car(args)))) return false }) s.PrivateMethod("is-method", func(p *Process, args Cell) bool { _, ok := Car(args).(*Method) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-null", func(p *Process, args Cell) bool { ok := Car(args) == Null SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-number", func(p *Process, args Cell) bool { _, ok := Car(args).(Number) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-object", func(p *Process, args Cell) bool { _, ok := Car(args).(Interface) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-status", func(p *Process, args Cell) bool { _, ok := Car(args).(*Status) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-string", func(p *Process, args Cell) bool { _, ok := Car(args).(*String) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-symbol", func(p *Process, args Cell) bool { _, ok := Car(args).(*Symbol) SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("is-text", func(p *Process, args Cell) bool { _, ok := Car(args).(*Symbol) if !ok { _, ok = Car(args).(*String) } SetCar(p.Scratch, NewBoolean(ok)) return false }) /* Generators. */ s.PrivateMethod("boolean", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewBoolean(Car(args).Bool())) return false }) s.PrivateMethod("channel", func(p *Process, args Cell) bool { SetCar(p.Scratch, channel(p, nil, nil)) return false }) s.PrivateMethod("float", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewFloat(Car(args).(Atom).Float())) return false }) s.PrivateMethod("integer", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewInteger(Car(args).(Atom).Int())) return false }) s.PrivateMethod("status", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewStatus(Car(args).(Atom).Status())) return false }) s.PrivateMethod("string", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewString(Car(args).String())) return false }) s.PrivateMethod("symbol", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewSymbol(Raw(Car(args)))) return false }) /* Relational. */ s.PrivateMethod("eq", func(p *Process, args Cell) bool { prev := Car(args) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args) if !prev.Equal(curr) { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("ge", func(p *Process, args Cell) bool { prev := Car(args).(Atom) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if prev.Less(curr) { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("gt", func(p *Process, args Cell) bool { prev := Car(args).(Atom) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if !prev.Greater(curr) { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("is", func(p *Process, args Cell) bool { prev := Car(args) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args) if prev != curr { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("le", func(p *Process, args Cell) bool { prev := Car(args).(Atom) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if prev.Greater(curr) { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("lt", func(p *Process, args Cell) bool { prev := Car(args).(Atom) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if !prev.Less(curr) { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("match", func(p *Process, args Cell) bool { pattern := Raw(Car(args)) text := Raw(Cadr(args)) ok, err := path.Match(pattern, text) if err != nil { panic(err) } SetCar(p.Scratch, NewBoolean(ok)) return false }) s.PrivateMethod("ne", func(p *Process, args Cell) bool { /* * This should really check to make sure no arguments are equal. * Currently it only checks whether adjacent pairs are not equal. */ prev := Car(args) SetCar(p.Scratch, False) for Cdr(args) != Null { args = Cdr(args) curr := Car(args) if prev.Equal(curr) { return false } prev = curr } SetCar(p.Scratch, True) return false }) s.PrivateMethod("not", func(p *Process, args Cell) bool { SetCar(p.Scratch, NewBoolean(!Car(args).Bool())) return false }) /* Arithmetic. */ s.PrivateMethod("add", func(p *Process, args Cell) bool { acc := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) acc = acc.Add(Car(args)) } SetCar(p.Scratch, acc) return false }) s.PrivateMethod("sub", func(p *Process, args Cell) bool { acc := Car(args).(Number) for Cdr(args) != Null { args = Cdr(args) acc = acc.Subtract(Car(args)) } SetCar(p.Scratch, acc) return false }) s.PrivateMethod("div", func(p *Process, args Cell) bool { acc := Car(args).(Number) for Cdr(args) != Null { args = Cdr(args) acc = acc.Divide(Car(args)) } SetCar(p.Scratch, acc) return false }) s.PrivateMethod("mod", func(p *Process, args Cell) bool { acc := Car(args).(Number) for Cdr(args) != Null { args = Cdr(args) acc = acc.Modulo(Car(args)) } SetCar(p.Scratch, acc) return false }) s.PrivateMethod("mul", func(p *Process, args Cell) bool { acc := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) acc = acc.Multiply(Car(args)) } SetCar(p.Scratch, acc) return false }) e.Add(NewSymbol("$$"), NewInteger(int64(os.Getpid()))) /* Command-line arguments */ args := Null if len(os.Args) > 1 { e.Add(NewSymbol("$0"), NewSymbol(os.Args[1])) for i, v := range os.Args[2:] { e.Add(NewSymbol("$"+strconv.Itoa(i+1)), NewSymbol(v)) } for i := len(os.Args) - 1; i > 1; i-- { args = Cons(NewSymbol(os.Args[i]), args) } } else { e.Add(NewSymbol("$0"), NewSymbol(os.Args[0])) } e.Add(NewSymbol("$args"), args) /* Environment variables. */ for _, s := range os.Environ() { kv := strings.SplitN(s, "=", 2) e.Add(NewSymbol("$"+kv[0]), NewSymbol(kv[1])) } Parse(bufio.NewReader(strings.NewReader(` define echo: builtin: $stdout::write @$args define expand: builtin: return $args define printf: method: echo: sprintf (car $args) @(cdr $args) define read: builtin: $stdin::read define readline: builtin: $stdin::readline define write: method: $stdout::write @$args define list-tail: method k x { if k { list-tail (sub k 1): cdr x } else { return x } } define list-ref: method k x: car: list-tail k x `)), Evaluate) /* Read and execute rc script if it exists. */ rc := filepath.Join(os.Getenv("HOME"), ".ohrc") if _, err := os.Stat(rc); err == nil { proc0.NewState(psEvalCommand) proc0.Code = List(NewSymbol("source"), NewSymbol(rc)) run(proc0) proc0.Scratch = Cdr(proc0.Scratch) } }
// verifyProperties that properties of the runes that are relied upon in the // implementation. Each property is marked with an identifier that is referred // to in the places where it is used. func verifyProperties(chars []runeInfo) { for i, c := range chars { r := rune(i) // Rune properties. // A.1: modifier never changes on lowercase. [ltLower] if c.CCC > 0 && unicode.ToLower(r) != r { log.Fatalf("%U: non-starter changes when lowercased", r) } // A.2: properties of decompositions starting with I or J. [ltLower] d := norm.NFD.PropertiesString(string(r)).Decomposition() if len(d) > 0 { if d[0] == 'I' || d[0] == 'J' { // A.2.1: we expect at least an ASCII character and a modifier. if len(d) < 3 { log.Fatalf("%U: length of decomposition was %d; want >= 3", r, len(d)) } // All subsequent runes are modifiers and all have the same CCC. runes := []rune(string(d[1:])) ccc := chars[runes[0]].CCC for _, mr := range runes[1:] { mc := chars[mr] // A.2.2: all modifiers have a CCC of Above or less. if ccc == 0 || ccc > above { log.Fatalf("%U: CCC of successive rune (%U) was %d; want (0,230]", r, mr, ccc) } // A.2.3: a sequence of modifiers all have the same CCC. if mc.CCC != ccc { log.Fatalf("%U: CCC of follow-up modifier (%U) was %d; want %d", r, mr, mc.CCC, ccc) } // A.2.4: for each trailing r, r in [0x300, 0x311] <=> CCC == Above. if (ccc == above) != (0x300 <= mr && mr <= 0x311) { log.Fatalf("%U: modifier %U in [U+0300, U+0311] != ccc(%U) == 230", r, mr, mr) } if i += len(string(mr)); i >= len(d) { break } } } } // A.3: no U+0307 in decomposition of Soft-Dotted rune. [ltUpper] if unicode.Is(unicode.Soft_Dotted, r) && strings.Contains(string(d), "\u0307") { log.Fatalf("%U: decomposition of soft-dotted rune may not contain U+0307", r) } // A.4: only rune U+0345 may be of CCC Iota_Subscript. [elUpper] if c.CCC == iotaSubscript && r != 0x0345 { log.Fatalf("%U: only rune U+0345 may have CCC Iota_Subscript", r) } // A.5: soft-dotted runes do not have exceptions. if c.SoftDotted && c.entry&exceptionBit != 0 { log.Fatalf("%U: soft-dotted has exception", r) } // A.6: Greek decomposition. [elUpper] if unicode.Is(unicode.Greek, r) { if b := norm.NFD.PropertiesString(string(r)).Decomposition(); b != nil { runes := []rune(string(b)) // A.6.1: If a Greek rune decomposes and the first rune of the // decomposition is greater than U+00FF, the rune is always // great and not a modifier. if f := runes[0]; unicode.IsMark(f) || f > 0xFF && !unicode.Is(unicode.Greek, f) { log.Fatalf("%U: expeced first rune of Greek decomposition to be letter, found %U", r, f) } // A.6.2: Any follow-up rune in a Greek decomposition is a // modifier of which the first should be gobbled in // decomposition. for _, m := range runes[1:] { switch m { case 0x0313, 0x0314, 0x0301, 0x0300, 0x0306, 0x0342, 0x0308, 0x0304, 0x345: default: log.Fatalf("%U: modifier %U is outside of expeced Greek modifier set", r, m) } } } } // Breaking properties. // B.1: all runes with CCC > 0 are of break type Extend. if c.CCC > 0 && c.BreakType != "Extend" { log.Fatalf("%U: CCC == %d, but got break type %s; want Extend", r, c.CCC, c.BreakType) } // B.2: all cased runes with c.CCC == 0 are of break type ALetter. if c.CCC == 0 && c.Cased && c.BreakType != "ALetter" { log.Fatalf("%U: cased, but got break type %s; want ALetter", r, c.BreakType) } // B.3: letter category. if c.CCC == 0 && c.BreakCat != breakBreak && !c.CaseIgnorable { if c.BreakCat != breakLetter { log.Fatalf("%U: check for letter break type gave %d; want %d", r, c.BreakCat, breakLetter) } } } }
func scanIllegal(l *CommonLexer, ch rune) (stateFn, syms.SymbolID) { if unicode.IsLetter(ch) || unicode.IsNumber(ch) || unicode.IsMark(ch) { return scanIllegal, syms.ERROR } return nil, syms.ERROR }
func isIdentMiddle(ch rune) bool { return unicode.IsLetter(ch) || unicode.IsNumber(ch) || unicode.IsMark(ch) || ch == '_' }
func main() { counts := make(map[rune]int) // counts of Unicode characters classfication := make(map[string]int) // counts of Unicode classification var utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings invalid := 0 // count of invalid UTF-8 characters in := bufio.NewReader(os.Stdin) for { r, n, err := in.ReadRune() // returns rune, nbytes, error if err == io.EOF { break } if err != nil { fmt.Fprintf(os.Stderr, "charcount: %v\n", err) os.Exit(1) } if r == unicode.ReplacementChar && n == 1 { invalid++ continue } if unicode.IsControl(r) { classfication["Control"]++ } if unicode.IsDigit(r) { classfication["Digit"]++ } if unicode.IsGraphic(r) { classfication["Graphic"]++ } if unicode.IsLetter(r) { classfication["Letter"]++ } if unicode.IsLower(r) { classfication["Lower"]++ } if unicode.IsMark(r) { classfication["Mark"]++ } if unicode.IsNumber(r) { classfication["Number"]++ } if unicode.IsPrint(r) { classfication["Print"]++ } if unicode.IsPunct(r) { classfication["Punct"]++ } if unicode.IsSpace(r) { classfication["Space"]++ } if unicode.IsSymbol(r) { classfication["Symbol"]++ } if unicode.IsTitle(r) { classfication["Title"]++ } if unicode.IsUpper(r) { classfication["Upper"]++ } counts[r]++ utflen[n]++ } fmt.Printf("rune\tcount\n") for c, n := range counts { fmt.Printf("%q\t%d\n", c, n) } fmt.Print("\nlen\tcount\n") for i, n := range utflen { if i > 0 { fmt.Printf("%d\t%d\n", i, n) } } fmt.Print("\nclassification\tcount\n") for cls, n := range classfication { fmt.Printf("%s\t%d\n", cls, n) } if invalid > 0 { fmt.Printf("\n%d invalid UTF-8 characters\n", invalid) } }
func newViewport(driver *driver, width, height int, title string, fullscreen bool) *viewport { v := &viewport{ fullscreen: fullscreen, scaling: 1, title: title, } glfw.DefaultWindowHints() glfw.WindowHint(glfw.Samples, 4) var monitor *glfw.Monitor if fullscreen { monitor = glfw.GetPrimaryMonitor() if width == 0 || height == 0 { vm := monitor.GetVideoMode() width, height = vm.Width, vm.Height } } wnd, err := glfw.CreateWindow(width, height, v.title, monitor, nil) if err != nil { panic(err) } width, height = wnd.GetSize() // At this time, width and height serve as a "hint" for glfw.CreateWindow, so get actual values from window. wnd.MakeContextCurrent() v.context = newContext() cursorPoint := func(x, y float64) math.Point { // HACK: xpos is off by 1 and ypos is off by 3 on OSX. // Compensate until real fix is found. x -= 1.0 y -= 3.0 return math.Point{X: int(x), Y: int(y)}.ScaleS(1 / v.scaling) } wnd.SetCloseCallback(func(*glfw.Window) { v.Close() }) wnd.SetPosCallback(func(w *glfw.Window, x, y int) { v.Lock() v.position = math.NewPoint(x, y) v.Unlock() }) wnd.SetSizeCallback(func(_ *glfw.Window, w, h int) { v.Lock() v.sizeDipsUnscaled = math.Size{W: w, H: h} v.sizeDips = v.sizeDipsUnscaled.ScaleS(1 / v.scaling) v.Unlock() v.onResize.Fire() }) wnd.SetFramebufferSizeCallback(func(_ *glfw.Window, w, h int) { v.Lock() v.sizePixels = math.Size{W: w, H: h} v.Unlock() gl.Viewport(0, 0, w, h) gl.ClearColor(kClearColorR, kClearColorG, kClearColorB, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) }) wnd.SetCursorPosCallback(func(w *glfw.Window, x, y float64) { p := cursorPoint(w.GetCursorPos()) v.Lock() if v.pendingMouseMoveEvent == nil { v.pendingMouseMoveEvent = &gxui.MouseEvent{} driver.Call(func() { v.Lock() ev := *v.pendingMouseMoveEvent v.pendingMouseMoveEvent = nil v.Unlock() v.onMouseMove.Fire(ev) }) } v.pendingMouseMoveEvent.Point = p v.pendingMouseMoveEvent.State = getMouseState(w) v.Unlock() }) wnd.SetCursorEnterCallback(func(w *glfw.Window, entered bool) { p := cursorPoint(w.GetCursorPos()) ev := gxui.MouseEvent{ Point: p, } ev.State = getMouseState(w) if entered { v.onMouseEnter.Fire(ev) } else { v.onMouseExit.Fire(ev) } }) wnd.SetScrollCallback(func(w *glfw.Window, xoff, yoff float64) { p := cursorPoint(w.GetCursorPos()) v.Lock() if v.pendingMouseScrollEvent == nil { v.pendingMouseScrollEvent = &gxui.MouseEvent{} driver.Call(func() { v.Lock() ev := *v.pendingMouseScrollEvent v.pendingMouseScrollEvent = nil ev.ScrollX, ev.ScrollY = int(v.scrollAccumX), int(v.scrollAccumY) if ev.ScrollX != 0 || ev.ScrollY != 0 { v.scrollAccumX -= float64(ev.ScrollX) v.scrollAccumY -= float64(ev.ScrollY) v.Unlock() v.onMouseScroll.Fire(ev) } else { v.Unlock() } }) } v.pendingMouseScrollEvent.Point = p v.scrollAccumX += xoff * platform.ScrollSpeed v.scrollAccumY += yoff * platform.ScrollSpeed v.pendingMouseScrollEvent.State = getMouseState(w) v.Unlock() }) wnd.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { p := cursorPoint(w.GetCursorPos()) ev := gxui.MouseEvent{ Point: p, Modifier: translateKeyboardModifier(mod), } ev.Button = translateMouseButton(button) ev.State = getMouseState(w) if action == glfw.Press { v.onMouseDown.Fire(ev) } else { v.onMouseUp.Fire(ev) } }) wnd.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { ev := gxui.KeyboardEvent{ Key: translateKeyboardKey(key), Modifier: translateKeyboardModifier(mods), } switch action { case glfw.Press: v.onKeyDown.Fire(ev) case glfw.Release: v.onKeyUp.Fire(ev) case glfw.Repeat: v.onKeyRepeat.Fire(ev) } }) wnd.SetCharModsCallback(func(w *glfw.Window, char rune, mods glfw.ModifierKey) { if !unicode.IsControl(char) && !unicode.IsGraphic(char) && !unicode.IsLetter(char) && !unicode.IsMark(char) && !unicode.IsNumber(char) && !unicode.IsPunct(char) && !unicode.IsSpace(char) && !unicode.IsSymbol(char) { return // Weird unicode character. Ignore } ev := gxui.KeyStrokeEvent{ Character: char, Modifier: translateKeyboardModifier(mods), } v.onKeyStroke.Fire(ev) }) wnd.SetRefreshCallback(func(w *glfw.Window) { if v.canvas != nil { v.render() } }) fw, fh := wnd.GetFramebufferSize() posX, posY := wnd.GetPos() // Pre-multiplied alpha blending gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.BLEND) gl.Enable(gl.SCISSOR_TEST) gl.Viewport(0, 0, fw, fh) gl.Scissor(0, 0, int32(fw), int32(fh)) gl.ClearColor(kClearColorR, kClearColorG, kClearColorB, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) wnd.SwapBuffers() v.window = wnd v.driver = driver v.onClose = driver.createAppEvent(func() {}) v.onResize = driver.createAppEvent(func() {}) v.onMouseMove = gxui.CreateEvent(func(gxui.MouseEvent) {}) v.onMouseEnter = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseExit = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseDown = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseUp = driver.createAppEvent(func(gxui.MouseEvent) {}) v.onMouseScroll = gxui.CreateEvent(func(gxui.MouseEvent) {}) v.onKeyDown = driver.createAppEvent(func(gxui.KeyboardEvent) {}) v.onKeyUp = driver.createAppEvent(func(gxui.KeyboardEvent) {}) v.onKeyRepeat = driver.createAppEvent(func(gxui.KeyboardEvent) {}) v.onKeyStroke = driver.createAppEvent(func(gxui.KeyStrokeEvent) {}) v.onDestroy = driver.createDriverEvent(func() {}) v.sizeDipsUnscaled = math.Size{W: width, H: height} v.sizeDips = v.sizeDipsUnscaled.ScaleS(1 / v.scaling) v.sizePixels = math.Size{W: fw, H: fh} v.position = math.Point{X: posX, Y: posY} return v }
// Functions starting with "Is" can be used to inspect which table of range a // rune belongs to. Note that runes may fit into more than one range. func Example_is() { // constant with mixed type runes const mixed = "\b5Ὂg̀9! ℃ᾭG" for _, c := range mixed { fmt.Printf("For %q:\n", c) if unicode.IsControl(c) { fmt.Println("\tis control rune") } if unicode.IsDigit(c) { fmt.Println("\tis digit rune") } if unicode.IsGraphic(c) { fmt.Println("\tis graphic rune") } if unicode.IsLetter(c) { fmt.Println("\tis letter rune") } if unicode.IsLower(c) { fmt.Println("\tis lower case rune") } if unicode.IsMark(c) { fmt.Println("\tis mark rune") } if unicode.IsNumber(c) { fmt.Println("\tis number rune") } if unicode.IsPrint(c) { fmt.Println("\tis printable rune") } if !unicode.IsPrint(c) { fmt.Println("\tis not printable rune") } if unicode.IsPunct(c) { fmt.Println("\tis punct rune") } if unicode.IsSpace(c) { fmt.Println("\tis space rune") } if unicode.IsSymbol(c) { fmt.Println("\tis symbol rune") } if unicode.IsTitle(c) { fmt.Println("\tis title case rune") } if unicode.IsUpper(c) { fmt.Println("\tis upper case rune") } } // Output: // For '\b': // is control rune // is not printable rune // For '5': // is digit rune // is graphic rune // is number rune // is printable rune // For 'Ὂ': // is graphic rune // is letter rune // is printable rune // is upper case rune // For 'g': // is graphic rune // is letter rune // is lower case rune // is printable rune // For '̀': // is graphic rune // is mark rune // is printable rune // For '9': // is digit rune // is graphic rune // is number rune // is printable rune // For '!': // is graphic rune // is printable rune // is punct rune // For ' ': // is graphic rune // is printable rune // is space rune // For '℃': // is graphic rune // is printable rune // is symbol rune // For 'ᾭ': // is graphic rune // is letter rune // is printable rune // is title case rune // For 'G': // is graphic rune // is letter rune // is printable rune // is upper case rune }