Skip to content

Commit

Permalink
More detailed spec and tests for parse limits. (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
JimLarson authored Sep 29, 2020
1 parent 69129c5 commit a93b60d
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 4 deletions.
15 changes: 13 additions & 2 deletions doc/langdef.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,19 @@ FieldInits = IDENT ":" Expr {"," IDENT ":" Expr} ;
MapInits = Expr ":" Expr {"," Expr ":" Expr} ;
```

Implementations are required to support at least 250 levels of recursion in
parsing, but may reject programs that exceed that limit.
Implementations are required to support at least:

* 32 levels of nested expressions;
* 32 repetitions of self-recursive or repetitive rules, i.e.:
* 32 terms separated by `||` in a row;
* 32 terms separated by `&&` in a row;
* 32 relations in a row;
* 32 binary arithmetic operators of the same precedence in a row;
* 32 selection (`.`) operators in a row;
* 32 indexing (`[_]`) operators in a row;
* 32 function call arguments;
* list literals with 32 elements;
* map or message literals with 32 fields.

This grammar corresponds to the following operator precedence and associativity:

Expand Down
122 changes: 120 additions & 2 deletions tests/simple/testdata/parse.textproto
Original file line number Diff line number Diff line change
@@ -1,11 +1,129 @@
name: "parse"
description: "End-to-end parsing tests."
section {
name: "depth"
name: "nest"
description: "Deep parse trees which all implementations must support."
test {
name: "list_index"
description: "Member = Member '[' Expr ']'"
expr: "a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[a[0]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
type_env {
name: "a"
ident { type { list_type { elem_type { primitive: INT64 } } } }
}
bindings {
key: "a"
value { value { list_value { values { int64_value: 0 } } } }
}
value { int64_value: 0 }
}
test {
name: "message_literal"
description: "Member = Member '{' [FieldInits] '}'"
container: "google.api.expr.test.v1.proto3"
expr: "NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{child: NestedTestAllTypes{payload: TestAllTypes{single_int64: 137}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}.payload.single_int64"
value { int64_value: 0 }
}
test {
name: "funcall"
description: "Primary = ['.'] IDENT ['(' [ExprList] ')']"
expr: "int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(int(uint(7))))))))))))))))))))))))))))))))"
value { int64_value: 7 }
}
test {
name: "parens"
description: "Primary = '(' Expr ')'"
expr: "((((((((((((((((((((((((((((((((7))))))))))))))))))))))))))))))))"
value { int64_value: 7 }
}
test {
name: "list_literal"
expr: "size([[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['just fine'],[1],[2],[3],[4],[5]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]])"
description: "Primary = '[' [ExprList] ']'"
expr: "size([[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[0]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]])"
value { int64_value: 1 }
}
test {
name: "map_literal"
description: "Primary = '{' [MapInits] '}'"
expr: "size({0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: {0: 'foo'}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})"
value { int64_value: 1 }
}
}
section {
name: "repeat"
description: "Repetitive parse trees which all implementations must support."
test {
name: "conditional"
description: "Expr = ConditionalOr ['?' ConditionalOr ':' Expr]"
expr: "true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : true ? true : false"
value { bool_value: true }
}
test {
name: "or"
description: "ConditionalOr = [ConditionalOr '||'] ConditionalAnd"
expr: "false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || false || true"
value { bool_value: true }
}
test {
name: "and"
description: "ConditionalAnd = [ConditionalAnd '&&'] Relation"
expr: "true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && true && false"
value { bool_value: false }
}
test {
name: "add_sub"
description: "Addition = [Addition ('+' | '-')] Multiplication"
expr: "3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3 - 3 + 3"
value { int64_value: 3 }
}
test {
name: "mul_div"
description: "Multiplication = [Multiplication ('*' | '/' | '%')] Unary"
expr: "4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4 * 4 / 4"
value { int64_value: 4 }
}
test {
name: "not"
description: "Unary = '!' {'!'} Member"
expr: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!true"
value { bool_value: true }
}
test {
name: "unary_neg"
description: "Unary = '-' {'-'} Member"
expr: "--------------------------------19"
value { int64_value: 19 }
}
test {
name: "select"
description: "Member = Member '.' IDENT ['(' [ExprList] ')']"
container: "google.api.expr.test.v1.proto3"
expr: "NestedTestAllTypes{}.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.child.payload.single_int32"
value { int64_value: 0 }
}
test {
name: "index"
description: "Member = Member '[' Expr ']'"
expr: "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['foo']]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]"
value { string_value: "foo" }
}
test {
name: "list_literal"
description: "Primary = '[' [ExprList] ']'"
expr: "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31][17]"
value { int64_value: 17 }
}
test {
name: "map_literal"
description: "Primary = '{' [MapInits] '}'"
expr: "{0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten', 11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen', 19: 'nineteen', 20: 'twenty', 21: 'twenty-one', 22: 'twenty-two', 23: 'twenty-three', 24: 'twenty-four', 25: 'twenty-five', 26: 'twenty-six', 27: 'twenty-seven', 28: 'twenty-eight', 29: 'twenty-nine', 30: 'thirty', 31: 'thirty-one'}[17]"
value { string_value: 'seventeen' }
}
test {
name: "message_literal"
description: "Member = Member '{' [FieldInits] '}'"
container: "google.api.expr.test.v1.proto3"
expr: "TestAllTypes{single_int32: 5, single_int64: 10, single_uint32: 15u, single_uint64: 20u, single_sint32: 25, single_sint64: 30, single_fixed32: 35u, single_fixed64: 40u, single_float: 45.0, single_double: 50.0, single_bool: true, single_string: 'sixty', single_bytes: b'sixty-five', single_value: 70.0, single_int64_wrapper: 75, single_int32_wrapper: 80, single_double_wrapper: 85.0, single_float_wrapper: 90.0, single_uint64_wrapper: 95u, single_uint32_wrapper: 100u, single_string_wrapper: 'one hundred five', single_bool_wrapper: true, repeated_int32: [115], repeated_int64: [120], repeated_uint32: [125u], repeated_uint64: [130u], repeated_sint32: [135], repeated_sint64: [140], repeated_fixed32: [145u], repeated_fixed64: [150u], repeated_sfixed32: [155], repeated_float: [160.0]}.single_sint64"
value { int64_value: 30 }
}
}

0 comments on commit a93b60d

Please sign in to comment.