type check progress
This commit is contained in:
parent
e6a49779ae
commit
bd86f0d5ce
23
lib/ast.js
23
lib/ast.js
|
|
@ -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\"]`",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -788,7 +789,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
|
|||
posed.push(splated = { pos : pos++, after : 0, val : val });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if(delQueue.length != 0)
|
||||
delQueue.reverse().forEach(function(val){
|
||||
node.argnames.splice(val, 1);
|
||||
|
|
|
|||
208
lib/typecheck.js
208
lib/typecheck.js
|
|
@ -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)){
|
||||
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_VarDef && !storage.uniqueAdd(d.name.name, d.type, false)){
|
||||
this.printVarRedef(d.name.start);
|
||||
this.storage.owerwriteAdd(d.name.name, d.type, false);
|
||||
} else
|
||||
if(d instanceof Cola.AST_SymbolFunarg) this.storage.owerwriteAdd(d.name, d.type, false);
|
||||
storage.owerwriteAdd(d.name.name, d.type, false);
|
||||
}
|
||||
|
||||
}, this); else
|
||||
|
||||
if(def instanceof Cola.AST_Defun){
|
||||
if(!this.storage.uniqueAdd(def.name.name, "Function", false)){
|
||||
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);
|
||||
this.storage.owerwriteAdd(def.name.name, "Function", false);
|
||||
}
|
||||
this.storage.owerwriteAdd(def.name.name, def.type, true);
|
||||
storage.owerwriteAdd(def.name.name, def.type, true, argsTypes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user