Skip to content

Instantly share code, notes, and snippets.

@mpapierski
Created February 25, 2012 02:35
Show Gist options
  • Save mpapierski/1905412 to your computer and use it in GitHub Desktop.
Save mpapierski/1905412 to your computer and use it in GitHub Desktop.
Write GUI applications in a compile-time abstract language
// Write GUI applications in an compile-time abstract language
//
// Copyright 2011 Michał Papierski <[email protected]>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301, USA.
#include <iostream>
#include <string>
#include <list>
#include <map>
#include <boost/lexical_cast.hpp>
using namespace std;
struct object
{
virtual string description() const = 0;
operator string() const { return description(); }
};
struct abstract_expr: object
{
};
template <typename T>
string toString(T t) { return (string)t; }
template <>
string toString(int t) { return boost::lexical_cast<string>(t); }
template <>
string toString(const char* t) { return string("\"") + t + '"'; }
template <typename T1, typename T2>
struct chain_op: abstract_expr
{
T1 t1_;
T2 t2_;
chain_op(T1 t1, T2 t2): t1_(t1), t2_(t2) {}
virtual string description() const
{
return t1_.description() + "\n" + t2_.description();
}
template <typename F1>
chain_op<chain_op<T1, T2>, F1> operator,(F1 f1)
{
return chain_op<chain_op<T1, T2>, F1>(*this, f1);
}
};
namespace expr
{
template <typename T1, typename T2>
struct add_impl: abstract_expr
{
T1 t1_;
T2 t2_;
add_impl(T1 t1, T2 t2): t1_(t1), t2_(t2) {}
virtual string description() const
{
return t1_.description() + " + " + t2_.description();
}
};
template <typename T1, typename T2>
struct setvar_impl: abstract_expr
{
T1 t1_;
T2 t2_;
setvar_impl(T1 t1, T2 t2): t1_(t1), t2_(t2) {}
virtual string description() const
{
return "var " + t1_.description() + " = " + t2_.description() + ';';
}
template <typename F1>
chain_op<setvar_impl<T1, T2>, F1> operator,(F1 f1)
{
return chain_op<setvar_impl<T1, T2>, F1>(*this, f1);
}
};
template <typename T>
struct val_impl: abstract_expr
{
T val_;
val_impl(T t): val_(t) {}
virtual string description() const
{
return toString(val_);
}
template <typename F1>
add_impl<val_impl<T>, F1> operator+(F1 f1)
{
return add_impl<val_impl<T>, F1>(*this, f1);
}
};
template <typename T>
val_impl<T>* val(T t) { return new val_impl<T>(t); }
struct var_impl: abstract_expr
{
string varname_;
var_impl(const string& varname): varname_(varname) {}
template <typename T1>
setvar_impl<var_impl, val_impl<T1> > operator=(T1 t1)
{
return setvar_impl<var_impl, val_impl<T1> >(*this, val_impl<T1>(t1));
}
virtual string description() const { return varname_; }
};
var_impl var(const string& name) { return var_impl(name); }
}
template <typename T1>
expr::add_impl<expr::val_impl<T1>, expr::var_impl> operator+(T1 t1, expr::var_impl t2)
{
return expr::add_impl<expr::val_impl<T1>, expr::var_impl>(t1, t2);
}
template <typename T>
struct alert_impl: abstract_expr
{
T message_;
alert_impl(const T& message): message_(message) {}
virtual string description() const
{
return "alert(" + message_.description() + ");";
}
template <typename F1>
chain_op<alert_impl<T>, F1> operator,(F1 f1)
{
return chain_op<alert_impl<T>, F1>(*this, f1);
}
};
template <typename T>
alert_impl<expr::val_impl<T> > alert(T t)
{
return alert_impl<expr::val_impl<T> >(t);
}
struct debug: abstract_expr
{
string message_;
debug(const string& message): message_(message) {}
virtual string description() const
{
return "debug(\"" + message_ + "\");";
}
template <typename F1>
chain_op<debug, F1> operator,(F1 f1)
{
return chain_op<debug, F1>(*this, f1);
}
};
struct function: object
{
string name_;
string code_;
function() {}
function(const string& name): name_(name) {}
template <typename T>
function& operator[](const T& t)
{
cout << __PRETTY_FUNCTION__ << endl;
code_ = "var _" + name_ + " = function " + name_ + "()\n" +
"{\n" + t.description() + "\n}";
return *this;
}
virtual string description() const
{
return code_;
}
};
struct widgethide_impl: abstract_expr
{
string name_;
widgethide_impl(const string& name): name_(name) {}
virtual string description() const
{
return "document.getElementByName(\"" + name_ + "\").visible = false;";
}
};
struct widget: object
{
string widgetName_;
widget(const string& widgetName): widgetName_(widgetName) {}
map<string /* event */, function /* code */> events_;
virtual string description() const
{
string out = '<' + widgetName_ + ' ';
for (map<string, function>::const_iterator it(events_.begin()),
end(events_.end()); it != end; ++it)
{
out += it->first + "=\"javascript:_" + it->second.name_ + "()\" ";
}
return out + '>';
}
widgethide_impl hide()
{
return widgethide_impl(widgetName_);
}
};
struct button: widget
{
button(): widget("button") {}
};
struct application: object
{
application() {}
list<widget*> dom_;
virtual string description() const
{
string script, temp;
for (list<widget*>::const_iterator it(dom_.begin()),
end(dom_.end()); it != end; ++it)
{
for (map<string, function>::const_iterator it2((*it)->events_.begin()),
end2((*it)->events_.end()); it2 != end2; ++it2)
{
script += it2->second.description() + '\n';
}
temp += (*it)->description();
}
return script + '\n' + temp;
}
};
template <typename T>
struct if_impl: abstract_expr
{
T cond_;
string truestmt_;
string falsestmt_;
if_impl(T cond): cond_(cond) {}
template <typename F1>
if_impl& operator[](F1 f1)
{
truestmt_ = f1.description();
return *this;
}
virtual string description() const
{
return "if (" + cond_.description() + ")\n" +
"{\n" +
truestmt_ + '\n' +
"}";
}
};
template <typename T>
if_impl<T> if_(T t)
{
return if_impl<T>(t);
}
/*
*
* "asdf" + var("var1")
* expression_impl<const char*, var_impl>
* "\"asdf\" + var("var1") + "\""
*
*/
int main(int argc, char **argv)
{
using namespace expr;
application app;
button* btn1 = new button;
btn1->events_["onclick"] = function("jp2gmd")[
var("asdf1") = 5,
var("asdf2") = "hello world",
alert("asdf1 = " + var("asdf1")),
alert("asdf2 = " + var("asdf2"))
];
button* btn2 = new button;
btn2->events_["onclick"] = function("dupa")[
alert("Test"),
widget("btn1").hide(),
widget("btn2").hide()
];
app.dom_.push_back(btn1);
app.dom_.push_back(btn2);
cout << app.description() << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment