Skip to content

Commit

Permalink
feat(type_inference): added NumericDefaultInt cons
Browse files Browse the repository at this point in the history
 - Added NumericDefaultInt constraint
 - Updated IntegerLit semantic node to have monotype value
 - Updated semantic analysis to convert all NumericDefaultInt to int in final pass
  • Loading branch information
Akhil Jakatdar committed Nov 12, 2020
1 parent 2e0f9dd commit dd51a9c
Show file tree
Hide file tree
Showing 38 changed files with 1,068 additions and 235 deletions.
5 changes: 5 additions & 0 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,11 @@ func compile(n semantic.Node, subst map[uint64]semantic.MonoType, scope Scope) (
return &integerEvaluator{
i: n.Value,
}, nil
case *semantic.PolyNumericLiteral:
return &integerEvaluator{
i: n.Value,
}, nil

case *semantic.UnsignedIntegerLiteral:
return &unsignedIntegerEvaluator{
i: n.Value,
Expand Down
5 changes: 5 additions & 0 deletions docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,11 @@ Int, Uint, and Float types are Divisible.

Int, Uint, and Float types are Numeric.

##### Numeric Default Int Constraint

Integer literals are polymorphic and can be interpreted as Int, Uint, or Float types.
This constraint is used to infer the type of integer literals based on the context of the program.

##### Comparable Constraint

Comparable types are those the binary comparison operators `<`, `<=`, `>`, or `>=` accept.
Expand Down
8 changes: 8 additions & 0 deletions internal/fbsemantic/semantic.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ enum Kind : ubyte {
Record,
Negatable,
Timeable,
NumericDefaultInt,
}

table Constraint {
Expand Down Expand Up @@ -133,6 +134,7 @@ union Expression {
DateTimeLiteral,
DurationLiteral,
FloatLiteral,
PolyNumericLiteral,
IntegerLiteral,
StringLiteral,
RegexpLiteral,
Expand Down Expand Up @@ -397,6 +399,12 @@ table DurationLiteral {
value:[Duration];
}

table PolyNumericLiteral {
loc:SourceLocation;
value:int64;
typ:MonoType;
}

table IntegerLiteral {
loc:SourceLocation;
value:int64;
Expand Down
137 changes: 113 additions & 24 deletions internal/fbsemantic/semantic_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ func (itrp *Interpreter) doLiteral(lit semantic.Literal) (values.Value, error) {
return values.NewDuration(dur), nil
case *semantic.FloatLiteral:
return values.NewFloat(l.Value), nil
case *semantic.IntegerLiteral:
case *semantic.PolyNumericLiteral:
return values.NewInt(l.Value), nil
case *semantic.UnsignedIntegerLiteral:
return values.NewUInt(l.Value), nil
Expand Down Expand Up @@ -1140,7 +1140,7 @@ func resolveValue(v values.Value) (semantic.Node, bool, error) {
Value: v.Str(),
}, true, nil
case semantic.Int:
return &semantic.IntegerLiteral{
return &semantic.PolyNumericLiteral{
Value: v.Int(),
}, true, nil
case semantic.UInt:
Expand Down
46 changes: 23 additions & 23 deletions interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ func TestEval(t *testing.T) {
{
name: "string interpolation missing field",
query: `
r = makeRecord(o: {a: "foo", b: 42})
r = o: {a: "foo", b: 42}
"r._value = ${r._value}"`,
wantErr: any,
},
{
name: "string interpolation field has wrong type",
query: `
r = makeRecord(o: {a: "foo", b: 42})
r = o: {a: "foo", b: 42}
"r._value = ${r.b}"`,
wantErr: any,
},
Expand Down Expand Up @@ -287,7 +287,7 @@ func TestEval(t *testing.T) {
name: "array index expression out of bounds high",
query: `
a = [1, 2, 3]
i = 3
i = 3
x = a[i]
`,
wantErr: any,
Expand Down Expand Up @@ -439,31 +439,31 @@ func TestEval_Operator_Precedence(t *testing.T) {
want values.Value
}{
{
src: "2.0 * 3.0 ^ 2.0",
src: "2 * 3 ^ 2",
want: values.NewFloat(18.0),
},
{
src: "(2.0 * 3.0) ^ 2.0",
src: "(2 * 3) ^ 2",
want: values.NewFloat(36.0),
},
{
src: "4.0 / 2.0 ^ 2.0",
src: "4 / 2 ^ 2",
want: values.NewFloat(1.0),
},
{
src: "(4.0 / 2.0) ^ 2.0",
src: "(4 / 2) ^ 2",
want: values.NewFloat(4.0),
},
{
src: "2.0 % 4.0 ^ 2.0",
src: "2 % 4 ^ 2",
want: values.NewFloat(2.0),
},
{
src: "(2.0 % 4.0) ^ 2.0",
src: "(2 % 4) ^ 2",
want: values.NewFloat(4.0),
},
{
src: "1.0 + 2.0 * 3.0",
src: "1 + 2 * 3.0",
want: values.NewFloat(7.0),
},
{
Expand Down Expand Up @@ -503,35 +503,35 @@ func TestEval_Operator_Precedence(t *testing.T) {
want: values.NewFloat(6.0),
},
{
src: "1.0 + 2.0 < 4.0",
src: "1 + 2 < 4",
want: values.NewBool(true),
},
{
src: "(1.0 + 2.0) < 4.0",
src: "(1 + 2) < 4",
want: values.NewBool(true),
},
{
src: "1.0 + 2.0 <= 4.0",
src: "1 + 2 <= 4",
want: values.NewBool(true),
},
{
src: "(1.0 + 2.0) <= 4.0",
src: "(1 + 2) <= 4",
want: values.NewBool(true),
},
{
src: "1.0 + 2.0 > 4.0",
src: "1 + 2 > 4",
want: values.NewBool(false),
},
{
src: "(1.0 + 2.0) > 4.0",
src: "(1 + 2) > 4",
want: values.NewBool(false),
},
{
src: "1.0 + 2.0 >= 4.0",
src: "1 + 2 >= 4",
want: values.NewBool(false),
},
{
src: "(1.0 + 2.0) >= 4.0",
src: "(1 + 2) >= 4",
want: values.NewBool(false),
},
{
Expand Down Expand Up @@ -666,9 +666,9 @@ func TestInterpreter_MultipleEval(t *testing.T) {
Value: values.NewInt(2),
Node: &semantic.ExpressionStatement{
Expression: &semantic.BinaryExpression{
Left: &semantic.IntegerLiteral{Value: 1},
Left: &semantic.PolyNumericLiteral{Value: 1},
Operator: ast.AdditionOperator,
Right: &semantic.IntegerLiteral{Value: 1},
Right: &semantic.PolyNumericLiteral{Value: 1},
},
},
},
Expand All @@ -686,9 +686,9 @@ func TestInterpreter_MultipleEval(t *testing.T) {
Value: values.NewInt(2),
Node: &semantic.ExpressionStatement{
Expression: &semantic.BinaryExpression{
Left: &semantic.IntegerLiteral{Value: 1},
Left: &semantic.PolyNumericLiteral{Value: 1},
Operator: ast.AdditionOperator,
Right: &semantic.IntegerLiteral{Value: 1},
Right: &semantic.PolyNumericLiteral{Value: 1},
},
},
},
Expand All @@ -709,7 +709,7 @@ func TestInterpreter_MultipleEval(t *testing.T) {
Property: "yield",
},
Arguments: &semantic.ObjectExpression{Properties: []*semantic.Property{}},
Pipe: &semantic.IntegerLiteral{Value: 0},
Pipe: &semantic.PolyNumericLiteral{Value: 0},
},
},
{
Expand Down
4 changes: 2 additions & 2 deletions libflux/c/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void test_semantic() {

{
printf("Parsing to AST\n");
struct flux_ast_pkg_t *ast_pkg_foo = flux_parse("test", "package foo\nx = 1 + 1.0");
struct flux_ast_pkg_t *ast_pkg_foo = flux_parse("test", "package foo\nx = 1 + \"1.0\"");
assert(ast_pkg_foo != NULL);

printf("Analyzing (expect failure)\n");
Expand Down Expand Up @@ -115,7 +115,7 @@ void test_semantic() {

{
printf("Parsing to AST\n");
struct flux_ast_pkg_t *ast_pkg_foo = flux_parse("test", "package foo\nx = 1 + 1.0");
struct flux_ast_pkg_t *ast_pkg_foo = flux_parse("test", "package foo\nx = 1 + \"1.0\"");
assert(ast_pkg_foo != NULL);
printf("Find variable type v (expect failure)\n");
struct flux_buffer_t buf;
Expand Down
Loading

0 comments on commit dd51a9c

Please sign in to comment.