Beispiel #1
0
// 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
}
Beispiel #2
0
// 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"
	}
}
Beispiel #3
0
// 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
}
Beispiel #4
0
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]++
	}

}
Beispiel #5
0
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)
		}
	}
}
Beispiel #6
0
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
}
Beispiel #7
0
func Sanitize(r rune) rune {
	switch {
	case unicode.IsPunct(r):
		return ' '
	case unicode.IsMark(r):
		return ' '
	case unicode.IsSymbol(r):
		return ' '
	}
	return r
}
Beispiel #8
0
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
}
Beispiel #9
0
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)
	}
}
Beispiel #10
0
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)
}
Beispiel #11
0
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)
	}
}
Beispiel #12
0
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])
	}
}
Beispiel #13
0
// 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
}
Beispiel #14
0
// 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)
}
Beispiel #15
0
// 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
}
Beispiel #16
0
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
}
Beispiel #17
0
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")
	}
}
Beispiel #18
0
// 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
}
Beispiel #19
0
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
}
Beispiel #20
0
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)))
	})
}
Beispiel #21
0
func isIdentifierPart(r rune) bool {
	return (unicode.IsLetter(r) || unicode.IsMark(r) || unicode.IsDigit(r) ||
		unicode.IsPunct(r)) && !strings.ContainsRune("{}[]:,", r)
}
Beispiel #22
0
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')))
)
Beispiel #23
0
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)
	}
}
Beispiel #24
0
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)
	}
}
Beispiel #25
0
// 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)
			}
		}
	}
}
Beispiel #26
0
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
}
Beispiel #27
0
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)
	}
}
Beispiel #29
0
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
}
Beispiel #30
0
// 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
}