Last active
March 22, 2016 20:41
-
-
Save brianv0/291b112fbaf6c38fc564 to your computer and use it in GitHub Desktop.
Simple IDL loosely based on capnproto
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{%- 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:] }}; | |
} | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 %} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Author
brianv0
commented
Mar 22, 2016
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment