func CapitalizeFirst(s string) string { runes := []rune(s) runes[0] = unicode.ToTitle(runes[0]) return string(runes) }
func ExampleToTitle() { const ucG = 'g' fmt.Printf("%#U\n", unicode.ToTitle(ucG)) // Output: // U+0047 'G' }
func TestWordBreaks(t *testing.T) { for _, tt := range breakTest { testtext.Run(t, tt, func(t *testing.T) { parts := strings.Split(tt, "|") want := "" for _, s := range parts { found := false // This algorithm implements title casing given word breaks // as defined in the Unicode standard 3.13 R3. for _, r := range s { title := unicode.ToTitle(r) lower := unicode.ToLower(r) if !found && title != lower { found = true want += string(title) } else { want += string(lower) } } } src := strings.Join(parts, "") got := Title(language.Und).String(src) if got != want { t.Errorf("got %q; want %q", got, want) } }) } }
func capitalize(s string) string { if s == "" { return s } r, n := utf8.DecodeRuneInString(s) return string(unicode.ToTitle(r)) + s[n:] }
func TestMapping(t *testing.T) { assigned := rangetable.Assigned(UnicodeVersion) coreVersion := rangetable.Assigned(unicode.Version) if coreVersion == nil { coreVersion = assigned } apply := func(r rune, f func(c *context) bool) string { c := contextFromRune(r) f(c) return string(c.dst[:c.pDst]) } for r, tt := range special { if got, want := apply(r, lower), tt.toLower; got != want { t.Errorf("lowerSpecial:(%U): got %+q; want %+q", r, got, want) } if got, want := apply(r, title), tt.toTitle; got != want { t.Errorf("titleSpecial:(%U): got %+q; want %+q", r, got, want) } if got, want := apply(r, upper), tt.toUpper; got != want { t.Errorf("upperSpecial:(%U): got %+q; want %+q", r, got, want) } } for r := rune(0); r <= lastRuneForTesting; r++ { if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) { continue } if rf := unicode.SimpleFold(r); rf == r || !unicode.In(rf, assigned) { continue } if _, ok := special[r]; ok { continue } want := string(unicode.ToLower(r)) if got := apply(r, lower); got != want { t.Errorf("lower:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) } want = string(unicode.ToUpper(r)) if got := apply(r, upper); got != want { t.Errorf("upper:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) } want = string(unicode.ToTitle(r)) if got := apply(r, title); got != want { t.Errorf("title:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) } } }
// TranslateNormal is the default translator for regular (NOT aligned) FASTA // files. func TranslateNormal(b byte) (seq.Residue, bool) { switch { case b >= 'a' && b <= 'z': return seq.Residue(unicode.ToTitle(rune(b))), true case b >= 'A' && b <= 'Z': return seq.Residue(b), true case b == '*': return 0, true case b == '-': return '-', true case b == '/': // PIR junk. Chain breaks? WTF? return '-', true } return 0, false }
// Converts strings with underscores to Go-like names. e.g.: bla_blub_foo -> BlaBlubFoo func GoName(n string) string { prev := '_' return strings.Map(func(r rune) rune { if r == '_' { prev = r return -1 } if prev == '_' { prev = r return unicode.ToTitle(r) } prev = r return unicode.ToLower(r) }, n) }
// Title returns a copy of the string s with all Unicode letters that begin words // mapped to their title case. func Title(s string) string { // Use a closure here to remember state. // Hackish but effective. Depends on Map scanning in order and calling // the closure once per rune. prev := rune(' ') return Map( func(r rune) rune { if isSeparator(prev) { prev = r return unicode.ToTitle(r) } prev = r return r }, s) }
// Title returns a copy of s with all Unicode letters that begin words // mapped to their title case. func Title(s []byte) []byte { // Use a closure here to remember state. // Hackish but effective. Depends on Map scanning in order and calling // the closure once per rune. prev := ' ' return Map( func(r int) int { if isSeparator(prev) { prev = r return unicode.ToTitle(r) } prev = r return r }, s) }
func fullCaseTest() { for i, c := range chars { lower := unicode.ToLower(i); want := caseIt(i, c.lowerCase); if lower != want { fmt.Fprintf(os.Stderr, "lower U+%04X should be U+%04X is U+%04X\n", i, want, lower) } upper := unicode.ToUpper(i); want = caseIt(i, c.upperCase); if upper != want { fmt.Fprintf(os.Stderr, "upper U+%04X should be U+%04X is U+%04X\n", i, want, upper) } title := unicode.ToTitle(i); want = caseIt(i, c.titleCase); if title != want { fmt.Fprintf(os.Stderr, "title U+%04X should be U+%04X is U+%04X\n", i, want, title) } } }
// Gets a proper case for a string (i.e. capitalised like a proper noun) func getProperCase(s string) string { // Generously 'borrowing' from strings.Map // In the worst case, the string can grow when mapped, making // things unpleasant. But it's so rare we barge in assuming it's // fine. It could also shrink but that falls out naturally. maxbytes := len(s) // length of b nbytes := 0 // number of bytes encoded in b var b []byte = make([]byte, maxbytes) needsCapitalising := true for _, c := range s { r := c // chars to skip and be followed by capitalisation if r == '.' || r == '-' || r == '_' || r == ' ' { needsCapitalising = true continue } if needsCapitalising { r = unicode.ToTitle(r) needsCapitalising = false } if r >= 0 { wid := 1 if r >= utf8.RuneSelf { wid = utf8.RuneLen(r) } if nbytes+wid > maxbytes { // Grow the buffer. maxbytes = maxbytes*2 + utf8.UTFMax nb := make([]byte, maxbytes) copy(nb, b[0:nbytes]) b = nb } nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r) } } return string(b[0:nbytes]) }
func fullCaseTest() { for j, c := range chars { i := rune(j) lower := unicode.ToLower(i) want := caseIt(i, c.lowerCase) if lower != want { fmt.Fprintf(os.Stderr, "lower %U should be %U is %U\n", i, want, lower) } upper := unicode.ToUpper(i) want = caseIt(i, c.upperCase) if upper != want { fmt.Fprintf(os.Stderr, "upper %U should be %U is %U\n", i, want, upper) } title := unicode.ToTitle(i) want = caseIt(i, c.titleCase) if title != want { fmt.Fprintf(os.Stderr, "title %U should be %U is %U\n", i, want, title) } } }
func TestMapping(t *testing.T) { apply := func(r rune, f func(c *context) bool) string { c := contextFromRune(r) f(c) return string(c.dst[:c.pDst]) } for r, tt := range special { if got, want := apply(r, lower), tt.toLower; got != want { t.Errorf("lowerSpecial:(%U): got %+q; want %+q", r, got, want) } if got, want := apply(r, title), tt.toTitle; got != want { t.Errorf("titleSpecial:(%U): got %+q; want %+q", r, got, want) } if got, want := apply(r, upper), tt.toUpper; got != want { t.Errorf("upperSpecial:(%U): got %+q; want %+q", r, got, want) } } for r := rune(0); r <= lastRuneForTesting; r++ { if _, ok := special[r]; ok { continue } want := string(unicode.ToLower(r)) if got := apply(r, lower); got != want { t.Errorf("lower:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) } want = string(unicode.ToUpper(r)) if got := apply(r, upper); got != want { t.Errorf("upper:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) } want = string(unicode.ToTitle(r)) if got := apply(r, title); got != want { t.Errorf("title:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) } } }
func camelCase(s string) string { camel := false first := true return strings.Map(func(r rune) rune { if unicode.IsLetter(r) || unicode.IsDigit(r) { if first { // always lower case first rune first = false return unicode.ToLower(r) } if camel { camel = false return unicode.ToTitle(r) } return r } if !first { // if first runes aren't letters or digits, don't capitalize camel = true // unknown rune type -> ignore and title case next rune } return -1 }, s) }
// capitalize the first letter in the string func capitalize(s string) string { r, size := utf8.DecodeRuneInString(s) return fmt.Sprintf("%c", unicode.ToTitle(r)) + s[size:] }
func CapitalizeFirst(s string) string { return string(unicode.ToTitle([]rune(s)[0])) + s[1:] }
func capitalize(s string) string { return string(unicode.ToTitle(rune(s[0]))) + s[1:] }
// capitalize the first letter in s func capitalize(s string) string { r, l := utf8.DecodeRuneInString(s) b := make([]byte, l) utf8.EncodeRune(b, unicode.ToTitle(r)) return strings.Join([]string{string(b), s[l:]}, "") }
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 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) }