// 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 }
//IsTitled reports wheter s is in Title Case. func IsTitled(s string) bool { for i, r := range s { if i == 0 { if !(unicode.IsUpper(r) || unicode.IsTitle(r)) { return false } } else { if !unicode.IsLower(r) { return false } } } return true }
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") } }
func propCased(r rune) bool { return propLower(r) || propUpper(r) || unicode.IsTitle(r) }
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 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) } }
func verifyCased(r rune) bool { return verifyLower(r) || verifyUpper(r) || unicode.IsTitle(r) }
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 Text(b []byte, stripSpeechmarks bool) []byte { // Convert to slice of runes n := len(b) if n == 0 { return b } para := make([][][]rune, 0, 1) sent := make([][]rune, 0, 3) word := make([]rune, 0, 3) var r, lastr rune var i, w int var ok bool for i = 0; i < n; i += w { r, w = utf8.DecodeRune(b[i:]) switch r { // New word case ' ', 9: if len(word) == 0 { continue } sent = append(sent, word) word = make([]rune, 0, 3) continue // New line case 10, 13: ok = false switch lastr { case '.', '!', '?': ok = true } if ok { if len(sent) == 0 { continue } if len(word) > 0 { sent = append(sent, word) word = make([]rune, 0, 3) } para = append(para, sent) sent = make([][]rune, 0, 3) } else { if len(word) == 0 { continue } sent = append(sent, word) word = make([]rune, 0, 3) } continue // Normalize aprostrophes case '‘', '’': r = 39 // Normalize speechmarks, or stripSpeechmarks case '“', '”', '"': if stripSpeechmarks { continue } r = '"' // em-dash should always be its own word case '—': if len(word) > 0 { sent = append(sent, word) } sent = append(sent, []rune{'—'}) word = make([]rune, 0, 3) continue } if r > 127 { switch r { case 'Æ': r = 'e' case 'æ': r = 'e' case 'Œ': word = append(word, 'o') r = 'e' case 'œ': word = append(word, 'o') r = 'e' case 'fi': word = append(word, 'f') r = 'i' } } // Add rune word = append(word, r) lastr = r } if len(word) > 0 { sent = append(sent, word) } if len(sent) > 0 { para = append(para, sent) } numpara := len(para) var allcaps, firstcap, othercap, anyletter, puncbefore bool var last, i2, on int for i = 0; i < numpara; i++ { sent = para[i] puncbefore = true // Loop though each word and correct casing for on, word = range sent { // First check for lost punctuation in front of the word ok = true for i2, r = range word { if unicode.IsLetter(r) || unicode.IsNumber(r) { break } switch r { case ',', '.', ':', ';', '!': ok = false } } if !ok { if on > 0 && !puncbefore && unicode.IsLetter(r) && (unicode.IsUpper(r) || unicode.IsTitle(r)) { sent[on-1] = append(sent[on-1], word[0:i2]...) puncbefore = true } sent[on] = word[i2:] word = word[i2:] } // Calculate the casing type of the word r = word[0] othercap = false if unicode.IsLetter(r) { anyletter = true if unicode.IsUpper(r) || unicode.IsTitle(r) { allcaps = true firstcap = true } else { allcaps = false firstcap = false } } else { anyletter = false allcaps = false firstcap = false } for _, r = range word[1:] { if unicode.IsLetter(r) { anyletter = true if unicode.IsUpper(r) || unicode.IsTitle(r) { othercap = true } else { allcaps = false } } } if anyletter { if puncbefore { if !firstcap { upperfirst(word) } else { if allcaps { if !isException(word) { upperfirst(word) } } else { if othercap { upperfirst(word) } } } } else { if othercap { if allcaps { if !isException(word) { lowercase(word) } } else { lowercase(word) } } } } puncbefore = false for i2 = len(word) - 1; i2 >= 0; i2-- { r = r if unicode.IsPunct(r) { switch r { case '.', '?', '!': puncbefore = true break } } else { break } } } // Ensure last character is suitable word = sent[len(sent)-1] last = len(word) - 1 ok = false r = word[last] switch r { case '.', '!', '?', ')', '"', 39: ok = true } if !ok { if !unicode.IsPunct(r) { sent[len(sent)-1] = append(sent[len(sent)-1], '.') } else { for i2 = last - 1; i2 >= 0; i2-- { r = word[i2] switch r { case '.', '!', '?', ')', '"', 39: sent[len(sent)-1] = sent[len(sent)-1][0 : i2+1] break } if !unicode.IsPunct(r) { word[i2+1] = '.' sent[len(sent)-1] = sent[len(sent)-1][0 : i2+2] break } } } } } // Write it back buf := bytes.NewBuffer(make([]byte, 0, 20)) for i, sent = range para { if i > 0 { buf.WriteByte(10) if len(sent) > 10 { buf.WriteByte(10) } } for i2, word = range sent { if i2 > 0 { buf.WriteByte(' ') } for _, r = range word { buf.WriteRune(r) } } } return buf.Bytes() }
// 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 }
func Start(i bool) { interactive = i irq = make(chan os.Signal, 1) signal.Notify(irq, syscall.SIGINT) proc0 = NewProcess(psEvalTopBlock, nil, nil) block0 = Cons(nil, Null) proc0.Code = block0 proc0.Scratch = Cons(NewStatus(0), proc0.Scratch) e, s := proc0.Dynamic, proc0.Lexical.Expose() e.Define(NewSymbol("False"), False) e.Define(NewSymbol("True"), True) e.Define(NewSymbol("$stdin"), channel(proc0, os.Stdin, nil, -1)) e.Define(NewSymbol("$stdout"), channel(proc0, nil, os.Stdout, -1)) e.Define(NewSymbol("$stderr"), channel(proc0, nil, os.Stderr, -1)) if wd, err := os.Getwd(); err == nil { e.Define(NewSymbol("$cwd"), NewSymbol(wd)) } s.DefineState("block", psBlock) s.DefineState("builtin", psBuiltin) s.DefineState("define", psDefine) s.DefineState("dynamic", psDynamic) s.DefineState("if", psIf) s.DefineState("method", psMethod) s.DefineState("set", psSet) s.DefineState("setenv", psSetenv) s.DefineState("spawn", psSpawn) s.DefineState("splice", psSplice) s.DefineState("syntax", psSyntax) s.DefineState("while", psWhile) s.PublicState("public", psPublic) /* Builtins. */ s.DefineFunction("cd", func(p *Process, args Cell) bool { err := os.Chdir(Raw(Car(args))) status := 0 if err != nil { status = 1 } if wd, err := os.Getwd(); err == nil { p.Dynamic.Define(NewSymbol("$cwd"), NewSymbol(wd)) } return p.Return(NewStatus(int64(status))) }) s.DefineFunction("debug", func(p *Process, args Cell) bool { debug(p, "debug") return false }) s.DefineFunction("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.DefineFunction("module", func(p *Process, args Cell) bool { str, err := module(Raw(Car(args))) if err != nil { return p.Return(Null) } sym := NewSymbol(str) c := Resolve(p.Lexical, p.Dynamic, sym) if c == nil { return p.Return(sym) } return p.Return(c.GetValue()) }) s.PublicMethod("child", func(p *Process, args Cell) bool { o := Car(p.Scratch).(*Applicative).Self.Expose() return p.Return(NewObject(NewLexicalScope(o))) }) s.PublicMethod("clone", func(p *Process, args Cell) bool { o := Car(p.Scratch).(*Applicative).Self.Expose() return p.Return(NewObject(o.Copy())) }) s.PublicMethod("exists", func(p *Process, args Cell) bool { l := Car(p.Scratch).(*Applicative).Self c := Resolve(l, p.Dynamic, NewSymbol(Raw(Car(args)))) return p.Return(NewBoolean(c != nil)) }) s.PublicMethod("unset", func(p *Process, args Cell) bool { l := Car(p.Scratch).(*Applicative).Self r := l.Remove(NewSymbol(Raw(Car(args)))) return p.Return(NewBoolean(r)) }) s.DefineMethod("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)) } return p.Return(Append(l, argv...)) }) s.DefineMethod("apply", func(p *Process, args Cell) bool { SetCar(p.Scratch, Car(args)) head(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.DefineMethod("car", func(p *Process, args Cell) bool { return p.Return(Caar(args)) }) s.DefineMethod("cdr", func(p *Process, args Cell) bool { return p.Return(Cdar(args)) }) s.DefineMethod("cons", func(p *Process, args Cell) bool { return p.Return(Cons(Car(args), Cadr(args))) }) s.PublicMethod("eval", func(p *Process, args Cell) bool { scope := Car(p.Scratch).(*Applicative).Self.Expose() p.RemoveState() if p.Lexical != scope { p.NewState(SaveLexical) p.Lexical = scope } p.NewState(psEvalElement) p.Code = Car(args) p.Scratch = Cdr(p.Scratch) return true }) s.DefineMethod("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) } return p.Return(NewInteger(l)) }) s.DefineMethod("list", func(p *Process, args Cell) bool { return p.Return(args) }) s.DefineMethod("open", func(p *Process, args Cell) bool { name := Raw(Car(args)) mode := Raw(Cadr(args)) flags := 0 if strings.IndexAny(mode, "-") == -1 { flags = os.O_CREATE } read := false if strings.IndexAny(mode, "r") != -1 { read = true } write := false if strings.IndexAny(mode, "w") != -1 { write = true if strings.IndexAny(mode, "a") == -1 { flags |= os.O_TRUNC } } if strings.IndexAny(mode, "a") != -1 { write = true flags |= os.O_APPEND } if read == write { read = true write = true flags |= os.O_RDWR } else if write { flags |= os.O_WRONLY } f, err := os.OpenFile(name, flags, 0666) if err != nil { panic(err) } r := f if !read { r = nil } w := f if !write { w = nil } return p.Return(channel(p, r, w, -1)) }) s.DefineMethod("reverse", func(p *Process, args Cell) bool { return p.Return(Reverse(Car(args))) }) s.DefineMethod("set-car", func(p *Process, args Cell) bool { SetCar(Car(args), Cadr(args)) return p.Return(Cadr(args)) }) s.DefineMethod("set-cdr", func(p *Process, args Cell) bool { SetCdr(Car(args), Cadr(args)) return p.Return(Cadr(args)) }) /* Predicates. */ s.DefineMethod("is-atom", func(p *Process, args Cell) bool { return p.Return(NewBoolean(IsAtom(Car(args)))) }) s.DefineMethod("is-boolean", func(p *Process, args Cell) bool { _, ok := Car(args).(*Boolean) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-channel", func(p *Process, args Cell) bool { o, ok := Car(args).(Context) if !ok { return p.Return(False) } g := Resolve(o.Expose(), nil, NewSymbol("guts")) if g == nil { return p.Return(False) } c, ok := g.GetValue().(*Channel) if !ok { return p.Return(False) } ok = (c.ReadFd() == nil && c.WriteFd() == nil) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-cons", func(p *Process, args Cell) bool { return p.Return(NewBoolean(IsCons(Car(args)))) }) s.DefineMethod("is-float", func(p *Process, args Cell) bool { _, ok := Car(args).(*Float) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-integer", func(p *Process, args Cell) bool { _, ok := Car(args).(*Integer) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-list", func(p *Process, args Cell) bool { return p.Return(NewBoolean(IsList(Car(args)))) }) s.DefineMethod("is-method", func(p *Process, args Cell) bool { _, ok := Car(args).(*Applicative) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-null", func(p *Process, args Cell) bool { ok := Car(args) == Null return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-number", func(p *Process, args Cell) bool { _, ok := Car(args).(Number) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-object", func(p *Process, args Cell) bool { _, ok := Car(args).(Context) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-pipe", func(p *Process, args Cell) bool { o, ok := Car(args).(Context) if !ok { return p.Return(False) } g := Resolve(o.Expose(), nil, NewSymbol("guts")) if g == nil { return p.Return(False) } c, ok := g.GetValue().(*Channel) if !ok { return p.Return(False) } ok = (c.ReadFd() != nil || c.WriteFd() != nil) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-status", func(p *Process, args Cell) bool { _, ok := Car(args).(*Status) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-string", func(p *Process, args Cell) bool { _, ok := Car(args).(*String) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-symbol", func(p *Process, args Cell) bool { _, ok := Car(args).(*Symbol) return p.Return(NewBoolean(ok)) }) s.DefineMethod("is-syntax", func(p *Process, args Cell) bool { _, ok := Car(args).(*Operative) return p.Return(NewBoolean(ok)) }) /* Generators. */ s.DefineMethod("boolean", func(p *Process, args Cell) bool { return p.Return(NewBoolean(Car(args).Bool())) }) s.DefineMethod("channel", func(p *Process, args Cell) bool { c := 0 if args != Null { c = int(Car(args).(Atom).Int()) } return p.Return(channel(p, nil, nil, c)) }) s.DefineMethod("float", func(p *Process, args Cell) bool { return p.Return(NewFloat(Car(args).(Atom).Float())) }) s.DefineMethod("integer", func(p *Process, args Cell) bool { return p.Return(NewInteger(Car(args).(Atom).Int())) }) s.DefineMethod("pipe", func(p *Process, args Cell) bool { return p.Return(channel(p, nil, nil, -1)) }) s.DefineMethod("status", func(p *Process, args Cell) bool { return p.Return(NewStatus(Car(args).(Atom).Status())) }) s.DefineMethod("string", func(p *Process, args Cell) bool { return p.Return(NewString(Car(args).String())) }) s.DefineMethod("symbol", func(p *Process, args Cell) bool { return p.Return(NewSymbol(Raw(Car(args)))) }) /* Relational. */ s.DefineMethod("eq", func(p *Process, args Cell) bool { prev := Car(args) for Cdr(args) != Null { args = Cdr(args) curr := Car(args) if !prev.Equal(curr) { return p.Return(False) } prev = curr } return p.Return(True) }) s.DefineMethod("ge", func(p *Process, args Cell) bool { prev := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if prev.Less(curr) { return p.Return(False) } prev = curr } return p.Return(True) }) s.DefineMethod("gt", func(p *Process, args Cell) bool { prev := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if !prev.Greater(curr) { return p.Return(False) } prev = curr } return p.Return(True) }) s.DefineMethod("is", func(p *Process, args Cell) bool { prev := Car(args) for Cdr(args) != Null { args = Cdr(args) curr := Car(args) if prev != curr { return p.Return(False) } prev = curr } return p.Return(True) }) s.DefineMethod("le", func(p *Process, args Cell) bool { prev := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if prev.Greater(curr) { return p.Return(False) } prev = curr } return p.Return(True) }) s.DefineMethod("lt", func(p *Process, args Cell) bool { prev := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) curr := Car(args).(Atom) if !prev.Less(curr) { return p.Return(False) } prev = curr } return p.Return(True) }) s.DefineMethod("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) } return p.Return(NewBoolean(ok)) }) s.DefineMethod("ne", func(p *Process, args Cell) bool { for l1 := args; l1 != Null; l1 = Cdr(l1) { for l2 := Cdr(l1); l2 != Null; l2 = Cdr(l2) { v1 := Car(l1) v2 := Car(l2) if v1.Equal(v2) { return p.Return(False) } } } return p.Return(True) }) s.DefineMethod("not", func(p *Process, args Cell) bool { return p.Return(NewBoolean(!Car(args).Bool())) }) /* Arithmetic. */ s.DefineMethod("add", func(p *Process, args Cell) bool { acc := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) acc = acc.Add(Car(args)) } return p.Return(acc) }) s.DefineMethod("sub", func(p *Process, args Cell) bool { acc := Car(args).(Number) for Cdr(args) != Null { args = Cdr(args) acc = acc.Subtract(Car(args)) } return p.Return(acc) }) s.DefineMethod("div", func(p *Process, args Cell) bool { acc := Car(args).(Number) for Cdr(args) != Null { args = Cdr(args) acc = acc.Divide(Car(args)) } return p.Return(acc) }) s.DefineMethod("mod", func(p *Process, args Cell) bool { acc := Car(args).(Number) for Cdr(args) != Null { args = Cdr(args) acc = acc.Modulo(Car(args)) } return p.Return(acc) }) s.DefineMethod("mul", func(p *Process, args Cell) bool { acc := Car(args).(Atom) for Cdr(args) != Null { args = Cdr(args) acc = acc.Multiply(Car(args)) } return p.Return(acc) }) /* Standard namespaces. */ list := NewObject(NewLexicalScope(s)) s.Define(NewSymbol("List"), list) list.PublicMethod("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())) } return p.Return(NewString(s)) }) list.PublicMethod("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())) } return p.Return(NewSymbol(s)) }) text := NewObject(NewLexicalScope(s)) s.Define(NewSymbol("Text"), text) text.PublicMethod("is-control", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsControl(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-digit", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsDigit(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-graphic", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsGraphic(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-letter", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsLetter(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-lower", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsLower(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-mark", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsMark(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-print", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsPrint(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-punct", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsPunct(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-space", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsSpace(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-symbol", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsSymbol(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-title", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsTitle(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("is-upper", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewBoolean(unicode.IsUpper(rune(t.Int()))) default: r = Null } return p.Return(r) }) text.PublicMethod("join", func(p *Process, args Cell) bool { str := false sep := Car(args) list := Cdr(args) arr := make([]string, Length(list)) for i := 0; list != Null; i++ { _, str = Car(list).(*String) arr[i] = string(Raw(Car(list))) list = Cdr(list) } r := strings.Join(arr, string(Raw(sep))) if str { return p.Return(NewString(r)) } return p.Return(NewSymbol(r)) }) text.PublicMethod("split", func(p *Process, args Cell) bool { var r Cell = Null sep := Car(args) str := Cadr(args) l := strings.Split(string(Raw(str)), string(Raw(sep))) for i := len(l) - 1; i >= 0; i-- { switch str.(type) { case *Symbol: r = Cons(NewSymbol(l[i]), r) case *String: r = Cons(NewString(l[i]), r) } } return p.Return(r) }) text.PublicMethod("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...) return p.Return(NewString(s)) }) text.PublicMethod("substring", func(p *Process, args Cell) bool { var r Cell s := []rune(Raw(Car(args))) start := int(Cadr(args).(Atom).Int()) end := len(s) if Cddr(args) != Null { end = int(Caddr(args).(Atom).Int()) } switch Car(args).(type) { case *String: r = NewString(string(s[start:end])) case *Symbol: r = NewSymbol(string(s[start:end])) default: r = Null } return p.Return(r) }) text.PublicMethod("to-list", func(p *Process, args Cell) bool { l := Null for _, char := range Raw(Car(args)) { l = Cons(NewInteger(int64(char)), l) } return p.Return(Reverse(l)) }) text.PublicMethod("lower", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewInteger(int64(unicode.ToLower(rune(t.Int())))) case *String: r = NewString(strings.ToLower(Raw(t))) case *Symbol: r = NewSymbol(strings.ToLower(Raw(t))) default: r = NewInteger(0) } return p.Return(r) }) text.PublicMethod("title", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewInteger(int64(unicode.ToTitle(rune(t.Int())))) case *String: r = NewString(strings.ToTitle(Raw(t))) case *Symbol: r = NewSymbol(strings.ToTitle(Raw(t))) default: r = NewInteger(0) } return p.Return(r) }) text.PublicMethod("upper", func(p *Process, args Cell) bool { var r Cell switch t := Car(args).(type) { case *Integer: r = NewInteger(int64(unicode.ToUpper(rune(t.Int())))) case *String: r = NewString(strings.ToUpper(Raw(t))) case *Symbol: r = NewSymbol(strings.ToUpper(Raw(t))) default: r = NewInteger(0) } return p.Return(r) }) s.Public(NewSymbol("Root"), s) e.Define(NewSymbol("$$"), NewInteger(int64(os.Getpid()))) /* Command-line arguments */ args := Null if len(os.Args) > 1 { e.Define(NewSymbol("$0"), NewSymbol(os.Args[1])) for i, v := range os.Args[2:] { e.Define(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.Define(NewSymbol("$0"), NewSymbol(os.Args[0])) } e.Define(NewSymbol("$args"), args) /* Environment variables. */ for _, s := range os.Environ() { kv := strings.SplitN(s, "=", 2) e.Define(NewSymbol("$"+kv[0]), NewSymbol(kv[1])) } Parse(bufio.NewReader(strings.NewReader(` define caar: method (l) as: car: car l define cadr: method (l) as: car: cdr l define cdar: method (l) as: cdr: car l define cddr: method (l) as: cdr: cdr l define caaar: method (l) as: car: caar l define caadr: method (l) as: car: cadr l define cadar: method (l) as: car: cdar l define caddr: method (l) as: car: cddr l define cdaar: method (l) as: cdr: caar l define cdadr: method (l) as: cdr: cadr l define cddar: method (l) as: cdr: cdar l define cdddr: method (l) as: cdr: cddr l define caaaar: method (l) as: caar: caar l define caaadr: method (l) as: caar: cadr l define caadar: method (l) as: caar: cdar l define caaddr: method (l) as: caar: cddr l define cadaar: method (l) as: cadr: caar l define cadadr: method (l) as: cadr: cadr l define caddar: method (l) as: cadr: cdar l define cadddr: method (l) as: cadr: cddr l define cdaaar: method (l) as: cdar: caar l define cdaadr: method (l) as: cdar: cadr l define cdadar: method (l) as: cdar: cdar l define cdaddr: method (l) as: cdar: cddr l define cddaar: method (l) as: cddr: caar l define cddadr: method (l) as: cddr: cadr l define cdddar: method (l) as: cddr: cdar l define cddddr: method (l) as: cddr: cddr l define $connect: syntax (type out close) as { set type: eval type set close: eval close syntax e (left right) as { define p: type spawn { eval: list 'dynamic out 'p e::eval left if close: p::writer-close } dynamic $stdin p e::eval right if close: p::reader-close } } define $redirect: syntax (chan mode mthd) as { syntax e (c cmd) as { define c: e::eval c define f '() if (not: or (is-channel c) (is-pipe c)) { set f: open c mode set c f } eval: list 'dynamic chan 'c e::eval cmd if (not: is-null f): eval: cons 'f mthd } } define and: syntax e (: lst) as { define r False while (not: is-null: car lst) { set r: e::eval: car lst if (not r): return r set lst: cdr lst } return r } define append-stderr: $redirect $stderr "a" writer-close define append-stdout: $redirect $stdout "a" writer-close define backtick: syntax e (cmd) as { define p: pipe define r '() spawn { dynamic $stdout p e::eval cmd p::writer-close } define l: p::readline while l { set r: append r l set l: p::readline } p::reader-close return r } define channel-stderr: $connect channel $stderr True define channel-stdout: $connect channel $stdout True define echo: builtin (: args) as: $stdout::write @args define for: method (l m) as { define r: cons '() '() define c r while (not: is-null l) { set-cdr c: cons (m: car l) '() set c: cdr c set l: cdr l } return: cdr r } define glob: builtin (: args) as: return args define import: syntax e (name) as { define m: module name if (or (is-null m) (is-object m)) { return m } define l: list 'source name set l: cons 'object: cons l '() set l: list 'Root::define m l e::eval l } define is-text: method (t) as: or (is-string t) (is-symbol t) define object: syntax e (: body) as { e::eval: cons 'block: append body '(clone) } define or: syntax e (: lst) as { define r False while (not: is-null: car lst) { set r: e::eval: car lst if r: return r set lst: cdr lst } return r } define pipe-stderr: $connect pipe $stderr True define pipe-stdout: $connect pipe $stdout True define printf: method (: args) as: echo: Text::sprintf (car args) @(cdr args) define quote: syntax (cell) as: return cell define read: builtin () as: $stdin::read define readline: builtin () as: $stdin::readline define redirect-stderr: $redirect $stderr "w" writer-close define redirect-stdin: $redirect $stdin "r" reader-close define redirect-stdout: $redirect $stdout "w" writer-close define source: syntax e (name) as { define basename: e::eval name define paths: Text::split ":" $OHPATH define name basename while (and (not: is-null paths) (not: test -r name)) { set name: Text::join / (car paths) basename set paths: cdr paths } if (not: test -r name): set name basename define f: open name "r-" define l: f::read while l { e::eval l set l: f::read } f::reader-close } define write: method (: args) as: $stdout::write @args List::public ref: method (k x) as: car: List::tail k x List::public tail: method (k x) as { if k { List::tail (sub k 1): cdr x } else { return x } } test -r (Text::join / $HOME .ohrc) && source (Text::join / $HOME .ohrc) `)), Evaluate) }