lang: Update map type definition to include a prefix
It turns out that some planned additions to the parser make it so that the map type definition can be ambiguous. As a result, this patch updates the definition so that the map definition is not confused with an open curly bracket anywhere. Thanks to pestle and stbenjamin for their help understanding yacc!
This commit is contained in:
@@ -60,7 +60,7 @@ func (obj *ExchangeFunc) Info() *interfaces.Info {
|
||||
// TODO: do we want to allow this to be statically polymorphic,
|
||||
// and have value be any type we might want?
|
||||
// output is map of: hostname => value
|
||||
Sig: types.NewType("func(namespace str, value str) {str: str}"),
|
||||
Sig: types.NewType("func(namespace str, value str) map{str: str}"),
|
||||
Err: obj.Validate(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (obj *KVLookupFunc) Info() *interfaces.Info {
|
||||
Pure: false, // definitely false
|
||||
Memo: false,
|
||||
// output is map of: hostname => value
|
||||
Sig: types.NewType("func(namespace str) {str: str}"),
|
||||
Sig: types.NewType("func(namespace str) map{str: str}"),
|
||||
Err: obj.Validate(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func init() {
|
||||
V: HasEnv,
|
||||
})
|
||||
Register("env", &types.FuncValue{
|
||||
T: types.NewType("func() {str: str}"),
|
||||
T: types.NewType("func() map{str: str}"),
|
||||
V: Env,
|
||||
})
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func Env(input []types.Value) (types.Value, error) {
|
||||
}
|
||||
}
|
||||
return &types.MapValue{
|
||||
T: types.NewType("{str: str}"),
|
||||
T: types.NewType("map{str: str}"),
|
||||
V: environ,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func init() {
|
||||
V: Len,
|
||||
},
|
||||
{
|
||||
T: types.NewType("func({variant: variant}) int"),
|
||||
T: types.NewType("func(map{variant: variant}) int"),
|
||||
V: Len,
|
||||
},
|
||||
// TODO: should we add support for struct or func lengths?
|
||||
|
||||
@@ -169,6 +169,11 @@
|
||||
lval.str = yylex.Text()
|
||||
return FLOAT_IDENTIFIER
|
||||
}
|
||||
/map/ {
|
||||
yylex.pos(lval) // our pos
|
||||
lval.str = yylex.Text()
|
||||
return MAP_IDENTIFIER
|
||||
}
|
||||
/struct/ {
|
||||
yylex.pos(lval) // our pos
|
||||
lval.str = yylex.Text()
|
||||
|
||||
@@ -242,11 +242,11 @@ func TestLexParse0(t *testing.T) {
|
||||
values = append(values, test{
|
||||
name: "maps and lists",
|
||||
code: `
|
||||
$strmap {str: int} = {
|
||||
$strmap map{str: int} = {
|
||||
"key1" => 42,
|
||||
"key2" => -13,
|
||||
}
|
||||
$mapstrintlist {str: []int} = {
|
||||
$mapstrintlist map{str: []int} = {
|
||||
"key1" => [42, 44,],
|
||||
"key2" => [],
|
||||
"key3" => [-13,],
|
||||
|
||||
@@ -83,7 +83,7 @@ func init() {
|
||||
%token COMMA COLON SEMICOLON
|
||||
%token ELVIS ROCKET ARROW DOT
|
||||
%token STR_IDENTIFIER BOOL_IDENTIFIER INT_IDENTIFIER FLOAT_IDENTIFIER
|
||||
%token STRUCT_IDENTIFIER VARIANT_IDENTIFIER VAR_IDENTIFIER IDENTIFIER
|
||||
%token MAP_IDENTIFIER STRUCT_IDENTIFIER VARIANT_IDENTIFIER VAR_IDENTIFIER IDENTIFIER
|
||||
%token VAR_IDENTIFIER_HX CAPITALIZED_IDENTIFIER
|
||||
%token CLASS_IDENTIFIER INCLUDE_IDENTIFIER
|
||||
%token COMMENT ERROR
|
||||
@@ -910,11 +910,11 @@ type:
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.typ = types.NewType("[]" + $3.typ.String())
|
||||
}
|
||||
| OPEN_CURLY type COLON type CLOSE_CURLY
|
||||
// map: {str: int} or {str: []int}
|
||||
| MAP_IDENTIFIER OPEN_CURLY type COLON type CLOSE_CURLY
|
||||
// map: map{str: int} or map{str: []int}
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.typ = types.NewType(fmt.Sprintf("{%s: %s}", $2.typ.String(), $4.typ.String()))
|
||||
$$.typ = types.NewType(fmt.Sprintf("map{%s: %s}", $3.typ.String(), $5.typ.String()))
|
||||
}
|
||||
| STRUCT_IDENTIFIER OPEN_CURLY type_struct_fields CLOSE_CURLY
|
||||
// struct: struct{} or struct{a bool} or struct{a bool; bb int}
|
||||
|
||||
@@ -236,8 +236,8 @@ func NewType(s string) *Type {
|
||||
}
|
||||
|
||||
// KindMap
|
||||
if strings.HasPrefix(s, "{") && strings.HasSuffix(s, "}") {
|
||||
s := s[1 : len(s)-1]
|
||||
if strings.HasPrefix(s, "map{") && strings.HasSuffix(s, "}") {
|
||||
s := s[len("map{") : len(s)-1]
|
||||
if s == "" { // it is empty
|
||||
return nil
|
||||
}
|
||||
@@ -502,7 +502,7 @@ func (obj *Type) String() string {
|
||||
if obj.Key == nil || obj.Val == nil {
|
||||
panic("malformed map type")
|
||||
}
|
||||
return fmt.Sprintf("{%s: %s}", obj.Key.String(), obj.Val.String())
|
||||
return fmt.Sprintf("map{%s: %s}", obj.Key.String(), obj.Val.String())
|
||||
|
||||
case KindStruct: // {a bool; b int}
|
||||
if obj.Map == nil {
|
||||
|
||||
@@ -122,8 +122,8 @@ func TestType1(t *testing.T) {
|
||||
},
|
||||
|
||||
// maps
|
||||
"{}": nil, // invalid
|
||||
"{str: str}": {
|
||||
"map{}": nil, // invalid
|
||||
"map{str: str}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindStr,
|
||||
@@ -132,7 +132,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindStr,
|
||||
},
|
||||
},
|
||||
"{str: int}": {
|
||||
"map{str: int}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindStr,
|
||||
@@ -141,7 +141,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindInt,
|
||||
},
|
||||
},
|
||||
"{str: variant}": {
|
||||
"map{str: variant}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindStr,
|
||||
@@ -150,7 +150,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindVariant,
|
||||
},
|
||||
},
|
||||
"{variant: int}": {
|
||||
"map{variant: int}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindVariant,
|
||||
@@ -159,7 +159,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindInt,
|
||||
},
|
||||
},
|
||||
"{variant: variant}": {
|
||||
"map{variant: variant}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindVariant,
|
||||
@@ -170,7 +170,7 @@ func TestType1(t *testing.T) {
|
||||
},
|
||||
|
||||
// nested maps
|
||||
"{str: {int: bool}}": {
|
||||
"map{str: map{int: bool}}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindStr,
|
||||
@@ -185,7 +185,7 @@ func TestType1(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"{{int: bool}: str}": {
|
||||
"map{map{int: bool}: str}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindMap,
|
||||
@@ -200,7 +200,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindStr,
|
||||
},
|
||||
},
|
||||
"{{str: int}: {int: bool}}": {
|
||||
"map{map{str: int}: map{int: bool}}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindMap,
|
||||
@@ -221,7 +221,7 @@ func TestType1(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"{str: {int: {int: bool}}}": {
|
||||
"map{str: map{int: map{int: bool}}}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindStr,
|
||||
@@ -394,7 +394,7 @@ func TestType1(t *testing.T) {
|
||||
},
|
||||
|
||||
// mixed nesting
|
||||
"{str: []struct{a bool; int []bool}}": {
|
||||
"map{str: []struct{a bool; int []bool}}": {
|
||||
Kind: KindMap,
|
||||
Key: &Type{
|
||||
Kind: KindStr,
|
||||
@@ -421,7 +421,7 @@ func TestType1(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"struct{a {str: {struct{deeply int; nested bool}: {int: bool}}}; bb struct{z bool; yy int}; ccc str}": {
|
||||
"struct{a map{str: map{struct{deeply int; nested bool}: map{int: bool}}}; bb struct{z bool; yy int}; ccc str}": {
|
||||
Kind: KindStruct,
|
||||
Ord: []string{
|
||||
"a",
|
||||
@@ -558,7 +558,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindBool,
|
||||
},
|
||||
},
|
||||
"func({str: int}) bool": {
|
||||
"func(map{str: int}) bool": {
|
||||
Kind: KindFunc,
|
||||
// key names are arbitrary...
|
||||
Map: map[string]*Type{
|
||||
@@ -579,7 +579,7 @@ func TestType1(t *testing.T) {
|
||||
Kind: KindBool,
|
||||
},
|
||||
},
|
||||
"func(bool, {str: int}) bool": {
|
||||
"func(bool, map{str: int}) bool": {
|
||||
Kind: KindFunc,
|
||||
// key names are arbitrary...
|
||||
Map: map[string]*Type{
|
||||
@@ -1243,7 +1243,7 @@ func TestType3(t *testing.T) {
|
||||
Kind: KindBool,
|
||||
},
|
||||
},
|
||||
"func(aaa {str: int}) bool": {
|
||||
"func(aaa map{str: int}) bool": {
|
||||
Kind: KindFunc,
|
||||
// key names are arbitrary...
|
||||
Map: map[string]*Type{
|
||||
|
||||
@@ -125,7 +125,7 @@ func ValueOf(v reflect.Value) (Value, error) {
|
||||
}
|
||||
|
||||
return &MapValue{
|
||||
T: NewType(fmt.Sprintf("{%s: %s}", kt.String(), vt.String())),
|
||||
T: NewType(fmt.Sprintf("map{%s: %s}", kt.String(), vt.String())),
|
||||
V: m,
|
||||
}, nil
|
||||
|
||||
|
||||
@@ -81,14 +81,14 @@ func TestPrint1(t *testing.T) {
|
||||
}}: `[["a", "bb", "ccc"], ["d", "ee", "fff"], ["g", "hh", "iii"]]`,
|
||||
}
|
||||
|
||||
d0 := NewMap(NewType("{str: int}"))
|
||||
d0 := NewMap(NewType("map{str: int}"))
|
||||
values[d0] = `{}`
|
||||
|
||||
d1 := NewMap(NewType("{str: int}"))
|
||||
d1 := NewMap(NewType("map{str: int}"))
|
||||
d1.Add(&StrValue{V: "answer"}, &IntValue{V: 42})
|
||||
values[d1] = `{"answer": 42}`
|
||||
|
||||
d2 := NewMap(NewType("{str: int}"))
|
||||
d2 := NewMap(NewType("map{str: int}"))
|
||||
d2.Add(&StrValue{V: "answer"}, &IntValue{V: 42})
|
||||
d2.Add(&StrValue{V: "hello"}, &IntValue{V: 13})
|
||||
values[d2] = `{"answer": 42, "hello": 13}`
|
||||
@@ -196,10 +196,10 @@ func TestReflectValue1(t *testing.T) {
|
||||
}: `[[a bb ccc] [d ee fff] [g hh iii]]`,
|
||||
}
|
||||
|
||||
d0 := NewMap(NewType("{str: int}"))
|
||||
d0 := NewMap(NewType("map{str: int}"))
|
||||
values[d0] = `map[]`
|
||||
|
||||
d1 := NewMap(NewType("{str: int}"))
|
||||
d1 := NewMap(NewType("map{str: int}"))
|
||||
d1.Add(&StrValue{V: "answer"}, &IntValue{V: 42})
|
||||
values[d1] = `map[answer:42]`
|
||||
|
||||
@@ -464,7 +464,7 @@ func TestSort1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMapReflectValue1(t *testing.T) {
|
||||
d := NewMap(NewType("{str: int}"))
|
||||
d := NewMap(NewType("map{str: int}"))
|
||||
d.Add(&StrValue{V: "answer"}, &IntValue{V: 42})
|
||||
d.Add(&StrValue{V: "hello"}, &IntValue{V: 13})
|
||||
// both are valid, since map's aren't sorted
|
||||
@@ -480,7 +480,7 @@ func TestMapReflectValue1(t *testing.T) {
|
||||
t.Errorf("did not match expected: `%s`", exp2)
|
||||
}
|
||||
|
||||
d2 := NewMap(NewType("{str: str}"))
|
||||
d2 := NewMap(NewType("map{str: str}"))
|
||||
d2.Add(&StrValue{V: "answer"}, &StrValue{V: "42 hello:13"})
|
||||
val2 := d2.Value()
|
||||
|
||||
@@ -512,7 +512,7 @@ func TestList1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMapLookup1(t *testing.T) {
|
||||
d := NewMap(NewType("{str: int}"))
|
||||
d := NewMap(NewType("map{str: int}"))
|
||||
k := &StrValue{V: "answer"}
|
||||
v := &IntValue{V: 42}
|
||||
if err := d.Add(k, v); err != nil {
|
||||
|
||||
@@ -147,7 +147,7 @@ func TestUnification1(t *testing.T) {
|
||||
v1: types.TypeFloat,
|
||||
v2: types.TypeFloat,
|
||||
v3: types.TypeFloat,
|
||||
expr: types.NewType("{int: float}"),
|
||||
expr: types.NewType("map{int: float}"),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ cd "${ROOT}"
|
||||
|
||||
failures=''
|
||||
|
||||
# TODO: test examples/lang/ directory to see if the .mcl files compile correctly
|
||||
|
||||
buildout='test-examples.out'
|
||||
# make symlink to outside of package
|
||||
linkto="`pwd`/examples/lib/"
|
||||
|
||||
Reference in New Issue
Block a user