from castile.backends.base import BaseCompiler
from castile.types import Union
OPS = {
}
PRELUDE = """\
# AUTOMATICALLY GENERATED -- EDIT AT YOUR OWN RISK
input = lambda { |s|
print(s)
STDIN.gets.chomp
}
print = lambda { |s|
puts s
}
read = lambda { |n|
s = STDIN.read(n)
if s == nil then s = "" end
return s
}
write = lambda { |s|
STDOUT.write(s)
}
len = lambda { |s|
s.length
}
concat = lambda { |s1, s2|
s1 + s2
}
substr = lambda { |s, p, k|
s[p..p+(k-1)]
}
str = lambda { |n|
n.to_s
}
def repr o
if o == true
return "True"
elsif o == false
return "False"
elsif o == nil
return "None"
elsif o.is_a? String
return "'" + o + "'"
else
return o.to_s
end
end
"""
POSTLUDE = """\
result = main.call()
if result != nil
puts(repr(result))
end
"""
class Compiler(BaseCompiler):
def mangle(self, ident):
if ident.startswith('next'):
return '{}_'.format(ident)
return ident
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.write_indent('%s = ' % ast.value)
self.compile(ast.children[0])
self.write('\n')
elif ast.tag == 'Forward':
self.write_indent('%s = nil\n' % ast.value)
elif ast.tag == 'StructDefn':
pass
elif ast.tag == 'FunLit':
self.write_indent('lambda { |')
self.compile(ast.children[0])
self.write('|\n')
self.indent += 1
self.compile(ast.children[1])
self.write_indent('return nil\n')
self.indent -= 1
self.write_indent('}\n')
elif ast.tag == 'Args':
self.commas(ast.children)
elif ast.tag == 'Arg':
self.write(ast.value)
elif ast.tag == 'Body':
self.compile(ast.children[0])
self.compile(ast.children[1])
elif ast.tag == 'VarDecls':
for child in ast.children:
self.compile(child)
elif ast.tag == 'VarDecl':
self.write_indent('%s = nil;\n' % self.mangle(ast.value))
elif ast.tag == 'Block':
for child in ast.children:
self.compile(child)
self.write('\n')
elif ast.tag == 'While':
self.write_indent('while (')
self.compile(ast.children[0])
self.write(') do\n')
self.indent += 1
self.compile(ast.children[1])
self.indent -= 1
self.write_indent('end\n')
elif ast.tag == 'Op':
self.write('(')
self.compile(ast.children[0])
self.write(' %s ' % OPS.get(ast.value, ast.value))
self.compile(ast.children[1])
self.write(')')
elif ast.tag == 'VarRef':
self.write(self.mangle(ast.value))
elif ast.tag == 'FunCall':
self.compile(ast.children[0])
self.write('.call(')
self.commas(ast.children[1:])
self.write(')')
elif ast.tag == 'If':
self.write_indent('if (')
self.compile(ast.children[0])
self.write(') then\n')
if len(ast.children) == 3: # if-else
self.indent += 1
self.compile(ast.children[1])
self.indent -= 1
self.write_indent('else\n')
self.indent += 1
self.compile(ast.children[2])
self.indent -= 1
else: # just-if
self.indent += 1
self.compile(ast.children[1])
self.indent -= 1
self.write_indent('end\n')
elif ast.tag == 'Return':
self.write_indent('return ')
self.compile(ast.children[0])
elif ast.tag == 'Break':
self.write_indent('break')
elif ast.tag == 'Not':
self.write('!(')
self.compile(ast.children[0])
self.write(')')
elif ast.tag == 'None':
self.write('nil')
elif ast.tag == 'BoolLit':
if ast.value:
self.write("true")
else:
self.write("false")
elif ast.tag == 'IntLit':
self.write(str(ast.value))
elif ast.tag == 'StrLit':
self.write("'%s'" % ast.value)
elif ast.tag == 'Assignment':
self.write_indent('')
self.compile(ast.children[0])
self.write(' = ')
self.compile(ast.children[1])
elif ast.tag == 'Make':
self.write('{')
self.commas(ast.children[1:])
self.write('}')
elif ast.tag == 'FieldInit':
self.write("'%s'=>" % ast.value)
self.compile(ast.children[0])
elif ast.tag == 'Index':
self.compile(ast.children[0])
self.write('["%s"]' % ast.value)
elif ast.tag == 'TypeCast':
# If the LHS is not already a union type, promote it to a tagged value.
if isinstance(ast.children[0].type, Union):
self.compile(ast.children[0])
else:
self.write("['%s'," % str(ast.children[0].type))
self.compile(ast.children[0])
self.write(']')
elif ast.tag == 'TypeCase':
self.write_indent('if (')
self.compile(ast.children[0])
self.write("[0] == '%s')" % str(ast.children[1].type))
self.write(' then\n')
self.indent += 1
self.write_indent('save=')
self.compile(ast.children[0])
self.write('\n')
self.write_indent('')
self.compile(ast.children[0])
self.write('=')
self.compile(ast.children[0])
self.write('[1]\n')
self.compile(ast.children[2])
self.write_indent('')
self.compile(ast.children[0])
self.write(' = save\n')
self.indent -= 1
self.write_indent('end')
else:
raise NotImplementedError(repr(ast))