Skip to content

Commit

Permalink
Added a version of a simple fluent C++ interface built by python from…
Browse files Browse the repository at this point in the history
… config file.
  • Loading branch information
mikeando committed Sep 16, 2011
1 parent 5cfe35f commit 18559c2
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 0 deletions.
25 changes: 25 additions & 0 deletions fluent_generated/FluentConfigCore.h
@@ -0,0 +1,25 @@
#pragma once

#include <string>
#include <iostream>

struct FluentConfigCore
{
void SetUrl( std::string s )
{
std::cout<<"Setting Url to "<<s<<std::endl;
}
void SetPost()
{
std::cout<<"Setting mode to POST"<<std::endl;
}
void SetGet()
{
std::cout<<"Setting mode to GET"<<std::endl;
}
void AddPostData(std::string key, std::string value)
{
std::cout<<"Adding Post Data :"<<key<<","<<value<<std::endl;
}
};

8 changes: 8 additions & 0 deletions fluent_generated/Makefile
@@ -0,0 +1,8 @@
a.out : fluent_simple.cpp transitions.h transitions.o
g++ fluent_simple.cpp transitions.o

transitions.o : transitions.h transitions.cpp
g++ -c transitions.cpp

transitions.h transitions.cpp : transition_table.txt helper.py
python helper.py
6 changes: 6 additions & 0 deletions fluent_generated/README.markdown
@@ -0,0 +1,6 @@
Shows how we could use python to generate the fluent interface from a simple config file at compile time.

The file `transition_table.py` contains the transitions the fluent interface can go through.
`helper.py` generates the source and header files from that file. (You can find them in the generated directory for reference).

The usage of the interface is in `fluent_simple.cpp`.
27 changes: 27 additions & 0 deletions fluent_generated/fluent_simple.cpp
@@ -0,0 +1,27 @@
#include <string>
#include <iostream>

#include "FluentConfigCore.h"
#include "transitions.h"

int main()
{
FluentConfigCore fcc;
ZZZState(&fcc)
.SetUrl("blue")
.SetPost()
.AddPostData("a","1")
.AddPostData("b","2");

// This will not compile
// It gives this error with clang++ (And something a little more cryptic on g++)
// fluent_interface3.cpp:262:6: error: no member named 'SetPostData' in 'FluentConfigState<UGZState>'
// .SetPostData("a","1")
// ^
//
// ZZZState(/*&fcc*/)
// .SetUrl("blue")
// .SetGet()
// .SetPostData("a","1")
// .SetPostData("b","2");
}
74 changes: 74 additions & 0 deletions fluent_generated/generated/transitions.cpp
@@ -0,0 +1,74 @@
#include "transitions.h"
#include "FluentConfigCore.h"
UZZState ZZZState::SetUrl(std::string url)
{
core->SetUrl(url);
return UZZState(core);
};

ZPZState ZZZState::SetPost()
{
core->SetPost();
return ZPZState(core);
};

ZGZState ZZZState::SetGet()
{
core->SetGet();
return ZGZState(core);
};

UGZState ZGZState::SetUrl(std::string url)
{
core->SetUrl(url);
return UGZState(core);
};

UGZState UZZState::SetGet()
{
core->SetGet();
return UGZState(core);
};

UPZState UZZState::SetPost()
{
core->SetPost();
return UPZState(core);
};

UPDState UPZState::AddPostData(std::string key, std::string value)
{
core->AddPostData(key,value);
return UPDState(core);
};

UPDState UPDState::AddPostData(std::string key, std::string value)
{
core->AddPostData(key,value);
return UPDState(core);
};

ZPDState ZPDState::AddPostData(std::string key, std::string value)
{
core->AddPostData(key,value);
return ZPDState(core);
};

UPDState ZPDState::SetUrl(std::string url)
{
core->SetUrl(url);
return UPDState(core);
};

UPZState ZPZState::SetUrl(std::string url)
{
core->SetUrl(url);
return UPZState(core);
};

ZPDState ZPZState::AddPostData(std::string key, std::string value)
{
core->AddPostData(key,value);
return ZPDState(core);
};

86 changes: 86 additions & 0 deletions fluent_generated/generated/transitions.h
@@ -0,0 +1,86 @@
class FluentConfigCore;
#include <string>
class UGZState;
class ZZZState;
class ZGZState;
class UZZState;
class UPZState;
class UPDState;
class ZPDState;
class ZPZState;
class UGZState
{
public:
explicit UGZState( FluentConfigCore * in_core ) : core(in_core) {}
protected:
FluentConfigCore * core;
};

class ZZZState
{
public:
explicit ZZZState( FluentConfigCore * in_core ) : core(in_core) {}
UZZState SetUrl(std::string url);
ZPZState SetPost();
ZGZState SetGet();
protected:
FluentConfigCore * core;
};

class ZGZState
{
public:
explicit ZGZState( FluentConfigCore * in_core ) : core(in_core) {}
UGZState SetUrl(std::string url);
protected:
FluentConfigCore * core;
};

class UZZState
{
public:
explicit UZZState( FluentConfigCore * in_core ) : core(in_core) {}
UGZState SetGet();
UPZState SetPost();
protected:
FluentConfigCore * core;
};

class UPZState
{
public:
explicit UPZState( FluentConfigCore * in_core ) : core(in_core) {}
UPDState AddPostData(std::string key, std::string value);
protected:
FluentConfigCore * core;
};

class UPDState
{
public:
explicit UPDState( FluentConfigCore * in_core ) : core(in_core) {}
UPDState AddPostData(std::string key, std::string value);
protected:
FluentConfigCore * core;
};

class ZPDState
{
public:
explicit ZPDState( FluentConfigCore * in_core ) : core(in_core) {}
ZPDState AddPostData(std::string key, std::string value);
UPDState SetUrl(std::string url);
protected:
FluentConfigCore * core;
};

class ZPZState
{
public:
explicit ZPZState( FluentConfigCore * in_core ) : core(in_core) {}
UPZState SetUrl(std::string url);
ZPDState AddPostData(std::string key, std::string value);
protected:
FluentConfigCore * core;
};

87 changes: 87 additions & 0 deletions fluent_generated/helper.py
@@ -0,0 +1,87 @@
import re
import sys

line_splitter = re.compile(r"(\w+)\s+(\w+)\s+(.*)$")
comment = re.compile(r"\s*//.*$")
out_header = re.compile(r"\s*HEADER\s*:\s*(\w+(?:\.h)?(?:\.hpp)?)\s*$")
out_source = re.compile(r"\s*SOURCE\s*:\s*(\w+(?:\.cpp)?(?:\.cxx)?)\s*$")
default_action_re = re.compile(r"\s*DEFAULT_ACTION\s*@([^@]*)@(.*)$")

transition_table = open('transition_table.txt', 'r')

transitions = dict()
structs = set()

header = None
source = None

default_actions ={} # { "SetUrl(std::string url)":"core->SetUrl(url);" }

for l in transition_table:
l = l.strip()
l = comment.sub("",l)

if l!="":
m=out_header.match(l)
if m:
if header!=None:
print >> sys.stderr, "ERROR: Multiple headers found, %s and %s" % header, m.group(1)
sys.exit(1)
header = m.group(1)
continue
m=out_source.match(l)
if m:
if source!=None:
print >> sys.stderr, "ERROR: Multiple sources found, %s and %s" % source, m.group(1)
sys.exit(1)
source = m.group(1)
continue
m = default_action_re.match(l)
if m:
default_actions[ m.group(1).strip() ] = m.group(2).strip();
continue
m = line_splitter.match(l)
if not m:
print >> sys.stderr, "Unable to parse line: %s" % l
else:
structs.add(m.group(1))
structs.add(m.group(2))
if m.group(1) not in transitions:
transitions[m.group(1)] = []

transitions[m.group(1)].append( { 'to':m.group(2), 'fn':m.group(3) } )

print default_actions

hf = open( header, "w" )
sf = open( source, "w" )

print >> hf, "class FluentConfigCore;"
print >> hf, "#include <string>"

for x in structs:
print >> hf, "class %s;" % x

for x in structs:
print >> hf, "class %s" % x
print >> hf, "{"
print >> hf, " public:"
print >> hf, " explicit %s( FluentConfigCore * in_core ) : core(in_core) {}" % x
for t in transitions.get(x,[]):
print >> hf, " %s %s;" % ( t['to'], t['fn'] )
print >> hf, " protected:"
print >> hf, " FluentConfigCore * core;"
print >> hf, "};\n"


print >> sf, "#include \"%s\"" % header
print >> sf, "#include \"FluentConfigCore.h\""
for x in structs:
for t in transitions.get(x,[]):
print >> sf,"%s %s::%s" % (t['to'], x, t['fn'])
print >> sf,"{"
if t['fn'] in default_actions:
print >> sf," "+default_actions[t['fn']]
print >> sf," return %s(core);" % t['to']
print >> sf,"};\n"

41 changes: 41 additions & 0 deletions fluent_generated/transition_table.txt
@@ -0,0 +1,41 @@
// +>>>>>>>>>>>(SetPost)>>>>>>>>>>>>>>>>>>+
// ^ v +>>(AddPostData)>>+
// ^ v ^ v
//[UZZState]>>>(SetGet)>>>[UGZState] [UPZState]>>>(AddPostData)>>>[UPDState]<<<<<<<<<<<+
// ^ ^ ^ ^
// ^ ^ ^ ^
//(SetUrl) (SetUrl) (SetUrl) (SetUrl)
// ^ ^ ^ ^
// ^ ^ ^ ^
//[ZZZState]>>>(SetGet)>>>[ZGZState] [ZPZState]>>>(AddPostData)>>>[ZPDState]<<<<<<<<<<<<+
// v ^ v ^
// v ^ +>>(AddPostData)>>+
// +>>>>>>>>>>>(SetPost)>>>>>>>>>>>>>>>>>>+
//

HEADER : transitions.h
SOURCE : transitions.cpp

DEFAULT_ACTION @ SetUrl(std::string url) @ core->SetUrl(url);
DEFAULT_ACTION @ SetPost() @ core->SetPost();
DEFAULT_ACTION @ SetGet() @ core->SetGet();
DEFAULT_ACTION @ AddPostData(std::string key, std::string value) @ core->AddPostData(key,value);

ZZZState UZZState SetUrl(std::string url)
ZZZState ZPZState SetPost()
ZZZState ZGZState SetGet()

UZZState UGZState SetGet()
UZZState UPZState SetPost()

ZGZState UGZState SetUrl(std::string url)

ZPZState UPZState SetUrl(std::string url)
ZPZState ZPDState AddPostData(std::string key, std::string value)

UPZState UPDState AddPostData(std::string key, std::string value)

ZPDState ZPDState AddPostData(std::string key, std::string value)
ZPDState UPDState SetUrl(std::string url)

UPDState UPDState AddPostData(std::string key, std::string value)

0 comments on commit 18559c2

Please sign in to comment.