package muesli import "fmt" /* Muesli has no key words by default, but they can be defined if desired * for ease of use. A key word is replaced by a token during lexing. */ type Keyword struct { Name string TokenKind Value } var DefaultKeywords []*Keyword = []*Keyword{ &Keyword { "true", TokenKindBoolean, TrueValue }, &Keyword { "false", TokenKindBoolean, FalseValue }, &Keyword { "nil", TokenKindNil, NilValue }, &Keyword { "do", TokenKindOpenBlock, StringValue("{") }, &Keyword { "end", TokenKindCloseBlock, StringValue("}") }, &Keyword { "as", TokenKindOpenParen, StringValue("(") }, &Keyword { "so", TokenKindCloseParen, StringValue(")") }, &Keyword { "list", TokenKindOpenList, StringValue("[") }, &Keyword { "done", TokenKindCloseList, StringValue("]") }, &Keyword { "the", TokenKindGet, StringValue("$") }, &Keyword { "a", TokenKindGet, StringValue("$") }, &Keyword { "an", TokenKindGet, StringValue("$") }, } var DefaultKeywordsFR []*Keyword = []*Keyword{ &Keyword { "vrai", TokenKindBoolean, TrueValue }, &Keyword { "faux", TokenKindBoolean, FalseValue }, &Keyword { "nul", TokenKindNil, NilValue }, &Keyword { "fais", TokenKindOpenBlock, StringValue("{") }, &Keyword { "fin", TokenKindCloseBlock, StringValue("}") }, &Keyword { "comme", TokenKindOpenParen, StringValue("(") }, &Keyword { "ça", TokenKindCloseParen, StringValue(")") }, &Keyword { "liste", TokenKindOpenList, StringValue("[") }, &Keyword { "fini", TokenKindCloseList, StringValue("]") }, &Keyword { "le", TokenKindGet, StringValue("$") }, &Keyword { "la", TokenKindGet, StringValue("$") }, } var _ Value = &Keyword{} const KeywordType = TypeValue("Keyword") func (kw * Keyword) String() string { return fmt.Sprintf("Keyword: %s %v %v", kw.Name, kw.TokenKind, kw.Value) } func (*Keyword) Type() TypeValue { return KeywordType } func (from * Keyword) Convert(to interface{}) error { switch toPtr := to.(type) { case **Keyword: (*toPtr) = from case *Keyword: (*toPtr) = *from case *Value: (*toPtr) = from default: return NewErrorValuef("Cannot convert Keyword value %v to %v", from, to) } return nil } func (vm * VM) AddKeyword(kw *Keyword) *Keyword { found := vm.Lookup(KeywordName) list, ok := found.(*ListValue) if !ok || list == nil { list = NewListValue() vm.Register(KeywordName, list) } list.Append(kw) return kw } func keyword(vm *VM, val ...Value) []Value { var name string = val[0].String() var tokenName string = val[1].String() var value = val[2] tokenkind, ok := NamesTokenKind[tokenName] if ! ok { return Fail(NewErrorValuef("Token kind unknown: %s", tokenName)) } kw := &Keyword{ Name: name, TokenKind: tokenkind, Value: value } return Ok(vm.AddKeyword(kw)) } func keywords(vm *VM, val ...Value) []Value { kws := []Value{} for i := 2 ; i < len(val) ; i += 3 { var name string = val[i-2].String() var tokenName string = val[i-1].String() var value = val[i] tokenkind, ok := NamesTokenKind[tokenName] if !ok { return Fail(NewErrorValuef("Token kind unknown: %s", tokenName)) } kw := &Keyword{ Name: name, TokenKind: tokenkind, Value: value } kws = append(kws, kw) } listValue := NewListValue(kws...) vm.RegisterTop(KeywordName, listValue) return Ok(listValue) } const KeywordName = "__muesli_keywords__" func (vm * VM) StoreKeywords(keywords []*Keyword) *ListValue { vm.Register("Keyword", KeywordType) vm.RegisterBuiltin("keyword", keyword).Takes(StringType, StringType, AnyType).Returns(KeywordType) vm.RegisterBuiltin("keywords", keyword).Takes(StringType, StringType, AnyType).Returns(ListType) list := NewValueArray() for _, kw := range keywords { list = append(list, kw) } listValue := NewListValue(list...) vm.RegisterTop(KeywordName, listValue) return listValue } func (vm * VM) LoadKeywords() ([]*Keyword) { found := vm.Lookup(KeywordName) list, ok := found.(*ListValue) if !ok || list == nil { return nil } result := []*Keyword{} for _, kw := range list.List { result = append(result, kw.(*Keyword)) } return result }