class fix, singletons added

This commit is contained in:
Dan Onoshko 2014-12-27 01:12:58 +06:00
parent 5cbfbaaa74
commit 45da7bde29
3 changed files with 486 additions and 7 deletions

View File

@ -394,6 +394,34 @@ Cola.AST_Class = Cola.DEFNODE("Class", "name extends", {
}
}, Cola.AST_Scope);
Cola.AST_Singleton = Cola.DEFNODE("Singleton", "name", {
$iscola: true,
$documentation: "Base class for singletons",
$propdoc: {
name: "[AST_SymbolSingleton] the name of this singleton"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.name._walk(visitor);
Cola.walk_body(this, visitor);
});
}
}, Cola.AST_Scope);
Cola.AST_Injector = Cola.DEFNODE("Injector", "name", {
$iscola: true,
$documentation: "Base class for injectors",
$propdoc: {
name: "[AST_SymbolInjector] the name of this injector"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.name._walk(visitor);
Cola.walk_body(this, visitor);
});
}
}, Cola.AST_Scope);
Cola.AST_Lambda = Cola.DEFNODE("Lambda", "name argnames uses_arguments", {
$documentation: "Base class for functions",
$propdoc: {
@ -951,6 +979,16 @@ Cola.AST_SymbolClass = Cola.DEFNODE("SymbolClass", null, {
$documentation: "Symbol defining a class",
}, Cola.AST_SymbolDeclaration);
Cola.AST_SymbolSingleton = Cola.DEFNODE("SymbolSingleton", null, {
$iscola: true,
$documentation: "Symbol defining a singleton",
}, Cola.AST_SymbolDeclaration);
Cola.AST_SymbolInjector = Cola.DEFNODE("SymbolInjector", null, {
$iscola: true,
$documentation: "Symbol defining an injector",
}, Cola.AST_SymbolDeclaration);
Cola.AST_SymbolFunarg = Cola.DEFNODE("SymbolFunarg", "type", {
$documentation: "Symbol naming a function argument",
}, Cola.AST_SymbolVar);

View File

@ -1200,6 +1200,12 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() {
case "class":
return this.class_();
case "singleton":
return this.singleton_();
case "injector":
return this.injector_();
case "function":
return this.function_(Cola.AST_Defun);
@ -1436,7 +1442,7 @@ Cola.Parser.prototype.for_in = function (init) {
Cola.Parser.prototype.class_ = function(){
if(this.S.in_class)
this.token_error(this.prev(), "You can't define class in other class.");
this.token_error(this.prev(), "You can define class, singleton or injector only in root scope.");
this.S.in_class = true;
@ -1504,6 +1510,112 @@ Cola.Parser.prototype.class_ = function(){
});
};
Cola.Parser.prototype.singleton_ = function(){
if(this.S.in_class)
this.token_error(this.prev(), "You can define class, singleton or injector only in root scope.");
this.S.in_class = true;
var _this = this,
name = this.is("name") ? this.as_symbol(Cola.AST_SymbolSingleton) : this.unexpected();
this.S.class_name = name.name;
return new Cola.AST_Singleton({
name: name,
body: (function(loop, labels){
++_this.S.in_function;
_this.S.in_directives = true;
_this.S.in_loop = 0;
_this.S.labels = [];
var tmp, a = _this.block_();
--_this.S.in_function;
_this.S.in_loop = loop;
_this.S.labels = labels;
var mconstr = false;
a.forEach(function(member){
if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_SymbolDefun && member.name.name == _this.S.class_name){
if(member.type != "dynamic")
_this.token_error(member.start, "Constructor can't have returned type.");
if(member.mods.length != 0)
_this.token_error(member.start, "Constructor can't have modificators.");
if(member.argnames.length)
_this.token_error(member.start, "Singleton's and injector's constructor can't have arguments.");
if(mconstr)
_this.token_error(member.start, "Main constructor can be defined only one time");
mconstr = true;
} else if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_Dot && member.mods.indexOf("static") != -1){
_this.token_error(member.start, "Unexpected `static` modificator.");
}
});
_this.S.in_class = false;
_this.S.class_name = false;
return a;
})(this.S.in_loop, this.S.labels)
});
};
Cola.Parser.prototype.injector_ = function(){
if(this.S.in_class)
this.token_error(this.prev(), "You can define class, singleton or injector only in root scope.");
this.S.in_class = true;
var _this = this,
name = this.is("name") ? this.as_symbol(Cola.AST_SymbolInjector) : this.unexpected();
this.S.class_name = name.name;
return new Cola.AST_Injector({
name: name,
body: (function(loop, labels){
++_this.S.in_function;
_this.S.in_directives = true;
_this.S.in_loop = 0;
_this.S.labels = [];
var tmp, a = _this.block_();
--_this.S.in_function;
_this.S.in_loop = loop;
_this.S.labels = labels;
var mconstr = false;
a.forEach(function(member){
if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_SymbolDefun && member.name.name == _this.S.class_name){
if(member.type != "dynamic")
_this.token_error(member.start, "Constructor can't have returned type.");
if(member.mods.length != 0)
_this.token_error(member.start, "Constructor can't have modificators.");
if(mconstr)
_this.token_error(member.start, "Main constructor can be defined only one time");
if(member.argnames.length)
_this.token_error(member.start, "Singleton's and injector's constructor can't have arguments.");
mconstr = true;
} else if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_Dot && member.mods.indexOf("static") != -1){
_this.token_error(member.start, "Unexpected `static` modificator.");
}
});
_this.S.in_class = false;
_this.S.class_name = false;
return a;
})(this.S.in_loop, this.S.labels)
});
};
Cola.Parser.prototype.as_funcarg = function(splatedexist) {
var name = this.as_symbol(Cola.AST_SymbolFunarg), type = name, argtype = 'positional', defval = new Cola.AST_Noop, required = true;

View File

@ -1475,8 +1475,11 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
newNode.push(pre_constructor);
main_constructors.forEach(function(constr){
constr.body.unshift(new Cola.AST_Call({
expression : new Cola.AST_Dot({ expression: new Cola.AST_This, property: "pre_constructor" }),
args : []
expression : new Cola.AST_Dot({
expression : new Cola.AST_Proto({ expression: node.name, property: "pre_constructor" }),
property : "call"
}),
args : [new Cola.AST_This]
}));
constr.body[0] = new Cola.AST_SimpleStatement({
body : constr.body[0]
@ -1488,8 +1491,11 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
newNode.push(post_constructor);
main_constructors.forEach(function(constr){
constr.body.push(new Cola.AST_Call({
expression : new Cola.AST_Dot({ expression: new Cola.AST_This, property: "post_constructor" }),
args : []
expression : new Cola.AST_Dot({
expression : new Cola.AST_Proto({ expression: node.name, property: "post_constructor" }),
property : "call"
}),
args : [new Cola.AST_This]
}));
constr.body[constr.body.length - 1] = new Cola.AST_SimpleStatement({
body : constr.body[constr.body.length - 1]
@ -1537,7 +1543,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
member.args.unshift(new Cola.AST_This);
} else
if(member instanceof Cola.AST_SymbolRef && hmembers.indexOf(member.name) != -1 && node.extends){
if(member instanceof Cola.AST_SymbolRef && hmembers.indexOf(member.name) != -1){
if(member.name == "super"){
with_super = true;
member.name = "$uper";
@ -1549,6 +1555,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
: new Cola.AST_This,
property : member.name
});
if(lvl == 1) flvl_this.push(member);
} else
@ -1564,6 +1571,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
: new Cola.AST_This,
property : member.name
});
if(lvl == 1) flvl_this.push(member);
}
@ -1601,6 +1609,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
});
}
}
});
if(with_super){
@ -1617,6 +1626,326 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){
node = new Cola.AST_BlockStatement({ body: newNode });
} else
/*
singleton Test {
const int i = 123;
Test(){ // constructor
alert("test");
}
queryAll("ul li a").forEach((el) =>
el.onclick = () => console.log("click")
);
covert String method1() => console.log("method");
get getter() => i;
set setter(int val) => console.log(val);
selfExample(){
query("*").onclick = () => console.log(self);
}
}
to
Test(){
this.pre_constructor();
alert("test")
this.post_constructor();
}
Test::pre_constructor(){
const int this.i = 123;
}
Test::post_constructor(){
queryAll("ul li a").forEach((el) =>
el.onclick = () => console.log("click")
);
}
covert String Test::method1() => console.log("method");
get Test::getter() => i;
set Test::setter(int val) => console.log(val);
Test::selfExample(){
var self = this;
query("*").onclick = () => console.log(self);
}
*/
if(node instanceof Cola.AST_Singleton){
var pre_constructor, post_constructor, main_constructors = [],
is_pre = true, members = [], binder;
newNode = [];
node.name = new Cola.AST_SymbolRef(node.name);
pre_constructor = new Cola.AST_Defun({
mods : ["covert"],
type : "dynamic",
name : new Cola.AST_Proto({
expression : new Cola.AST_SymbolDefun(node.name),
property : "pre_constructor"
}),
argnames : [],
body : []
});
post_constructor = new Cola.AST_Defun({
mods : ["covert"],
type : "dynamic",
name : new Cola.AST_Proto({
expression : new Cola.AST_SymbolDefun(node.name),
property : "post_constructor"
}),
argnames : [],
body : []
});
var has_main_constr = false;
node.body.forEach(function(member){
if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_SymbolDefun && member.name.name == node.name.name){
main_constructors.push(member);
newNode.push(member);
has_main_constr = true;
is_pre = false;
} else
if(member instanceof Cola.AST_Lambda && member.name instanceof Cola.AST_SymbolDefun){
if(members.indexOf(member.name.name) == -1) members.push(member.name.name);
member.name = new Cola.AST_Proto({
expression : node.name,
property : member.name.name
});
newNode.push(member);
} else
if(member instanceof Cola.AST_Var && member.mods.indexOf("static") != -1){
member.definitions.forEach(function(def){
var texpr = def.name;
if(!(texpr instanceof Cola.AST_Symbol)){
while(!(texpr.expression instanceof Cola.AST_Symbol || texpr.expression instanceof Cola.AST_Constant)) texpr = texpr.expression;
}
if(def.name instanceof Cola.AST_Symbol && (def.value || member.mods.indexOf("covert") != -1)){
newNode.push(new Cola.AST_VarDef({
name : new Cola.AST_Dot({ expression: node.name, property: def.name.name }),
value : def.value
}));
member.mods.splice(member.mods.indexOf("static"), 1);
newNode[newNode.length - 1] = new Cola.AST_Var({
type : member.type,
mods : member.mods,
definitions : [newNode[newNode.length - 1]]
});
} else
if((def.value || member.mods.indexOf("covert") != -1) && !(texpr.expression instanceof Cola.AST_This)){
texpr.expression = new Cola.AST_Dot({ expression: node.name, property: texpr.expression.name });
newNode.push(new Cola.AST_VarDef({
name : def.name,
value : def.value
}));
member.mods.splice(member.mods.indexOf("static"), 1);
newNode[newNode.length - 1] = new Cola.AST_Var({
type : member.type,
mods : member.mods,
definitions : [newNode[newNode.length - 1]]
});
}
});
}
else {
if(member instanceof Cola.AST_Var)
member.definitions.forEach(function(def){
var texpr = def.name;
if(!(texpr instanceof Cola.AST_Symbol)){
while(!(texpr.expression instanceof Cola.AST_Symbol || texpr.expression instanceof Cola.AST_Constant)) texpr = texpr.expression;
texpr = texpr.expression;
}
if(texpr instanceof Cola.AST_Symbol && !(texpr instanceof Cola.AST_This) && members.indexOf(texpr.name) == -1)
members.push(texpr.name);
});
if(is_pre) pre_constructor.body.push(member);
else post_constructor.body.push(member);
}
});
if(!has_main_constr){
newNode.unshift(new Cola.AST_Defun({
mods : [],
type : "dynamic",
name : new Cola.AST_SymbolDefun(node.name),
argnames : [],
body : []
}));
main_constructors.push(newNode[0]);
}
if(pre_constructor.body.length != 0){
newNode.push(pre_constructor);
main_constructors.forEach(function(constr){
constr.body.unshift(new Cola.AST_Call({
expression : new Cola.AST_Dot({ expression: new Cola.AST_This, property: "pre_constructor" }),
args : []
}));
constr.body[0] = new Cola.AST_SimpleStatement({
body : constr.body[0]
});
});
}
if(post_constructor.body.length != 0){
newNode.push(post_constructor);
main_constructors.forEach(function(constr){
constr.body.push(new Cola.AST_Call({
expression : new Cola.AST_Dot({ expression: new Cola.AST_This, property: "post_constructor" }),
args : []
}));
constr.body[constr.body.length - 1] = new Cola.AST_SimpleStatement({
body : constr.body[constr.body.length - 1]
});
});
}
var scope, lvl = 0, hmembers, with_self = false, self_def = false, flvl_this = [];
binder = new Cola.TreeTransformer(function(member){
var tmembers, tscope, tlvl, tself_def;
member = member.clone();
if(lvl > 1 && member instanceof Cola.AST_Var){
member.definitions.forEach(function(def){
if(def.name instanceof Cola.AST_Symbol){
if(hmembers.indexOf(def.name.name) != -1)
hmembers.splice(hmembers.indexOf(def.name.name), 1);
if(def.name.name == "self")
self_def = true;
}
});
} else
if(lvl > 1 && (member instanceof Cola.AST_Defun || member instanceof Cola.AST_Getter || member instanceof Cola.AST_Setter) && member.name instanceof Cola.AST_Symbol && hmembers.indexOf(member.name.name) != -1){
hmembers.splice(hmembers.indexOf(member.name.name), 1);
} else
if(member instanceof Cola.AST_Scope)
scope = (lvl++, member);
else
if(member instanceof Cola.AST_SymbolRef && hmembers.indexOf(member.name) != -1){
member = new Cola.AST_Dot({
expression : lvl > 1
? (with_self = true, new Cola.AST_SymbolRef({ name: "self" }))
: new Cola.AST_This,
property : member.name
});
if(lvl == 1) flvl_this.push(member);
} else
if(member instanceof Cola.AST_SymbolRef && member.name == "self" && !self_def){
with_self = true;
} else
if(member instanceof Cola.AST_SymbolVar && scope.name instanceof Cola.AST_Proto && (scope.name.property == "pre_constructor" || scope.name.property == "post_constructor")
&& hmembers.indexOf(member.name) != -1){
member = new Cola.AST_Dot({
expression : lvl > 1
? (with_self = true, new Cola.AST_SymbolVar({ name: "self" }))
: new Cola.AST_This,
property : member.name
});
if(lvl == 1) flvl_this.push(member);
}
tscope = scope; tlvl = lvl; tmembers = hmembers.slice(); tself_def = self_def;
member._descend(member, this);
scope = tscope; lvl = tlvl; hmembers = tmembers; self_def = tself_def;
return member;
});
newNode.forEach(function(member, i){
lvl = 0;
flvl_this = [];
with_self = false;
self_def = false;
hmembers = members.slice();
if(member instanceof Cola.AST_Lambda){
newNode[i] = member.transform(binder);
newNode[i].mods ? newNode[i].mods.push("method") : (newNode[i].mods = ["method"]);
if(with_self) {
newNode[i].body.unshift(new Cola.AST_Var({
mods : [],
type : "dynamic",
definitions : [new Cola.AST_VarDef({
type : "dynamic",
name : new Cola.AST_SymbolVar({ name: "self" }),
value : new Cola.AST_This
})]
}));
flvl_this.forEach(function(th){
th.expression = new Cola.AST_SymbolRef({ name: "self" });
});
}
}
});
newNode.push(new Cola.AST_Return({
value : new Cola.AST_New({
args : [],
expression : node.name
})
}));
//node = new Cola.AST_BlockStatement({ body: newNode });
newNode = new Cola.AST_Function({
type : node.name.name,
body : newNode,
argnames : []
});
newNode = new Cola.AST_Call({
args : [],
expression : newNode
});
node = new Cola.AST_Var({
type : node.name.name,
mods : [],
definitions : [new Cola.AST_VarDef({
type : node.name.name,
name : new Cola.AST_SymbolVar(node.name),
value : newNode
})]
});
} else
/*
func(String s, Number n:, Array list..., Boolean b = false, h: 123){