require 'erb' require_relative '../builder' require_relative './python_templates' module Shift module Generator class PythonGenerator attr_accessor :integer_attributes, :builder, :has_models, :defined_hashes def initialize() @integer_attributes = [] @defined_hashes = [] @has_models = false @builder = Shift::ShiftBuilder.new end def get_data_from_file(file_name) @builder.get_data_from_file file_name end def get_import_statements() Shift::Generator::PythonTemplates::IMPORT_WEBAPP_STATEMENT + "\n\n" + Shift::Generator::PythonTemplates::IMPORT_PYSTACHE_STATEMENT + "\n\n" + (@has_models ? Shift::Generator::PythonTemplates::IMPORT_DATABASE_STATEMENT + "\n\n" : "") + Shift::Generator::PythonTemplates::UTILITY_FUNCTIONS + "\n\n" end def get_model_data() result = "" model_name_template = ERB.new(Shift::Generator::PythonTemplates::MODEL_NAME_TEMPLATE) @builder.models.each do | model | model_name = model.name result += model_name_template.result(binding) + "\n" model.attributes.each do | attribute | if (attribute[:type] == "string") result += ("\t" + attribute[:name] + " = " + Shift::Generator::PythonTemplates::DB_STRING_PROPERTY + "\n") else if (attribute[:type] == "integer") @integer_attributes.push attribute[:name] result += ("\t" + attribute[:name] + " = " + Shift::Generator::PythonTemplates::DB_INTEGER_PROPERTY + "\n") end end end end result end def expression_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } key = statement.keys[0] case key when :assignment_statement extra = "" if(statement[:assignment_statement][:left].keys[0] == :hash_value) val = statement[:assignment_statement][:left][:hash_value].to_s hash_var = val[0..(val.index('[') - 1)] if !@defined_hashes.include?(hash_var) @defined_hashes.push hash_var extra += (tabs + "if (('" + hash_var + "' in locals()) == False):\n") extra += (tabs + "\t" + hash_var + " = {}\n") end end left = apply_transforms(statement[:assignment_statement][:left], 0) right = apply_transforms(statement[:assignment_statement][:right], 0) if(statement[:assignment_statement][:left].keys[0] == :object_value) value_name = statement[:assignment_statement][:left][:object_value].to_s value_name = value_name[(value_name.index('.') + 1)..(value_name.length - 1)] if(@integer_attributes.include?(value_name)) right = "int(" + right.to_s + ")" end end extra + tabs + left.to_s + " = " + right.to_s end end def token_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } key = statement.keys[0] case key when :identifier statement[:identifier].to_s when :object_value if (statement[:object_value].to_s.split(".")[1] == "save") tabs + statement[:object_value].to_s.split(".")[0] + ".put()" else tabs + statement[:object_value].to_s end when :hash_value statement[:hash_value].to_s when :string statement[:string].to_s else nil end end def query_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } statement = statement[:query] case statement[:operation].to_s when "all" (statement[:model_name].to_s + ".all().fetch(20)") when "new" (statement[:model_name].to_s + "()") when "find" # Todo.gql("WHERE priority=" + self.request.get('priority')).fetch(20) statement[:model_name].to_s + '.gql("WHERE ' + statement[:condition][:attribute].to_s + " " + statement[:condition][:operator].to_s + '"' + ' + ' + apply_transforms(statement[:condition][:value], 0) + ").fetch(20)" when "find_by_id" item_id = apply_transforms(statement[:item_id], 0) (statement[:model_name].to_s + ".get_by_id(int(" + item_id + "))") when "update" tabs + (statement[:model_name].to_s + ".put()") when "delete" tabs + (statement[:model_name].to_s + ".delete()") end end def write_function_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } write_data_template = ERB.new(Shift::Generator::PythonTemplates::WRITE_DATA_TEMPLATE) write_data = apply_transforms(statement[:write_statement][:write_statement_param], 0) tabs + write_data_template.result(binding) + "\n" + tabs + Shift::Generator::PythonTemplates::WRITE_RESPONSE_STATEMENT end def write_file_function_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } write_file_template = ERB.new(PythonTemplates::WRITE_FILE_TEMPLATE) if(statement[:write_file_statement].is_a?(Array)) file_name = apply_transforms(statement[:write_file_statement][0][:file_name], 0) template_values = apply_transforms(statement[:write_file_statement][1][:template_values], 0) else file_name = apply_transforms(statement[:write_file_statement][:file_name], 0) end tabs + write_file_template.result(binding) + "\n" + tabs + Shift::Generator::PythonTemplates::WRITE_RESPONSE_STATEMENT end def read_statement_transform(statement, num_tabs) read_statement_template = ERB.new(Shift::Generator::PythonTemplates::REQUEST_GET_VAR_TEMPLATE) var_name = apply_transforms(statement[:read_statement][:read_statement_param], 0) read_statement_template.result(binding) end def redirect_statement_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } redirect_statement_template = ERB.new(Shift::Generator::PythonTemplates::REDIRECT_STATEMENT_TEMPLATE) url = apply_transforms(statement[:redirect_statement][:redirect_statement_param], 0) "\n" + tabs + redirect_statement_template.result(binding) end def value_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } key = statement.keys[0] statement[key].to_s end def control_statement_transform(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } key = statement.keys[0] result = "" case key when :if_statement result = tabs + "if " + apply_transforms(statement[:if_statement][:condition], 0) + ":" when :while_statement result = tabs + "while " + apply_transforms(statement[:while_statement][:condition], 0) + ":" end result end def concatenated_string_expression_transform(statement, num_tabs) statement = statement.map do | token | apply_transforms(token, 0) end statement.join(" + ") end def integer_casted_expression_transform(statement, num_tabs) statement.delete(:int) "int(" + apply_transforms(statement, 0) + ")" end def apply_transforms(statement, num_tabs) tabs = "" num_tabs.times { tabs += "\t" } if(statement.is_a?(Hash)) key = statement.keys[0] case key when :assignment_statement expression_transform(statement, num_tabs) + "\n" when :write_statement write_function_transform(statement, num_tabs) + "\n" when :write_file_statement write_file_function_transform(statement, num_tabs) + "\n" when :read_statement read_statement_transform(statement, num_tabs) when :redirect_statement redirect_statement_transform(statement, num_tabs) when :arithmetic_expression value_transform(statement, num_tabs) when :boolean_expression value_transform(statement, num_tabs) when :if_statement control_statement_transform(statement, num_tabs) + "\n" when :else_statement tabs + value_transform(statement, num_tabs) + ":\n" when :for_statement tabs + value_transform(statement, num_tabs) + ":\n" when :while_statement control_statement_transform(statement, num_tabs) + "\n" when :query query_transform(statement, num_tabs) when :int integer_casted_expression_transform(statement, num_tabs) else token_transform(statement, num_tabs) end else if statement.is_a?(Array) concatenated_string_expression_transform(statement, num_tabs) else statement.to_s end end end def url_transform(url) if(url.is_a?(Array)) result_url = "" result_vars = "" url.each do | token | case token.keys[0] when :url_token result_url += "/" + token[:url_token].to_s when :url_variable result_url += "/(\\w+)" result_vars += ", " + token[:url_variable].to_s end end result = { :url => result_url, :vars => result_vars } else result = { :url => url.to_s, :vars => "" } end end def write_data() if (@builder.models.length != 0) @has_models = true end result = get_import_statements + get_model_data last_url = "" base_handler_name = "Handler" i = 0 routes = "" @builder.handlers.each do | handlers | url_info = url_transform(handlers.url) url = url_info[:url] @defined_hashes = [] if(url != last_url) handler_name = base_handler_name + i.to_s result += "\n\nclass " + handler_name + "(webapp2.RequestHandler):\n" i += 1 routes += "('" + url + "'," + handler_name + ")," end result += "\tdef " + handlers.method + "(self" + url_info[:vars] + "):\n" handlers.handler.each do | statement | result += apply_transforms(statement[:statement], statement[:num_tabs]) end last_url = url end app_template = ERB.new(Shift::Generator::PythonTemplates::WEBAPP2_APPLICATION_TEMPLATE) result += "\n\n\n" + app_template.result(binding) result end end end end