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: { $propdoc: {
name: "[string] Name of command", name: "[string] Name of command",
args: "[AST_Node*] List of arguments" 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); }, Cola.AST_Node);
@ -406,6 +413,11 @@ Cola.AST_Namedarg = Cola.DEFNODE("Namedarg", "start end name value", {
$documentation: "Named argument", $documentation: "Named argument",
$propdoc: { $propdoc: {
value: "Value of named argument" value: "Value of named argument"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.value._walk(visitor);
});
} }
}, Cola.AST_SymbolRef); }, Cola.AST_SymbolRef);
@ -415,6 +427,11 @@ Cola.AST_ArgDef = Cola.DEFNODE("ArgDef", "start end name type argtype defval", {
$propdoc: { $propdoc: {
type: "Data type", type: "Data type",
argtype: "positional/named/splated" argtype: "positional/named/splated"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.name._walk(visitor);
});
} }
}, Cola.AST_SymbolFunarg); }, Cola.AST_SymbolFunarg);
@ -712,12 +729,12 @@ Cola.AST_Cascade = Cola.DEFNODE("Cascade", "expression subexpressions", {
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function(){
this.expression._walk(visitor); this.expression._walk(visitor);
this.subexpressions.forEach(function(el){ this.subexpressions.forEach(function(subexpr){
el._walk(visitor); subexpr._walk(visitor);
}); });
}); });
} }
}); }, Cola.AST_PropAccess);
Cola.AST_Sub = Cola.DEFNODE("Sub", null, { Cola.AST_Sub = Cola.DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`", $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){ 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; var posed = [], named = [], onfront = true, delQueue = [], pos = 0, splated, aftersplated = -1;
node.argnames.forEach(function(val, i){ node.argnames.forEach(function(val, i){
if(val.argtype == "positional"){ if(val.argtype == "positional"){
if(val.defval instanceof Cola.AST_Noop && onfront) pos++, node.argnames[i] = val.name; 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 // RefsStorage
@ -56,11 +66,21 @@ Cola.RefsStorage = function (parentStorage) {
this.objs = []; this.objs = [];
}; };
Cola.RefsStorage.Element = function (name, vartype, callable) { Cola.RefsStorage.Element = function (name, vartype, callable, args) {
this.name = name; this.name = name;
this.vartype = vartype; this.vartype = vartype;
this.callable = callable; this.callable = callable;
this.props = new Cola.RefsStorage(); 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) { Cola.RefsStorage.prototype.setSingleType = function (type) {
@ -72,40 +92,42 @@ Cola.RefsStorage.prototype.setSingleType = function (type) {
Cola.RefsStorage.prototype.contains = function (name, callable) { Cola.RefsStorage.prototype.contains = function (name, callable) {
return this.objs.some(function(el){ 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; var pre = this.objs.length;
this.objs = this.objs.filter(function(el){ this.objs = this.objs.filter(function(el){
return !(el.name == name && el.callable == callable); return !(el.name == name);
}); });
return pre != this.objs.length; return pre != this.objs.length;
}; };
Cola.RefsStorage.prototype.uniqueAdd = function (name, vartype, callable) { Cola.RefsStorage.prototype.uniqueAdd = function (name, vartype, callable, args) {
if(!this.contains(name, callable)){ if(!this.contains(name)){
this.objs.push(new Cola.RefsStorage.Element(name, vartype, callable)); 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 true;
} }
return false; return false;
}; };
Cola.RefsStorage.prototype.owerwriteAdd = function (name, vartype, callable) { Cola.RefsStorage.prototype.owerwriteAdd = function (name, vartype, callable, args) {
var removed = this.remove(name, callable); var removed = this.remove(name);
this.objs.push(new Cola.RefsStorage.Element(name, vartype, callable)); 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; return removed;
}; };
Cola.RefsStorage.prototype.get = function (name) { Cola.RefsStorage.prototype.get = function (name, callable) {
if(this.singletype) return this.objs[0]; if(this.singletype) return this.objs[0];
var obj = false; var obj = false;
this.objs.some(function(el){ 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); if(!obj && this.parentStorage) obj = this.parentStorage.get(name);
@ -123,48 +145,162 @@ Cola.TypeChecker = function (parentStorage, om) {
/* /*
Defs: Defs:
first step ( simple ) // first step ( simple )
- vars definition * AST_VarDef - done - vars definition * AST_VarDef - done
- function definition * AST_Defun - done - function definition * AST_Defun - done
- function argument definition * AST_SymbolFunarg - done - function argument definition * AST_SymbolFunarg - done
second step // second step
- object's property assignment * AST_Assign //- object's property assignment * AST_Assign
- prototypes ( classes methods ) * AST_Assign - after classes //- prototypes ( classes methods ) * AST_Assign - after classes
- vars definition in constructor ( vars of class ) * 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(def.forEach) def.forEach(function(d){
if(d instanceof Cola.AST_VarDef && !this.storage.uniqueAdd(d.name.name, d.type, false)){ if(Cola.TypeAliases[d.type]) d.type = Cola.TypeAliases[d.type];
this.printVarRedef(d.name.start);
this.storage.owerwriteAdd(d.name.name, d.type, false); 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 } else
if(d instanceof Cola.AST_SymbolFunarg) this.storage.owerwriteAdd(d.name, d.type, false); if(d instanceof Cola.AST_VarDef && !storage.uniqueAdd(d.name.name, d.type, false)){
}, this); else this.printVarRedef(d.name.start);
if(def instanceof Cola.AST_Defun){ storage.owerwriteAdd(d.name.name, d.type, false);
if(!this.storage.uniqueAdd(def.name.name, "Function", false)){ }
this.printFuncRedef(def.start);
this.storage.owerwriteAdd(def.name.name, "Function", 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_Binary
* AST_UnaryPrefix * AST_UnaryPrefix
* AST_UnaryPostfix * AST_UnaryPostfix
* AST_Return
* AST_Conditional * AST_Conditional
* AST_VarDef * AST_Call - checking args
* AST_ForIn - `in` left argument * AST_Defun && AST_Function - checking returned type
* AST_Switch * 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_Binary
* AST_UnaryPrefix * AST_UnaryPrefix
* AST_UnaryPostfix * AST_UnaryPostfix
* AST_Return
* AST_Conditional * AST_Conditional
* AST_Call * AST_Call
* AST_Seq * AST_Seq
* AST_Dot * AST_Dot
* AST_Sub * AST_Sub
* AST_Cascade
* AST_Proto
* AST_Symbol * AST_Symbol
@ -186,9 +323,10 @@ Cola.TypeChecker.prototype.check = function () {
* AST_Constant * AST_Constant
* AST_Array * AST_Array
* AST_Object * 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); 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_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; csDump = currScope;
currScope = node; currScope = node;