Skip to content

Commit

Permalink
Establish an abstract base class for compiler backends.
Browse files Browse the repository at this point in the history
  • Loading branch information
cpressey committed Feb 16, 2022
1 parent 7ab5898 commit 70e0e73
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 117 deletions.
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Castile 0.5

* Requesting the AST be dumped, will also dump the AST with
type assignments, if an error occurs during type checking.
* Established an abstract base class for compiler backends.

Castile 0.4
-----------
Expand Down
21 changes: 21 additions & 0 deletions src/castile/backends/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Abstract base class for Castile compiler backends,
especially source-to-source."""

class BaseCompiler(object):
def __init__(self, out):
self.out = out
self.indent = 0

def commas(self, asts, sep=','):
if asts:
for child in asts[:-1]:
self.compile(child)
self.out.write(sep)
self.compile(asts[-1])

def write(self, x):
self.out.write(x)

def write_indent(self, x):
self.out.write(' ' * self.indent)
self.out.write(x)
22 changes: 4 additions & 18 deletions src/castile/backends/c.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from castile.backends.base import BaseCompiler
from castile.transformer import VarDeclTypeAssigner
from castile.types import (
Integer, String, Void, Boolean, Function, Union, Struct
Expand All @@ -9,7 +10,7 @@
}

PRELUDE = r"""
/* AUTOMATICALLY GENERATED -- EDIT AT OWN RISK */
/* AUTOMATICALLY GENERATED -- EDIT AT YOUR OWN RISK */
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -81,27 +82,12 @@
"""


class Compiler(object):
class Compiler(BaseCompiler):
def __init__(self, out):
self.out = out
super(Compiler, self).__init__(out)
self.main_type = None
self.indent = 0
self.typecasing = set()

def commas(self, asts, sep=','):
if asts:
for child in asts[:-1]:
self.compile(child)
self.out.write(sep)
self.compile(asts[-1])

def write(self, x):
self.out.write(x)

def write_indent(self, x):
self.out.write(' ' * self.indent)
self.out.write(x)

# as used in local variable declarations
def c_type(self, type):
if type == Integer():
Expand Down
152 changes: 74 additions & 78 deletions src/castile/backends/javascript.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from castile.backends.base import BaseCompiler
from castile.types import Struct, Union

OPS = {
Expand All @@ -6,22 +7,8 @@
'==': '===',
}


class Compiler(object):
def __init__(self, out):
self.out = out

def commas(self, asts, sep=','):
if asts:
for child in asts[:-1]:
self.compile(child)
self.out.write(sep)
self.compile(asts[-1])

def compile(self, ast):
if ast.tag == 'Program':
self.out.write("""\
/* AUTOMATICALLY GENERATED -- EDIT AT OWN RISK */
PRELUDE = r"""
/* AUTOMATICALLY GENERATED -- EDIT AT YOUR OWN RISK */
/*
var stdin = process.openStdin();
Expand Down Expand Up @@ -60,154 +47,163 @@ def compile(self, ast):
{
return (tv1.tag === tv2.tag) && (tv1.value === tv2.value);
}
""")
for child in ast.children:
self.compile(child)
self.out.write("""\
"""

POSTLUDE = """\
var result = main();
if (result !== undefined && result !== null)
print(repr(result));
""")
"""


class Compiler(BaseCompiler):

def compile(self, ast):
if ast.tag == 'Program':
self.write(PRELUDE)
for child in ast.children:
self.compile(child)
self.write(POSTLUDE)
elif ast.tag == 'Defn':
self.out.write('var %s = ' % ast.value)
self.write('var %s = ' % ast.value)
self.compile(ast.children[0])
self.out.write(';\n')
self.write(';\n')
elif ast.tag == 'Forward':
pass
elif ast.tag == 'StructDefn':
field_defns = ast.children[0].children
self.out.write('function equal_%s(a, b) {\n' % ast.value)
self.write('function equal_%s(a, b) {\n' % ast.value)
for child in field_defns:
assert child.tag == 'FieldDefn', child.tag
struct_type = child.children[0].value if child.children[0].tag == 'StructType' else None
if struct_type:
self.out.write('if (!equal_%s(a.%s, b.%s)) return false;\n' % (struct_type, child.value, child.value))
self.write('if (!equal_%s(a.%s, b.%s)) return false;\n' % (struct_type, child.value, child.value))
else:
self.out.write('if (a.%s !== b.%s) return false;\n' % (child.value, child.value))
self.out.write('return true;\n')
self.out.write('}\n\n')
self.write('if (a.%s !== b.%s) return false;\n' % (child.value, child.value))
self.write('return true;\n')
self.write('}\n\n')
elif ast.tag == 'FunLit':
self.out.write('function(')
self.write('function(')
self.compile(ast.children[0])
self.out.write(')\n')
self.write(')\n')
self.compile(ast.children[1])
elif ast.tag == 'Args':
self.commas(ast.children)
elif ast.tag == 'Arg':
self.out.write(ast.value)
self.write(ast.value)
elif ast.tag == 'Body':
self.out.write('{')
self.write('{')
self.compile(ast.children[0])
assert ast.children[1].tag == 'Block'
block = ast.children[1]
for child in block.children:
self.compile(child)
self.out.write(';\n')
self.out.write('}')
self.write(';\n')
self.write('}')
elif ast.tag == 'VarDecls':
for child in ast.children:
self.compile(child)
elif ast.tag == 'VarDecl':
self.out.write('var %s;\n' % ast.value)
self.write('var %s;\n' % ast.value)
elif ast.tag == 'Block':
self.out.write('{')
self.write('{')
for child in ast.children:
self.compile(child)
self.out.write(';\n')
self.out.write('}')
self.write(';\n')
self.write('}')
elif ast.tag == 'While':
self.out.write('while (')
self.write('while (')
self.compile(ast.children[0])
self.out.write(')')
self.write(')')
self.compile(ast.children[1])
elif ast.tag == 'Op':
if ast.value == '==' and isinstance(ast.children[0].type, Struct):
self.out.write('equal_%s(' % ast.children[0].type.name)
self.write('equal_%s(' % ast.children[0].type.name)
self.compile(ast.children[0])
self.out.write(', ')
self.write(', ')
self.compile(ast.children[1])
self.out.write(')')
self.write(')')
elif ast.value == '==' and isinstance(ast.children[0].type, Union):
self.out.write('equal_tagged_value(')
self.write('equal_tagged_value(')
self.compile(ast.children[0])
self.out.write(', ')
self.write(', ')
self.compile(ast.children[1])
self.out.write(')')
self.write(')')
else:
self.out.write('(')
self.write('(')
self.compile(ast.children[0])
self.out.write(' %s ' % OPS.get(ast.value, ast.value))
self.write(' %s ' % OPS.get(ast.value, ast.value))
self.compile(ast.children[1])
self.out.write(')')
self.write(')')
elif ast.tag == 'VarRef':
self.out.write(ast.value)
self.write(ast.value)
elif ast.tag == 'FunCall':
self.compile(ast.children[0])
self.out.write('(')
self.write('(')
self.commas(ast.children[1:])
self.out.write(')')
self.write(')')
elif ast.tag == 'If':
self.out.write('if(')
self.write('if(')
self.compile(ast.children[0])
self.out.write(')')
self.write(')')
if len(ast.children) == 3: # if-else
self.compile(ast.children[1])
self.out.write(' else ')
self.write(' else ')
self.compile(ast.children[2])
else: # just-if
self.compile(ast.children[1])
elif ast.tag == 'Return':
self.out.write('return ')
self.write('return ')
self.compile(ast.children[0])
elif ast.tag == 'Break':
self.out.write('break')
self.write('break')
elif ast.tag == 'Not':
self.out.write('!(')
self.write('!(')
self.compile(ast.children[0])
self.out.write(')')
self.write(')')
elif ast.tag == 'None':
self.out.write('null')
self.write('null')
elif ast.tag == 'IntLit':
self.out.write(str(ast.value))
self.write(str(ast.value))
elif ast.tag == 'StrLit':
self.out.write("'%s'" % ast.value)
self.write("'%s'" % ast.value)
elif ast.tag == 'BoolLit':
if ast.value:
self.out.write("true")
self.write("true")
else:
self.out.write("false")
self.write("false")
elif ast.tag == 'Assignment':
self.compile(ast.children[0])
self.out.write(' = ')
self.write(' = ')
self.compile(ast.children[1])
elif ast.tag == 'Make':
self.out.write('{')
self.write('{')
self.commas(ast.children[1:])
self.out.write('}')
self.write('}')
elif ast.tag == 'FieldInit':
self.out.write("'%s':" % ast.value)
self.write("'%s':" % ast.value)
self.compile(ast.children[0])
elif ast.tag == 'Index':
self.compile(ast.children[0])
self.out.write('.%s' % ast.value)
self.write('.%s' % ast.value)
elif ast.tag == 'TypeCast':
self.out.write("['%s'," % str(ast.children[0].type))
self.write("['%s'," % str(ast.children[0].type))
self.compile(ast.children[0])
self.out.write(']')
self.write(']')
elif ast.tag == 'TypeCase':
self.out.write('if (')
self.write('if (')
self.compile(ast.children[0])
self.out.write("[0] == '%s')" % str(ast.children[1].type))
self.out.write('{ var save=')
self.write("[0] == '%s')" % str(ast.children[1].type))
self.write('{ var save=')
self.compile(ast.children[0])
self.out.write('; ')
self.write('; ')
self.compile(ast.children[0])
self.out.write('=')
self.write('=')
self.compile(ast.children[0])
self.out.write('[1]; ')
self.write('[1]; ')
self.compile(ast.children[2])
self.compile(ast.children[0])
self.out.write(' =save; }')
self.write(' =save; }')
else:
raise NotImplementedError(repr(ast))
25 changes: 5 additions & 20 deletions src/castile/backends/ruby.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from castile.backends.base import BaseCompiler


OPS = {
}

PRELUDE = """\
# AUTOMATICALLY GENERATED -- EDIT AT OWN RISK
# AUTOMATICALLY GENERATED -- EDIT AT YOUR OWN RISK
input = lambda { |s|
print(s)
Expand Down Expand Up @@ -64,25 +67,7 @@ def repr o
"""


class Compiler(object):
def __init__(self, out):
self.out = out
self.indent = 0

def commas(self, asts, sep=','):
if asts:
for child in asts[:-1]:
self.compile(child)
self.out.write(sep)
self.compile(asts[-1])

def write(self, x):
self.out.write(x)

def write_indent(self, x):
self.out.write(' ' * self.indent)
self.out.write(x)

class Compiler(BaseCompiler):
def mangle(self, ident):
if ident.startswith('next'):
return '{}_'.format(ident)
Expand Down
2 changes: 1 addition & 1 deletion src/castile/backends/stackmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def get_tag(self, value):
def compile(self, ast):
if ast.tag == 'Program':
self.out.write("""\
; AUTOMATICALLY GENERATED -- EDIT AT OWN RISK
; AUTOMATICALLY GENERATED -- EDIT AT YOUR OWN RISK
""")
for child in ast.children:
Expand Down

0 comments on commit 70e0e73

Please sign in to comment.