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