Implement casts

This commit is contained in:
joeduffy 2017-02-13 05:56:39 -08:00
parent 55deb13100
commit d82adefd38
10 changed files with 825 additions and 345 deletions

View file

@ -606,8 +606,13 @@ func (a *astBinder) checkBinaryOperatorExpression(node *ast.BinaryOperatorExpres
}
func (a *astBinder) checkCastExpression(node *ast.CastExpression) {
// TODO: validate that this is legal.
a.b.ctx.RegisterType(node, a.b.ctx.LookupType(node.Type))
// If we know statically that the cast is invalid, issue an error. Otherwise, defer to runtime.
from := a.b.ctx.RequireType(node.Expression)
to := a.b.ctx.LookupType(node.Type)
if !types.CanConvert(from, to) {
a.b.Diag().Errorf(errors.ErrorInvalidCast.At(node), from, to)
}
a.b.ctx.RegisterType(node, to)
}
func (a *astBinder) checkTypeOfExpression(node *ast.TypeOfExpression) {

View file

@ -37,4 +37,5 @@ var (
"Expected an object target for this instance member load operation")
ErrorUnexpectedObject = newError(527,
"Unexpected object target for this static or module load operation")
ErrorInvalidCast = newError(528, "Illegal cast from '%v' to '%v'; this can never succeed")
)

View file

@ -1406,8 +1406,20 @@ func (e *evaluator) evalBinaryOperatorEquals(lhs *rt.Object, rhs *rt.Object) boo
}
func (e *evaluator) evalCastExpression(node *ast.CastExpression) (*rt.Object, *Unwind) {
contract.Failf("Evaluation of %v nodes not yet implemented", reflect.TypeOf(node))
return nil, nil
// Evaluate the underlying expression.
obj, uw := e.evalExpression(node.Expression)
if uw != nil {
return nil, uw
}
// All bad static casts have been rejected, so we now need to check the runtime types.
from := obj.Type()
to := e.ctx.RequireType(node)
if !types.CanConvert(from, to) {
return nil, NewThrowUnwind(e.NewInvalidCastException(node, from, to))
}
return obj, nil
}
func (e *evaluator) evalIsInstExpression(node *ast.IsInstExpression) (*rt.Object, *Unwind) {

View file

@ -3,6 +3,7 @@
package eval
import (
"github.com/marapongo/mu/pkg/compiler/symbols"
"github.com/marapongo/mu/pkg/diag"
"github.com/marapongo/mu/pkg/eval/rt"
"github.com/marapongo/mu/pkg/util/contract"
@ -25,3 +26,7 @@ func (e *evaluator) NewNegativeArrayLengthException(node diag.Diagable) *rt.Obje
func (e *evaluator) NewIncorrectArrayElementCountException(node diag.Diagable, expect int, got int) *rt.Object {
return e.NewException(node, "Invalid number of array elements; expected <=%v, got %v", expect, got)
}
func (e *evaluator) NewInvalidCastException(node diag.Diagable, from symbols.Type, to symbols.Type) *rt.Object {
return e.NewException(node, "Cannot cast object of type '%v' to '%v'", from, to)
}

View file

@ -0,0 +1,4 @@
{
"name": "basic/casts"
}

View file

@ -0,0 +1,310 @@
{
"name": "basic/casts",
"modules": {
"index": {
"kind": "Module",
"name": {
"kind": "Identifier",
"ident": "index"
},
"imports": [],
"members": {
"a": {
"kind": "ModuleProperty",
"name": {
"kind": "Identifier",
"ident": "a",
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 4
},
"end": {
"line": 3,
"column": 5
}
}
},
"access": "private",
"type": {
"kind": "TypeToken",
"tok": "string",
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 4
},
"end": {
"line": 3,
"column": 19
}
}
}
},
"b": {
"kind": "ModuleProperty",
"name": {
"kind": "Identifier",
"ident": "b",
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 5
}
}
},
"access": "private",
"type": {
"kind": "TypeToken",
"tok": "dynamic",
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 19
}
}
}
},
".init": {
"kind": "ModuleMethod",
"name": {
"kind": "Identifier",
"ident": ".init"
},
"access": "public",
"body": {
"kind": "Block",
"statements": [
{
"kind": "ExpressionStatement",
"expression": {
"kind": "BinaryOperatorExpression",
"left": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/casts:index:a",
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 4
},
"end": {
"line": 3,
"column": 5
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 19
}
}
},
"operator": "=",
"right": {
"kind": "StringLiteral",
"raw": "x",
"value": "x",
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 19
}
}
},
{
"kind": "ExpressionStatement",
"expression": {
"kind": "BinaryOperatorExpression",
"left": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/casts:index:b",
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 5
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 13
},
"end": {
"line": 4,
"column": 19
}
}
},
"operator": "=",
"right": {
"kind": "CastExpression",
"expression": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/casts:index:a",
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 18
},
"end": {
"line": 4,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 18
},
"end": {
"line": 4,
"column": 19
}
}
},
"type": {
"kind": "TypeToken",
"tok": "dynamic",
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 13
},
"end": {
"line": 4,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 13
},
"end": {
"line": 4,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 13
},
"end": {
"line": 4,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 4,
"column": 13
},
"end": {
"line": 4,
"column": 19
}
}
}
]
}
},
".main": {
"kind": "ModuleMethod",
"name": {
"kind": "Identifier",
"ident": ".main"
},
"access": "public",
"body": {
"kind": "Block",
"statements": []
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 12,
"column": 0
}
}
}
},
"default": "index"
}

View file

@ -0,0 +1,11 @@
// This tests out some good and bad cast cases.
let a: string = "x";
let b: any = <any>a; // ok.
// TODO: a way to baseline expected failures.
// let c: number = <number>a; // statically rejected.
// TODO: a way to baseline expected runtime failures.
// let d: number = <number>b; // dynamically rejected.

View file

@ -0,0 +1,6 @@
{
"files": [
"index.ts"
]
}

View file

@ -618,74 +618,6 @@
}
}
},
"d": {
"kind": "ModuleProperty",
"name": {
"kind": "Identifier",
"ident": "d",
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 4
},
"end": {
"line": 21,
"column": 5
}
}
},
"access": "private",
"type": {
"kind": "TypeToken",
"tok": "bool",
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 4
},
"end": {
"line": 21,
"column": 26
}
}
}
},
"e": {
"kind": "ModuleProperty",
"name": {
"kind": "Identifier",
"ident": "e",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 4
},
"end": {
"line": 22,
"column": 5
}
}
},
"access": "private",
"type": {
"kind": "TypeToken",
"tok": "dynamic",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 4
},
"end": {
"line": 26,
"column": 1
}
}
}
},
".init": {
"kind": "ModuleMethod",
"name": {
@ -1075,14 +1007,15 @@
}
},
{
"kind": "ExpressionStatement",
"expression": {
"kind": "IfStatement",
"condition": {
"kind": "BinaryOperatorExpression",
"operator": "!=",
"left": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:d",
"tok": "basic/props:index:c",
"loc": {
"file": "index.ts",
"start": {
@ -1099,70 +1032,25 @@
"file": "index.ts",
"start": {
"line": 21,
"column": 17
"column": 4
},
"end": {
"line": 21,
"column": 26
"column": 5
}
}
},
"operator": "=",
"right": {
"kind": "LoadLocationExpression",
"object": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:c",
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 17
},
"end": {
"line": 21,
"column": 18
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 17
},
"end": {
"line": 21,
"column": 18
}
}
},
"name": {
"kind": "Token",
"tok": "basic/props:index:C:claprop",
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 19
},
"end": {
"line": 21,
"column": 26
}
}
},
"kind": "NullLiteral",
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 17
"column": 10
},
"end": {
"line": 21,
"column": 26
"column": 19
}
}
},
@ -1170,258 +1058,494 @@
"file": "index.ts",
"start": {
"line": 21,
"column": 17
"column": 4
},
"end": {
"line": 21,
"column": 26
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 21,
"column": 17
},
"end": {
"line": 21,
"column": 26
}
}
},
{
"kind": "ExpressionStatement",
"expression": {
"kind": "BinaryOperatorExpression",
"left": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:e",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 4
},
"end": {
"line": 22,
"column": 5
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 8
},
"end": {
"line": 26,
"column": 1
}
}
},
"operator": "=",
"right": {
"kind": "ObjectLiteral",
"type": {
"kind": "TypeToken",
"tok": "dynamic"
},
"properties": [
{
"kind": "ObjectLiteralProperty",
"property": {
"kind": "Token",
"tok": "f"
},
"value": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:modprop",
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 7
},
"end": {
"line": 23,
"column": 14
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 7
},
"end": {
"line": 23,
"column": 14
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 4
},
"end": {
"line": 23,
"column": 14
}
}
},
{
"kind": "ObjectLiteralProperty",
"property": {
"kind": "Token",
"tok": "g"
},
"value": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:C:clastaprop",
"loc": {
"file": "index.ts",
"start": {
"line": 24,
"column": 9
},
"end": {
"line": 24,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 24,
"column": 7
},
"end": {
"line": 24,
"column": 19
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 24,
"column": 4
},
"end": {
"line": 24,
"column": 19
}
}
},
{
"kind": "ObjectLiteralProperty",
"property": {
"kind": "Token",
"tok": "h"
},
"value": {
"kind": "LoadLocationExpression",
"object": {
"kind": "LoadLocationExpression",
"consequent": {
"kind": "Block",
"statements": [
{
"kind": "MultiStatement",
"statements": [
{
"kind": "LocalVariableDeclaration",
"local": {
"kind": "LocalVariable",
"name": {
"kind": "Token",
"tok": "basic/props:index:c",
"kind": "Identifier",
"ident": "d",
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 7
"line": 22,
"column": 8
},
"end": {
"line": 25,
"line": 22,
"column": 9
}
}
},
"type": {
"kind": "TypeToken",
"tok": "bool",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 8
},
"end": {
"line": 22,
"column": 30
}
}
}
}
},
{
"kind": "ExpressionStatement",
"expression": {
"kind": "BinaryOperatorExpression",
"left": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "d",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 8
},
"end": {
"line": 22,
"column": 9
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 21
},
"end": {
"line": 22,
"column": 30
}
}
},
"operator": "=",
"right": {
"kind": "LoadLocationExpression",
"object": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:c",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 21
},
"end": {
"line": 22,
"column": 22
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 21
},
"end": {
"line": 22,
"column": 22
}
}
},
"name": {
"kind": "Token",
"tok": "basic/props:index:C:claprop",
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 23
},
"end": {
"line": 22,
"column": 30
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 21
},
"end": {
"line": 22,
"column": 30
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 7
"line": 22,
"column": 21
},
"end": {
"line": 25,
"column": 8
}
}
},
"name": {
"kind": "Token",
"tok": "basic/props:index:C:claprop",
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 9
},
"end": {
"line": 25,
"column": 16
"line": 22,
"column": 30
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 7
"line": 22,
"column": 21
},
"end": {
"line": 25,
"column": 16
"line": 22,
"column": 30
}
}
}
],
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 21
},
"end": {
"line": 22,
"column": 30
}
}
},
{
"kind": "MultiStatement",
"statements": [
{
"kind": "LocalVariableDeclaration",
"local": {
"kind": "LocalVariable",
"name": {
"kind": "Identifier",
"ident": "e",
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 8
},
"end": {
"line": 23,
"column": 9
}
}
},
"type": {
"kind": "TypeToken",
"tok": "dynamic",
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 8
},
"end": {
"line": 27,
"column": 5
}
}
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 4
{
"kind": "ExpressionStatement",
"expression": {
"kind": "BinaryOperatorExpression",
"left": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "e",
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 8
},
"end": {
"line": 23,
"column": 9
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 12
},
"end": {
"line": 27,
"column": 5
}
}
},
"operator": "=",
"right": {
"kind": "ObjectLiteral",
"type": {
"kind": "TypeToken",
"tok": "dynamic"
},
"properties": [
{
"kind": "ObjectLiteralProperty",
"property": {
"kind": "Token",
"tok": "f"
},
"value": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:modprop",
"loc": {
"file": "index.ts",
"start": {
"line": 24,
"column": 11
},
"end": {
"line": 24,
"column": 18
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 24,
"column": 11
},
"end": {
"line": 24,
"column": 18
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 24,
"column": 8
},
"end": {
"line": 24,
"column": 18
}
}
},
{
"kind": "ObjectLiteralProperty",
"property": {
"kind": "Token",
"tok": "g"
},
"value": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:C:clastaprop",
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 13
},
"end": {
"line": 25,
"column": 23
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 11
},
"end": {
"line": 25,
"column": 23
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 25,
"column": 8
},
"end": {
"line": 25,
"column": 23
}
}
},
{
"kind": "ObjectLiteralProperty",
"property": {
"kind": "Token",
"tok": "h"
},
"value": {
"kind": "LoadLocationExpression",
"object": {
"kind": "LoadLocationExpression",
"name": {
"kind": "Token",
"tok": "basic/props:index:c",
"loc": {
"file": "index.ts",
"start": {
"line": 26,
"column": 11
},
"end": {
"line": 26,
"column": 12
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 26,
"column": 11
},
"end": {
"line": 26,
"column": 12
}
}
},
"name": {
"kind": "Token",
"tok": "basic/props:index:C:claprop",
"loc": {
"file": "index.ts",
"start": {
"line": 26,
"column": 13
},
"end": {
"line": 26,
"column": 20
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 26,
"column": 11
},
"end": {
"line": 26,
"column": 20
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 26,
"column": 8
},
"end": {
"line": 26,
"column": 20
}
}
}
],
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 12
},
"end": {
"line": 27,
"column": 5
}
}
},
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 12
},
"end": {
"line": 27,
"column": 5
}
}
},
"end": {
"line": 25,
"column": 16
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 12
},
"end": {
"line": 27,
"column": 5
}
}
}
}
],
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 8
},
"end": {
"line": 26,
"column": 1
],
"loc": {
"file": "index.ts",
"start": {
"line": 23,
"column": 12
},
"end": {
"line": 27,
"column": 5
}
}
}
},
],
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 8
"line": 21,
"column": 21
},
"end": {
"line": 26,
"line": 28,
"column": 1
}
}
@ -1429,11 +1553,11 @@
"loc": {
"file": "index.ts",
"start": {
"line": 22,
"column": 8
"line": 21,
"column": 0
},
"end": {
"line": 26,
"line": 28,
"column": 1
}
}
@ -1461,7 +1585,7 @@
"column": 0
},
"end": {
"line": 28,
"line": 30,
"column": 0
}
}

View file

@ -18,10 +18,12 @@ class D extends C {
let a: string = modprop;
let b: number = C.clastaprop;
let c: C = <C><any>undefined;
let d: boolean = c.claprop;
let e = {
f: modprop,
g: C.clastaprop,
h: c.claprop,
};
if (c !== undefined) {
let d: boolean = c.claprop;
let e = {
f: modprop,
g: C.clastaprop,
h: c.claprop,
};
}