type check progress

This commit is contained in:
Onoshko Dan 2014-07-29 01:51:41 +07:00
parent e6a49779ae
commit bd86f0d5ce
3 changed files with 195 additions and 39 deletions

View File

@ -118,6 +118,13 @@ Cola.AST_Command = Cola.DEFNODE("Command", "name args", {
$propdoc: {
name: "[string] Name of command",
args: "[AST_Node*] List of arguments"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.args.forEach(function(arg){
arg._walk(visitor);
});
});
}
}, Cola.AST_Node);
@ -406,6 +413,11 @@ Cola.AST_Namedarg = Cola.DEFNODE("Namedarg", "start end name value", {
$documentation: "Named argument",
$propdoc: {
value: "Value of named argument"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.value._walk(visitor);
});
}
}, Cola.AST_SymbolRef);
@ -415,6 +427,11 @@ Cola.AST_ArgDef = Cola.DEFNODE("ArgDef", "start end name type argtype defval", {
$propdoc: {
type: "Data type",
argtype: "positional/named/splated"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.name._walk(visitor);
});
}
}, Cola.AST_SymbolFunarg);
@ -712,12 +729,12 @@ Cola.AST_Cascade = Cola.DEFNODE("Cascade", "expression subexpressions", {
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
this.subexpressions.forEach(function(el){
el._walk(visitor);
this.subexpressions.forEach(function(subexpr){
subexpr._walk(visitor);
});
});
}
});
}, Cola.AST_PropAccess);
Cola.AST_Sub = Cola.DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`",

View File

@ -770,6 +770,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
*/
if((node instanceof Cola.AST_Function || node instanceof Cola.AST_Defun) && node.argnames.length != 0){
var posed = [], named = [], onfront = true, delQueue = [], pos = 0, splated, aftersplated = -1;
node.argnames.forEach(function(val, i){
if(val.argtype == "positional"){
if(val.defval instanceof Cola.AST_Noop && onfront) pos++, node.argnames[i] = val.name;

View File

@ -47,6 +47,16 @@
*/
// TypeAliases
Cola.TypeAliases = {
"int": "Number",
"float": "Number",
"real": "Number",
"double": "Number",
"bool": "Boolean",
"void": "undefined"
};
// RefsStorage
@ -56,11 +66,21 @@ Cola.RefsStorage = function (parentStorage) {
this.objs = [];
};
Cola.RefsStorage.Element = function (name, vartype, callable) {
Cola.RefsStorage.Element = function (name, vartype, callable, args) {
this.name = name;
this.vartype = vartype;
this.callable = callable;
this.props = new Cola.RefsStorage();
this.args = callable ? new Cola.RefsStorage() : false;
if(callable && args){
args.posed.forEach(function(v, k){
this.args.uniqueAdd(k, v, false, false);
}, this);
for(var n in args.named)
this.args.uniqueAdd(n, args.named[n], false, false);
}
};
Cola.RefsStorage.prototype.setSingleType = function (type) {
@ -72,40 +92,42 @@ Cola.RefsStorage.prototype.setSingleType = function (type) {
Cola.RefsStorage.prototype.contains = function (name, callable) {
return this.objs.some(function(el){
return el.name == name && el.callable == callable;
return el.name == name && (el.callable = callable);
});
};
Cola.RefsStorage.prototype.remove = function (name, callable) {
Cola.RefsStorage.prototype.remove = function (name) {
var pre = this.objs.length;
this.objs = this.objs.filter(function(el){
return !(el.name == name && el.callable == callable);
return !(el.name == name);
});
return pre != this.objs.length;
};
Cola.RefsStorage.prototype.uniqueAdd = function (name, vartype, callable) {
if(!this.contains(name, callable)){
this.objs.push(new Cola.RefsStorage.Element(name, vartype, callable));
Cola.RefsStorage.prototype.uniqueAdd = function (name, vartype, callable, args) {
if(!this.contains(name)){
if(callable) this.objs.push(new Cola.RefsStorage.Element(name, "Function", false, false));
this.objs.push(new Cola.RefsStorage.Element(name, vartype, callable, args));
return true;
}
return false;
};
Cola.RefsStorage.prototype.owerwriteAdd = function (name, vartype, callable) {
var removed = this.remove(name, callable);
this.objs.push(new Cola.RefsStorage.Element(name, vartype, callable));
Cola.RefsStorage.prototype.owerwriteAdd = function (name, vartype, callable, args) {
var removed = this.remove(name);
if(callable) this.objs.push(new Cola.RefsStorage.Element(name, "Function", false, false));
this.objs.push(new Cola.RefsStorage.Element(name, vartype, callable, args));
return removed;
};
Cola.RefsStorage.prototype.get = function (name) {
Cola.RefsStorage.prototype.get = function (name, callable) {
if(this.singletype) return this.objs[0];
var obj = false;
this.objs.some(function(el){
return el.name == name && (obj = el);
return el.name == name && el.callable == callable && (obj = el);
});
if(!obj && this.parentStorage) obj = this.parentStorage.get(name);
@ -123,48 +145,162 @@ Cola.TypeChecker = function (parentStorage, om) {
/*
Defs:
first step ( simple )
// first step ( simple )
- vars definition * AST_VarDef - done
- function definition * AST_Defun - done
- function argument definition * AST_SymbolFunarg - done
second step
- object's property assignment * AST_Assign
- prototypes ( classes methods ) * AST_Assign - after classes
- vars definition in constructor ( vars of class ) * AST_Assign - after classes
// second step
//- object's property assignment * AST_Assign
//- prototypes ( classes methods ) * AST_Assign - after classes
//- vars definition in constructor ( vars of class ) * AST_Assign - after classes
*/
Cola.TypeChecker.prototype.reg = function (def) {
Cola.TypeChecker.prototype.reg = function (def, storage) {
if(!storage) storage = this.storage;
if(def.forEach) def.forEach(function(d){
if(d instanceof Cola.AST_VarDef && !this.storage.uniqueAdd(d.name.name, d.type, false)){
this.printVarRedef(d.name.start);
this.storage.owerwriteAdd(d.name.name, d.type, false);
if(Cola.TypeAliases[d.type]) d.type = Cola.TypeAliases[d.type];
if(d instanceof Cola.AST_VarDef && d.type == "Function" && !storage.uniqueAdd(d.name.name, d.type, true)){
this.printFuncRedef(d.name.start);
storage.owerwriteAdd(d.name.name, d.type, true);
} else
if(d instanceof Cola.AST_SymbolFunarg) this.storage.owerwriteAdd(d.name, d.type, false);
}, this); else
if(def instanceof Cola.AST_Defun){
if(!this.storage.uniqueAdd(def.name.name, "Function", false)){
this.printFuncRedef(def.start);
this.storage.owerwriteAdd(def.name.name, "Function", false);
if(d instanceof Cola.AST_VarDef && !storage.uniqueAdd(d.name.name, d.type, false)){
this.printVarRedef(d.name.start);
storage.owerwriteAdd(d.name.name, d.type, false);
}
}, this); else
if(def instanceof Cola.AST_Defun){
if(Cola.TypeAliases[def.type]) def.type = Cola.TypeAliases[def.type];
var argsTypes = { posed: [], named: {} };
def.argnames.forEach(function(val, i){
if(val.argtype == "positional"){
argsTypes.posed.push(val.type);
} else if(val.argtype == "named"){
argsTypes.named[val.name.name] = val.type;
} else if(val.argtype == "splated"){
argsTypes.posed.push(null);
}
});
if(!storage.uniqueAdd(def.name.name, def.type, true, argsTypes)){
this.printFuncRedef(def.start);
storage.owerwriteAdd(def.name.name, def.type, true, argsTypes);
}
this.storage.owerwriteAdd(def.name.name, def.type, true);
}
};
/*
Nodes to check:
Nodes to check: - done
* AST_Binary
* AST_UnaryPrefix
* AST_UnaryPostfix
* AST_Return
* AST_Conditional
* AST_VarDef
* AST_ForIn - `in` left argument
* AST_Switch
* AST_Call - checking args
* AST_Defun && AST_Function - checking returned type
* AST_VarDef - checking def value
* AST_ForIn - checking `in` left arg with right
* AST_Switch - checking arg with braches args
*/
Cola.TypeChecker.prototype.check = function () {
Cola.TypeChecker.prototype.check = function (node) {
if(node instanceof Cola.AST_Assign){
var left = this.get(node.left),
right = this.get(node.right);
if(left != "dynamic" && left != right) this.printMism(node.start);
} else
if(node instanceof Cola.AST_Binary){
var left = this.get(node.left),
right = this.get(node.right);
switch(node.operator){
case "===": case "!==": case "in": case "instanceof": break;
default:
if(left != "dynamic" && right != "dynamic" && left != right)
this.printMism(node.start);
}
} else
if(node instanceof Cola.AST_UnaryPrefix)
switch(node.operator){
case "typeof": case "in": case "delete": case "new": break;
case "+": case "-": case "++": case "--": case "~":
if(this.get(node.expression) != "Number") this.printMism(node.start);
break;
case "!":
if(this.get(node.expression) != "Boolean") this.printMism(node.start);
break;
}
else
if(node instanceof Cola.AST_UnaryPostfix)
switch(node.operator){
case "+": case "-": case "++": case "--":
if(this.get(node.expression) != "Number") this.printMism(node.start);
break;
}
else
if(node instanceof Cola.AST_Conditional){
var cond = this.get(this.condition),
cons = this.get(this.consequent),
altr = this.get(this.alternative);
if(cond != "Boolean" && cond != "dynamic" || cons != altr) this.printMism(node.start);
} else
if(node instanceof Cola.AST_Call){
var args = this.get(node, true).args;
//node.argmap
} else
if((node instanceof Cola.AST_Function || node instanceof Cola.AST_Defun) && node.type != "dynamic"){
var types = this.getReturnedTypes(node);
types.forEach(function(el){
if(node.type != el[0]) this.printMism(el[1]);
});
} else
if(node instanceof Cola.AST_VarDef && node.type != "dynamic" && node.type != this.get(node.value))
this.printMism(node.start);
else
if(node instanceof Cola.AST_ForIn){
var init = node.init instanceof Cola.AST_Var
? node.init.type
: this.get(node.init),
object = this.get(node.object, true);
if(!object.storage.singletype || init != object.storage.get('every').vartype) this.printMism(node.start);
} else
if(node instanceof Cola.AST_Switch){
var expr = this.get(node.expression);
node.body.forEach(function(branch){
if(branch.expression && this.get(branch.expression) != expr) this.printMism(branch.expression.start)
});
}
};
Cola.TypeChecker.prototype.getReturnedTypes = function (node) {
var types = [];
var tw = new Cola.TreeWalker(function(node, descend){
if(node instanceof Cola.AST_Return) types.push([this.get(node), node.start]);
if(!(node instanceof Cola.AST_Defun || node instanceof Cola.AST_Function)) descend();
});
node.walk(tw);
return types;
};
/*
@ -172,13 +308,14 @@ Cola.TypeChecker.prototype.check = function () {
* AST_Binary
* AST_UnaryPrefix
* AST_UnaryPostfix
* AST_Return
* AST_Conditional
* AST_Call
* AST_Seq
* AST_Dot
* AST_Sub
* AST_Cascade
* AST_Proto
* AST_Symbol
@ -186,9 +323,10 @@ Cola.TypeChecker.prototype.check = function () {
* AST_Constant
* AST_Array
* AST_Object
* AST_StringTemplate
*/
Cola.TypeChecker.prototype.get = function () {
Cola.TypeChecker.prototype.get = function (node) {
};
@ -241,7 +379,7 @@ Cola.AST_Toplevel.DEFMETHOD("check_types", function(options){
node.type_checker = new Cola.TypeChecker(node.parent_scope ? node.parent_scope.type_checker.storage : null, options.output_mode);
if (node instanceof Cola.AST_Defun) currScope.type_checker.reg(node);
if (node instanceof Cola.AST_Function || node instanceof Cola.AST_Defun) node.type_checker.reg(node.argnames);
//if (node instanceof Cola.AST_Function || node instanceof Cola.AST_Defun) node.type_checker.reg(node.argnames);
csDump = currScope;
currScope = node;