Example #1
0
Vp.validate = function validate(src) {
    this._src = src;
    var module = esprima.parse("(" + src + ")", { raw: true, loc: true }).body[0].expression;
    var vars = this.match(module, "asm.js module declaration").when({
        type: 'FunctionExpression',
        id: match.var('id', { type: 'Identifier' }),
        params: match.var('params', { length: match.range(0, 4) }),
        body: { loc: match.var('loc'), body: match.var('body') }
    });
    return this.module(vars.params, vars.body.filter(nonEmpty), vars.loc);
};
Example #2
0
    return match(loc, function(when) {
        when({
            start: { line: match.var('sl'), column: match.var('sc') },
            end: { line: match.var('el'), column: match.var('ec') }
        }, function(vars) {
            return " at " + vars.sl + ":" + vars.sc + "-" + vars.el + ":" + vars.ec;
        });

        when(match.any, function() {
            return "";
        });
    });
Example #3
0
        match(todo.pop(), function(when) {
            when({
                type: 'BinaryExpression',
                operator: match.some('+', '-'),
                left: match.var('left'),
                right: match.var('right')
            }, function(vars) {
                todo.push(vars.right, vars.left);
            });

            when(match.var('operand'), function(vars) {
                result.push(vars.operand);
            });
        });
Example #4
0
Vp.table = function table(x, rhs, loc) {
    this.match(rhs, "function table").when({
        type: 'ArrayExpression',
        elements: match.var('elements')
    }, function(vars) {
        var fs = elements.map(function(element) {
            return this.match(element, "function table entry").when(match.var('f', { type: 'Identifier' }),
                                                                    function(vars) { return vars.f; },
                                                                    this);
        }, this);

        if (fs.length === 0)
            this.fail("empty function table", loc);
        if (!powerOf2(fs.length))
            this.fail("function table length must be a power of 2, got " + fs.length, loc);

        var fts = fs.map(function(f) {
            var ft = this.lookup(f.name, f.loc);
            if (!(ft instanceof ty.Arrow))
                this.fail("non-function " + f.name + " in function table", f.loc);
            return ft;
        }, this);

        var ft = fts[0];

        for (var i = 1, n = fts.length; i < n; i++) {
            if (!ft.equals(fts[i]))
                this.fail("unexpected function type " + fs[i].name + " : " + fts[i] + " in function table", fs[i].loc);
        }

        return new ty.Table(ft, fs.length);
    });
};
Example #5
0
Vp.paramType = function paramType(id, stmt) {
    return this.match(stmt, "parameter annotation").when({
        type: 'ExpressionStatement',
        expression: {
            type: 'AssignmentExpression',
            left: { type: 'Identifier', name: id.name },
            right: match.var('right')
        }
    }, function(vars) {
        return this.match(vars.right, "parameter annotation type", function(when) {
            when({
                type: 'UnaryExpression',
                operator: '+',
                argument: { type: 'Identifier', name: id.name }
            }, function() {
                return ty.Double;
            });

            when({
                type: 'BinaryExpression',
                operator: '|',
                left: { type: 'Identifier', name: id.name },
                right: { type: 'Literal', value: 0 }
            }, function() {
                return ty.Int;
            });
        });
    });
};
Example #6
0
    return this.match(e, "function call", function(when) {
        when({
            type: 'CallExpression',
            callee: { type: 'Identifier', name: match.var('f'), loc: match.var('loc') },
            arguments: match.var('args')
        }, function(vars) {
            var formalReturnType = this.checkArguments(vars.args.map(this.expression, this),
                                                       this.lookup(vars.f, vars.loc),
                                                       "function call",
                                                       vars.args.map(function(arg) { return arg.loc; }),
                                                       e.loc);
            this.checkSameType(formalReturnType, t, "function call", e.loc);
        }, this);

        when({
            type: 'CallExpression',
            callee: {
                type: 'MemberExpression',
                object: { type: 'Identifier', name: match.var('f'), loc: match.var('loc') },
                property: {
                    type: 'BinaryExpression',
                    operator: '&',
                    left: match.var('index'),
                    right: {
                        type: 'Literal',
                        value: match.var('n', match.number),
                        raw: dotless,
                        loc: match.var('nloc')
                    }
                },
                computed: true
            },
            arguments: match.var('args')
        }, function(vars) {
            var t = this.lookup(vars.f, vars.loc);
            if (!(t instanceof ty.Table))
                this.fail("expected function table, got " + vars.f, vars.loc);
            this.checkSubtype(this.expression(vars.index), ty.Intish, "function pointer", vars.index.loc);
            if (t.length !== vars.n + 1)
                this.fail("function table mask should be " + (t.length - 1) + ", got " + vars.n, vars.nloc);
            var formalReturnType = this.checkArguments(vars.args.map(this.expression, this),
                                                       t.type, "function pointer call",
                                                       vars.args.map(function(arg) { return arg.loc; }),
                                                       e.loc);
            this.checkSameType(formalReturnType, t, "function call", e.loc);
        }, this);
    });
Example #7
0
                return this.match(prop, "export declaration", function(when) {
                    when({
                        key: {
                            type: 'Literal',
                            value: match.var('external', match.string)
                        },
                        value: {
                            type: 'Identifier',
                            name: match.var('internal'),
                            loc: match.var('loc')
                        },
                        kind: 'init'
                    }, function(vars) {
                        add(vars.internal, vars.external, vars.loc);
                    }, this);

                    when({
                        key: {
                            type: 'Identifier',
                            name: match.var('external')
                        },
                        value: {
                            type: 'Identifier',
                            name: match.var('internal'),
                            loc: match.var('loc')
                        },
                        kind: 'init'
                    }, function(vars) {
                        add(vars.internal, vars.external, vars.loc);
                    }, this);
                });
Example #8
0
 varKeys.forEach(function(key){
   pattern[key] = match.var(key)
 })
Example #9
0
    return this.match(e, "expression", function(when) {
        when({ type: 'Literal', raw: hasDot }, function() {
            return ty.Double;
        });

        when({ type: 'Literal', value: match.range(-0x80000000, 0xffffffff) }, function() {
            return ty.Fixnum;
        });

        when({ type: 'Identifier' }, function() {
            return this.lookupValueType(e.name, e.loc);
        }, this);

        when({
            type: 'AssignmentExpression',
            left: match.var('left', { type: match.some('Identifier', 'MemberExpression') }),
            right: match.var('right')
        }, function(vars) {
            var s = this.expression(vars.left);
            var t = this.expression(vars.right);
            this.checkSubtype(t, s, "assignment", e.loc);
            return t;
        }, this);

        when({
            type: 'MemberExpression',
            object: { type: 'Identifier', name: match.var('x'), loc: match.var('loc') },
            property: { type: 'Literal', value: match.range(0, 0x100000000), raw: dotless }
        }, function(vars) {
            var t = this.lookup(vars.x, vars.loc);
            if (!(t instanceof ty.View))
                this.fail("expected view type, got " + t);
            return t.elementType;
        }, this);

        when({
            type: 'MemberExpression',
            object: { type: 'Identifier', name: match.var('x'), loc: match.var('loc') },
            property: {
                type: 'BinaryExpression',
                operator: '>>',
                left: match.var('e'),
                right: match.var('n', {
                    type: 'Literal',
                    value: match.var('shift', match.number),
                    raw: dotless
                })
            },
            computed: true
        }, function(vars) {
            var t = this.lookup(vars.x, vars.loc);
            if (!(t instanceof ty.View))
                this.fail("expected view type, got " + t, vars.loc);
            this.checkSubtype(this.expression(vars.e), ty.Intish, "heap address" , vars.e.loc);
            var expectedShift = log2(t.bytes);
            if (vars.shift !== expectedShift)
                this.fail("expected shift of " + expectedShift + " bits for view type " + t + ", got " + vars.shift, vars.n.loc);
            return t.elementType;
        }, this);

        when({
            type: 'MemberExpression',
            object: { type: 'Identifier', name: match.var('x'), loc: match.var('loc') },
            property: match.var('e'),
            computed: true
        }, function(vars) {
            var t = this.lookup(vars.x, vars.loc);
            if (!(t instanceof ty.View))
                this.fail("expected view type, got " + t, vars.loc);
            if (t.bytes !== 1)
                this.fail("expected view type with element size 1, got " + t, vars.loc);
            if (t.elementType !== ty.Intish)
                this.fail("expected view type with intish elements, got " + t, vars.loc);
            this.checkSubtype(this.expression(vars.e), ty.Int, "heap address", vars.e.loc);
            return t.Intish;
        }, this);

        when({
            type: 'ConditionalExpression',
            test: match.var('test'),
            consequent: match.var('cons'),
            alternate: match.var('alt')
        }, function(vars) {
            this.checkSubtype(this.expression(vars.test), ty.Int, "conditional test", vars.test.loc);
            var t1 = this.expression(vars.cons);
            var t2 = this.expression(vars.alt);
            if (t1 !== t2)
                this.fail("type mismatch between conditional branches", e.loc);
            if (t1 !== ty.Int && t1 !== ty.Double)
                this.fail("expected int or double in conditional branch, got " + t1, vars.cons.loc);
            return t1;
        }, this);

        when({
            type: 'SequenceExpression',
            expressions: match.var('es')
        }, function(vars) {
            var last = vars.es.pop();
            vars.es.forEach(function(e) {
                if (e.type === 'CallExpression')
                    this.call(e, ty.Void);
                else
                    this.expression(e);
            }, this);
            return this.expression(last);
        }, this);

        when({
            type: 'UnaryExpression',
            operator: '~',
            argument: {
                type: 'UnaryExpression',
                operator: '~',
                argument: match.var('e')
            }
        }, function(vars) {
            this.checkSubtype(this.expression(vars.e), ty.Double, "double->signed coercion", e.loc);
            return ty.Signed;
        }, this);

        when({
            type: 'UnaryExpression',
            operator: '+',
            argument: match.var('e', { type: 'CallExpression' })
        }, function(vars) {
            this.call(vars.e, ty.Double);
            return ty.Double;
        }, this);

        when({
            type: 'UnaryExpression',
            operator: match.var('op'),
            argument: match.var('arg')
        }, function(vars) {
            var t = tables.UNOPS.get(vars.op);
            if (!t)
                this.fail("unknown unary operator " + vars.op, e.loc);
            return this.checkArguments([this.expression(vars.arg)], t, "unary expression", [vars.op.loc], e.loc);
        }, this);

        when({
            type: 'BinaryExpression',
            operator: '|',
            left: match.var('e', { type: 'CallExpression' }),
            right: { type: 'Literal', value: 0, raw: dotless }
        }, function(vars) {
            this.call(vars.e, ty.Signed);
            return ty.Signed;
        }, this);

        when({
            type: 'BinaryExpression',
            operator: match.some('+', '-'),
            left: match.var('left'),
            right: match.var('right')
        }, function(vars) {
            var operands = flattenAdditive(vars.left, vars.right);
            var n = operands.length;
            var t = this.expression(operands[0]);
            if (t.subtype(ty.Double)) {
                for (var i = 1; i < n; i++) {
                    var operand = operands[i];
                    this.checkSubtype(this.expression(operand), ty.Double, "additive operand", operand.loc);
                }
                return ty.Double;
            } else if (t.subtype(ty.Int)) {
                if (n > 0x100000)
                    this.fail("too many additive operations without coercion: " + n + " > maximum 2^20", e.loc);
                for (var i = 1; i < n; i++) {
                    var operand = operands[i];
                    this.checkSubtype(this.expression(operand), ty.Int, "additive operand", operand.loc);
                }
                return ty.Intish;
            }
            this.fail("expected type int or double, got " + t, operands[0].loc);
        }, this);

        when({
            type: 'BinaryExpression',
            operator: match.var('op'),
            left: match.var('left'),
            right: match.var('right')
        }, function(vars) {
            var t = tables.BINOPS.get(vars.op);
            if (!t)
                this.fail("unknown binary operator " + vars.op, e.loc);
            return this.checkArguments([this.expression(vars.left), this.expression(vars.right)],
                                       t, "operator " + vars.op,
                                       [vars.left.loc, vars.right.loc],
                                       e.loc);
        }, this);
    });
Example #10
0
    return this.match(expr, "exports declaration", function(when) {
        when({
            type: 'Identifier',
            name: match.var('f'),
            loc: match.var('loc')
        }, function(vars) {
            var t = this.lookup(vars.f, vars.loc);
            if (!(t instanceof ty.Arrow))
                this.fail("expected exported function, got definition of type " + t, vars.loc);
            return { type: 'single', export: { name: vars.f, type: t } };
        }, this);

        when({
            type: 'ObjectExpression',
            properties: match.var('props')
        }, function(vars) {
            var table = dict();

            var self = this;

            function add(internal, external, loc) {
                var t = self.lookup(internal, loc);
                if (!(t instanceof ty.Arrow))
                    self.fail("expected exported function, got definition of type " + t, loc);
                table.set(external, {
                    name: internal,
                    type: t
                });
            }

            vars.props.forEach(function(prop) {
                return this.match(prop, "export declaration", function(when) {
                    when({
                        key: {
                            type: 'Literal',
                            value: match.var('external', match.string)
                        },
                        value: {
                            type: 'Identifier',
                            name: match.var('internal'),
                            loc: match.var('loc')
                        },
                        kind: 'init'
                    }, function(vars) {
                        add(vars.internal, vars.external, vars.loc);
                    }, this);

                    when({
                        key: {
                            type: 'Identifier',
                            name: match.var('external')
                        },
                        value: {
                            type: 'Identifier',
                            name: match.var('internal'),
                            loc: match.var('loc')
                        },
                        kind: 'init'
                    }, function(vars) {
                        add(vars.internal, vars.external, vars.loc);
                    }, this);
                });
            }, this);

            return { type: 'multiple', exports: table };
        }, this);
    });
Example #11
0
 var fs = elements.map(function(element) {
     return this.match(element, "function table entry").when(match.var('f', { type: 'Identifier' }),
                                                             function(vars) { return vars.f; },
                                                             this);
 }, this);
Example #12
0
    return this.match(rhs, "global declaration", function(when) {
        when({
            type: 'Literal',
            value: match.var('f', match.number),
            raw: match.var('src', hasDot)
        }, function(vars) {
            return { mutable: true, type: ty.Double };
        }, this);

        when({
            type: 'Literal',
            value: match.var('n', match.all(match.integer,
                                            match.range(-0x80000000, 0x100000000))),
            raw: match.var('src')
        }, function(vars) {
            return { mutable: true, type: ty.Int };
        }, this);

        when({
            type: 'MemberExpression',
            object: {
                type: 'MemberExpression',
                object: {
                    type: 'Identifier',
                    name: this._roots.stdlib
                },
                property: {
                    type: 'Identifier',
                    name: 'Math'
                }
            },
            property: {
                type: 'Identifier',
                name: match.var('x')
            }
        }, function(vars) {
            if (!tables.STDLIB_MATH_TYPES.has(vars.x))
                this.fail("unknown library: Math." + vars.x, init.loc);
            return { mutable: false, type: tables.STDLIB_MATH_TYPES.get(vars.x) };
        }, this);

        when({
            type: 'MemberExpression',
            object: {
                type: 'Identifier',
                name: this._roots.stdlib
            },
            property: match.var('x')
        }, function(vars) {
            if (!tables.STDLIB_TYPES.has(vars.x))
                this.fail("unknown library: " + vars.x, init.loc);
            return { mutable: false, type: tables.STDLIB_TYPES.get(vars.x) };
        }, this);

        when({
            type: 'MemberExpression',
            object: {
                type: 'Identifier',
                name: this._roots.foreign
            },
            property: match.var('x')
        }, function(vars) {
            return { mutable: false, type: ty.Function };
        }, this);

        when({
            type: 'BinaryExpression',
            operator: '|',
            left: {
                type: 'MemberExpression',
                object: {
                    type: 'Identifier',
                    name: this._roots.foreign
                },
                property: match.var('x')
            },
            right: {
                type: 'Literal',
                value: 0
            }
        }, function(vars) {
            return { mutable: false, type: ty.Int };
        }, this);

        when({
            type: 'UnaryExpression',
            operator: '+',
            argument: {
                type: 'MemberExpression',
                object: {
                    type: 'Identifier',
                    name: this._roots.foreign
                },
                property: match.var('x')
            }
        }, function(vars) {
            return { mutable: false, type: ty.Double };
        }, this);

        when({
            type: 'NewExpression',
            callee: {
                type: 'MemberExpression',
                object: {
                    type: 'Identifier',
                    name: this._roots.stdlib
                },
                property: {
                    type: 'Identifier',
                    name: match.var('view'),
                    loc: match.var('loc')
                }
            },
            arguments: match.var('args', [{ type: 'Identifier', name: this._roots.heap }])
        }, function(vars) {
            if (vars.args.length !== 1)
                this.fail("heap view constructor expects 1 argument, got " + vars.args.length, vars.args[1].loc);
            if (!tables.HEAP_VIEW_TYPES.has(vars.view))
                this.fail("unknown typed array type: " + vars.view, vars.loc);
            return { mutable: false, type: tables.HEAP_VIEW_TYPES.get(vars.view) };
        }, this);
    }, this);