Skip to content

Instantly share code, notes, and snippets.

@brianv0
Last active March 22, 2016 20:41
Show Gist options
  • Save brianv0/291b112fbaf6c38fc564 to your computer and use it in GitHub Desktop.
Save brianv0/291b112fbaf6c38fc564 to your computer and use it in GitHub Desktop.
Simple IDL loosely based on capnproto
{%- macro safe_type(type) -%}
{%- if type in java_mappings -%}
{{ java_mappings[type] }}
{%- else -%}
{{ type }}
{%- endif -%}
{%- endmacro -%}
class {{ name }} {
{% for field in field_list %}
private {{ safe_type(field["type"]) }} {{ field["name"] }};
{% endfor %}
private {{ name }}(){
// Private Constructor
}
{% for field in field_list %}
public {{ safe_type(field["type"]) }} get{{ field["name"]|title }}(){
return {{ field["name"] }};
}
{% endfor %}
public static Builder newBuilder(){
return new Builder();
}
public static class Builder {
{% for field in field_list %}
private {{ safe_type(field["type"]) }} {{ field["name"] }};
{% endfor %}
{% for field in field_list %}
public Builder set{{ field["name"]|title }}({{ safe_type(field["type"]) }} val){
this.{{ field["name"] }} = val;
return this;
}
{% endfor %}
public {{ name }} build(){
{% set cc_name = name[0]|lower + name[1:] %}
// Validate
{% for field in field_list %}
{% if field["required"] %}
if(this.{{ field["name"] }} == null){
throw new IllegalArgumentException("{{ field['name'] }} must not be null");
}
{% endif %}
{% endfor %}
{{ name }} {{ cc_name }} = new {{ name }}();
{% for field in field_list %}
{{ cc_name }}.{{ field["name"] }} = this.{{ field["name"] }};
{% endfor %}
return {{ name[0]|lower }}{{ name[1:] }};
}
}
}
class {{ name }}:
def __init__(self, {{ field_list|join('=None, ', attribute='name') }}=None):
{% for field in field_list %}
self.{{ field["name"] }} = {{ field["name"] }}
{% endfor %}
{% for field in field_list %}
{% if field["required"] %}
if {{ field["name"] }} is None:
raise ValueError("{{ field['name'] }} must not be None")
{% endif %}
{% endfor %}
import ply.lex as lex
import ply.yacc as yacc
from jinja2 import Template
__author__ = 'bvan'
RESERVED = ('class', 'required', 'optional')
tokens = (
'ORDINAL','COLON','LBRACKET', 'RBRACKET',
#'TYPE','NUMBER','STRING','BOOLEAN', 'NULL',
#'EQ','LPAREN','RPAREN',
'COMMA','IDENT') + tuple(rsv.upper() for rsv in RESERVED)
#t_BOOLEAN = r'true|false'
#t_NULL = r'null|none'
#t_LPAREN = r'\('
#t_RPAREN = r'\)'
t_LBRACKET= r'\{'
t_RBRACKET= r'\}'
t_COMMA = r','
t_ORDINAL = r'@\d+'
t_COLON = r':'
def t_IDENT(t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
if t.value in RESERVED:
t.type = t.value.upper()
return t
def t_NUMBER(t):
r'[+-]?\d+(?:\.\d+)?(?:[eE][+-]\d+)?'
try:
t.value = int(t.value)
except ValueError:
try:
t.value = float(t.value)
except ValueError:
print("Number value too large %d", t.value)
t.value = 0
return t
def t_STRING(t):
r'''([durt]|ts)?'[^\r\n\'\\]*'|([durt]|ts)?"[^\r\n\"\\]*"'''
if(t.value[0] not in ('"',"'")):
print "special str"
t.value = t.value[1:-1]
return t
# Ignored characters
t_ignore = " \t"
def t_newline(t):
r'\n+'
t.lexer.lineno += t.value.count("\n")
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
# Build the lexer
def p_ast(p):
'ast : struct_list'
p[0] = p[1]
def p_struct_list(p):
'''struct_list : struct_list struct
| empty'''
p[0] = list_of(p)
def p_struct(p):
"""struct : CLASS ident LBRACKET field_list RBRACKET"""
p[0] = dict(type="class", name=p[2], field_list=p[4])
def p_field_list(p):
'''field_list : field_list field
| empty'''
p[0] = list_of(p)
def p_field(p):
'''field : requiredness IDENT ORDINAL COLON IDENT optional_comma'''
p[0] = dict(required=p[1], name=p[2], ordinal=p[3], type=p[5])
def p_optional_comma(p):
'''optional_comma : COMMA
| empty'''
pass
def p_requiredness(p):
"""requiredness : REQUIRED
| OPTIONAL
| empty"""
p[0] = p[1]
def p_ident(p):
'ident : IDENT'
p[0] = p[1]
# Error rule for syntax errors
def p_error(p):
print p
print "Syntax error in input!"
def p_empty(p):
'empty :'
pass
def list_of(p):
if len(p) == 3:
return (p[1] if p[1] else []) + [p[2]]
return []
lex.lex()
inp1 = "class MessageName {optional some_name @1 :i32, required value @2 :string,}"
lex.input(inp1)
print [str(repr(tok.type)) + ":" + str(repr(tok.value)) for tok in iter(lex.token, None)]
parser = yacc.yacc()
inp1 = "class MessageName {optional some_name @1 :i32, required value @2 :string,}"
print parser.parse(inp1)
inp1 = "class MessageName {some_name @1 :i32, required value @2 :string,}"
print parser.parse(inp1)
inp1 = "class M1 {m1n1 @1 :i32, required m1n2 @2 :string,} class M2 {m2n1 @1 :i32, required m2n2 @2 :string,}"
print parser.parse(inp1)
classes = parser.parse(inp1)
java_mappings = {
"string":"String",
"i32":"Integer",
"i64":"Long",
"float":"Float",
"double":"Double"
}
indent = lambda x: " "*(x*4)
t = Template(open("builder.j2").read(), trim_blocks=True, lstrip_blocks=True)
for clz in classes:
print t.render(java_mappings=java_mappings, **clz)
t = Template(open("builder.py.j2").read(), trim_blocks=True, lstrip_blocks=True)
for clz in classes:
print t.render(java_mappings=java_mappings, **clz)
@brianv0
Copy link
Author

brianv0 commented Mar 22, 2016

class M1 {
    private Integer m1n1;
    private String m1n2;

    private M1(){
        // Private Constructor
    }

    public Integer getM1n1(){
        return m1n1;
    }

    public String getM1n2(){
        return m1n2;
    }

    public static Builder newBuilder(){
        return new Builder();
    }

    public static class Builder {
        private Integer m1n1;
        private String m1n2;

        public Builder setM1n1(Integer val){
            this.m1n1 = val;
            return this;
        }

        public Builder setM1n2(String val){
            this.m1n2 = val;
            return this;
        }

        public M1 build(){
            // Validate
            if(this.m1n2 == null){
                throw new IllegalArgumentException("m1n2 must not be null");
            }

            M1 m1 = new M1();
            m1.m1n1 = this.m1n1;
            m1.m1n2 = this.m1n2;
            return m1;
        }
    }
}

class M2 {
    private Integer m2n1;
    private String m2n2;

    private M2(){
        // Private Constructor
    }

    public Integer getM2n1(){
        return m2n1;
    }

    public String getM2n2(){
        return m2n2;
    }

    public static Builder newBuilder(){
        return new Builder();
    }

    public static class Builder {
        private Integer m2n1;
        private String m2n2;

        public Builder setM2n1(Integer val){
            this.m2n1 = val;
            return this;
        }

        public Builder setM2n2(String val){
            this.m2n2 = val;
            return this;
        }

        public M2 build(){
            // Validate
            if(this.m2n2 == null){
                throw new IllegalArgumentException("m2n2 must not be null");
            }

            M2 m2 = new M2();
            m2.m2n1 = this.m2n1;
            m2.m2n2 = this.m2n2;
            return m2;
        }
    }
}
class M1:

    def __init__(self, m1n1=None, m1n2=None):
        self.m1n1 = m1n1
        self.m1n2 = m1n2
        if m1n2 is None:
            raise ValueError("m1n2 must not be None")


class M2:

    def __init__(self, m2n1=None, m2n2=None):
        self.m2n1 = m2n1
        self.m2n2 = m2n2
        if m2n2 is None:
            raise ValueError("m2n2 must not be None")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment