Begin work on inline / builtin functions.
This commit is contained in:
		
							parent
							
								
									5e93fa1963
								
							
						
					
					
						commit
						35b9c7651a
					
				
							
								
								
									
										21
									
								
								src/chalk/builtin.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/chalk/builtin.cr
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| module Chalk | ||||
|   class BuiltinFunction | ||||
|       getter param_count : Int32 | ||||
| 
 | ||||
|       def initialize(@param_count) | ||||
|       end | ||||
| 
 | ||||
|       def generate!(into) | ||||
|       end | ||||
|   end | ||||
| 
 | ||||
|   class InlineFunction | ||||
|       getter param_count : Int32 | ||||
|        | ||||
|       def initialize(@param_count) | ||||
|       end | ||||
| 
 | ||||
|       def generate!(codegen, params, table, target, free) | ||||
|       end | ||||
|   end | ||||
| end | ||||
| @ -4,9 +4,12 @@ require "./emitter.cr" | ||||
| module Chalk | ||||
|   class CodeGenerator | ||||
|     include Emitter | ||||
| 
 | ||||
|     RETURN_REG = 14 | ||||
|     STACK_REG  = 13 | ||||
| 
 | ||||
|     property instructions : Array(Instruction) | ||||
| 
 | ||||
|     def initialize(table, @function : TreeFunction) | ||||
|       @registers = 0 | ||||
|       @instructions = [] of Instruction | ||||
| @ -18,25 +21,12 @@ module Chalk | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def generate!(tree, table, target, free) | ||||
|       case tree | ||||
|       when TreeId | ||||
|         entry = table[tree.id]? | ||||
|         raise "Unknown variable" unless entry && | ||||
|                                         entry.is_a?(VarEntry) | ||||
|         loadr target, entry.register | ||||
|       when TreeLit | ||||
|         load target, tree.lit | ||||
|       when TreeOp | ||||
|         generate! tree.left, table, target, free | ||||
|         generate! tree.right, table, free, free + 1 | ||||
|         opr tree.op, target, free | ||||
|       when TreeCall | ||||
|         entry = table[tree.name]? | ||||
|         raise "Unknown function" unless entry && | ||||
|                                         entry.is_a?(FunctionEntry) | ||||
|         raise "Invalid call" if tree.params.size != entry.function.params.size | ||||
|     def generate!(tree, function : InlineFunction, table, target, free) | ||||
|         start = free | ||||
|         function.generate!(self, tree.params, table, target, free) | ||||
|     end | ||||
| 
 | ||||
|     def generate!(tree, function : TreeFunction | BuiltinFunction, table, target, free) | ||||
|         start_at = free | ||||
|         # Move I to stack | ||||
|         setis | ||||
| @ -71,6 +61,28 @@ module Chalk | ||||
|         restore (start_at - 1) unless start_at == 0 | ||||
|         # Get call value into target | ||||
|         loadr target, RETURN_REG | ||||
|     end | ||||
| 
 | ||||
|     def generate!(tree, table, target, free) | ||||
|       case tree | ||||
|       when TreeId | ||||
|         entry = table[tree.id]? | ||||
|         raise "Unknown variable" unless entry && | ||||
|                                         entry.is_a?(VarEntry) | ||||
|         loadr target, entry.register | ||||
|       when TreeLit | ||||
|         load target, tree.lit | ||||
|       when TreeOp | ||||
|         generate! tree.left, table, target, free | ||||
|         generate! tree.right, table, free, free + 1 | ||||
|         opr tree.op, target, free | ||||
|       when TreeCall | ||||
|         entry = table[tree.name]? | ||||
|         raise "Unknown function" unless entry && | ||||
|                                         entry.is_a?(FunctionEntry) | ||||
|         function = entry.function | ||||
|         raise "Invalid call" if tree.params.size != function.param_count | ||||
|         generate! tree, function, table, target, free | ||||
|       when TreeBlock | ||||
|         table = Table.new(table) | ||||
|         tree.children.each do |child| | ||||
| @ -110,13 +122,6 @@ module Chalk | ||||
|       return 0 | ||||
|     end | ||||
| 
 | ||||
|     private def check_dead(inst) | ||||
|       if inst.is_a?(LoadRegInstruction) | ||||
|         return inst.from == inst.into | ||||
|       end | ||||
|       return false | ||||
|     end | ||||
| 
 | ||||
|     def generate! | ||||
|       generate!(@function.block, @table, -1, @registers) | ||||
|       return @instructions | ||||
|  | ||||
| @ -43,6 +43,9 @@ module Chalk | ||||
|         table[tree.name] = FunctionEntry.new tree | ||||
|       end | ||||
|       @logger.debug("Done creating symbol table") | ||||
| 
 | ||||
|       table["draw"] = FunctionEntry.new InlineDrawFunction.new | ||||
|       table["get_key"] = FunctionEntry.new InlineAwaitKeyFunction.new | ||||
|       return table | ||||
|     end | ||||
| 
 | ||||
| @ -52,6 +55,12 @@ module Chalk | ||||
|       return generator.generate! | ||||
|     end | ||||
| 
 | ||||
|     private def create_code(tree : BuiltinFunction, table) | ||||
|       instructions = [] of Instruction | ||||
|       tree.generate!(instructions) | ||||
|       return instructions | ||||
|     end | ||||
| 
 | ||||
|     private def create_code(trees : Array(TreeFunction), table) | ||||
|       code = {} of String => Array(Instruction) | ||||
|       trees.each do |tree| | ||||
| @ -97,14 +106,16 @@ module Chalk | ||||
|       while !open.empty? | ||||
|         first = open.first | ||||
|         open.delete first | ||||
|         done << first | ||||
| 
 | ||||
|         entry = table[first]? | ||||
|         raise "Unknown function" unless entry && entry.is_a?(FunctionEntry) | ||||
|         next unless entry.function.is_a?(TreeFunction) | ||||
|         function = entry.function | ||||
|         next if function.is_a?(InlineFunction) | ||||
|         done << first | ||||
|         next unless function.is_a?(TreeFunction) | ||||
| 
 | ||||
|         visitor = CallVisitor.new | ||||
|         entry.function.accept(visitor) | ||||
|         function.accept(visitor) | ||||
|         open.concat(visitor.calls - done) | ||||
|       end | ||||
|       return done | ||||
| @ -118,14 +129,16 @@ module Chalk | ||||
|       names.delete "main" | ||||
| 
 | ||||
|       main_entry = table["main"]?.as(FunctionEntry) | ||||
|       all_instructions.concat create_code(main_entry.function, table) | ||||
|       all_instructions.concat create_code(main_entry.function.as(TreeFunction), table) | ||||
|       main_entry.addr = 0 | ||||
|       all_instructions << JumpRelativeInstruction.new 0 | ||||
| 
 | ||||
|       names.each do |name| | ||||
|         entry = table[name]?.as(FunctionEntry) | ||||
|         entry.addr = all_instructions.size | ||||
|         all_instructions.concat create_code(entry.function, table) | ||||
|         function = entry.function | ||||
|         raise "Trying to compile inlined function" if function.is_a?(InlineFunction) | ||||
|         all_instructions.concat create_code(function, table) | ||||
|         all_instructions << ReturnInstruction.new | ||||
|       end | ||||
| 
 | ||||
|  | ||||
| @ -1,72 +1,72 @@ | ||||
| module Chalk | ||||
|   module Emitter | ||||
|     private def load(into, value) | ||||
|     def load(into, value) | ||||
|       inst = LoadInstruction.new into, value.to_i32 | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def loadr(into, from) | ||||
|     def loadr(into, from) | ||||
|       inst = LoadRegInstruction.new into, from | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def op(op, into, from) | ||||
|     def op(op, into, from) | ||||
|       inst = OpInstruction.new op, into, from | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def opr(op, into, from) | ||||
|     def opr(op, into, from) | ||||
|       inst = OpRegInstruction.new op, into, from | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def sne(l, r) | ||||
|     def sne(l, r) | ||||
|       inst = SkipNeInstruction.new l, r | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def jr(o) | ||||
|     def jr(o) | ||||
|       inst = JumpRelativeInstruction.new o | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def store(up_to) | ||||
|     def store(up_to) | ||||
|       inst = StoreInstruction.new up_to | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def restore(up_to) | ||||
|     def restore(up_to) | ||||
|       inst = RestoreInstruction.new up_to | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def ret | ||||
|     def ret | ||||
|       inst = ReturnInstruction.new | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def call(func) | ||||
|     def call(func) | ||||
|       inst = CallInstruction.new func | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def setis | ||||
|     def setis | ||||
|       inst = SetIStackInstruction.new | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|     end | ||||
| 
 | ||||
|     private def addi(reg) | ||||
|     def addi(reg) | ||||
|       inst = AddIRegInstruction.new reg | ||||
|       @instructions << inst | ||||
|       return inst | ||||
|  | ||||
							
								
								
									
										26
									
								
								src/chalk/inline.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/chalk/inline.cr
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| module Chalk | ||||
|     class InlineDrawFunction < InlineFunction | ||||
|         def initialize | ||||
|             @param_count = 3 | ||||
|         end | ||||
| 
 | ||||
|         def generate!(emitter, params, table, target, free) | ||||
|             if !params[2].is_a?(TreeLit) | ||||
|                 raise "Third parameter must be a constant." | ||||
|             end | ||||
|             emitter.generate! params[0], table, free, free + 1 | ||||
|             emitter.generate! params[1], table, free + 1, free + 2 | ||||
|             emitter.instructions << DrawInstruction.new free, free + 1, params[2].as(TreeLit).lit.to_i32 | ||||
|         end | ||||
|     end | ||||
| 
 | ||||
|     class InlineAwaitKeyFunction < InlineFunction | ||||
|         def initialize | ||||
|             @param_count = 0 | ||||
|         end | ||||
| 
 | ||||
|         def generate!(emitter, params, table, target, free) | ||||
|             emitter.instructions << AwaitKeyInstruction.new target | ||||
|         end | ||||
|     end | ||||
| end | ||||
| @ -29,7 +29,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       0x6000 | (register << 8) | value | ||||
|       0x6000 | (@register << 8) | @value | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -48,7 +48,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       0x8000 | (into << 8) | (from << 4) | ||||
|       0x8000 | (@into << 8) | (@from << 4) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -69,7 +69,7 @@ module Chalk | ||||
|     def to_bin(i, index) | ||||
|       case op | ||||
|       when TokenType::OpAdd | ||||
|         return 0x7000 | (into << 8) | value | ||||
|         return 0x7000 | (@into << 8) | @value | ||||
|       else | ||||
|         raise "Invalid instruction" | ||||
|       end | ||||
| @ -107,7 +107,7 @@ module Chalk | ||||
|       else | ||||
|         raise "Invalid instruction" | ||||
|       end | ||||
|       return 0x8000 | (into << 8) | (from << 4) | code | ||||
|       return 0x8000 | (@into << 8) | (@from << 4) | code | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -123,7 +123,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0xf055 | (up_to << 8) | ||||
|       return 0xf055 | (@up_to << 8) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -139,7 +139,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0xf065 | (up_to << 8) | ||||
|       return 0xf065 | (@up_to << 8) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -167,7 +167,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0x1000 | ((offset + index) * 2 + 0x200) | ||||
|       return 0x1000 | ((@offset + index) * 2 + 0x200) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -185,7 +185,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0x3000 | (left << 8) | right | ||||
|       return 0x3000 | (@left << 8) | @right | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -203,7 +203,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0x4000 | (left << 8) | right | ||||
|       return 0x4000 | (@left << 8) | @right | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -222,7 +222,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0x5000 | (left << 8) | (right << 4) | ||||
|       return 0x5000 | (@left << 8) | (@right << 4) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -241,7 +241,7 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0x9000 | (left << 8) | (right << 4) | ||||
|       return 0x9000 | (@left << 8) | (@right << 4) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| @ -282,7 +282,40 @@ module Chalk | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|       return 0xf000 | (reg << 8) | 0x1e | ||||
|       return 0xf000 | (@reg << 8) | 0x1e | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   class DrawInstruction < Instruction | ||||
|     property x : Int32 | ||||
|     property y : Int32 | ||||
|     property height : Int32 | ||||
| 
 | ||||
|     def initialize(@x, @y, @height) | ||||
|     end | ||||
| 
 | ||||
|     def to_s(io) | ||||
|         io << "draw R" | ||||
|         x.to_s(16, io) | ||||
|         io << " R" | ||||
|         y.to_s(16, io) | ||||
|         io << " " << height | ||||
|     end | ||||
| 
 | ||||
|     def to_bin(i, index) | ||||
|         return 0xd000 | (@x << 8) | (@y << 4) | height | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   class AwaitKeyInstruction < Instruction | ||||
|     property into : Int32 | ||||
| 
 | ||||
|     def initialize(@into) | ||||
|     end | ||||
| 
 | ||||
|     def to_s(io) | ||||
|         io << "getk R" | ||||
|         @into.to_s(16, io) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| @ -4,6 +4,13 @@ module Chalk | ||||
|       @instructions = instructions.dup | ||||
|     end | ||||
| 
 | ||||
|     private def check_dead(inst) | ||||
|       if inst.is_a?(LoadRegInstruction) | ||||
|         return inst.from == inst.into | ||||
|       end | ||||
|       return false | ||||
|     end | ||||
| 
 | ||||
|     private def optimize!(range) | ||||
|       offset = 0 | ||||
|       range.each do |index| | ||||
|  | ||||
| @ -3,7 +3,7 @@ module Chalk | ||||
|   end | ||||
| 
 | ||||
|   class FunctionEntry < Entry | ||||
|     property function : TreeFunction | ||||
|     property function : TreeFunction | BuiltinFunction | InlineFunction | ||||
|     property addr : Int32 | ||||
| 
 | ||||
|     def initialize(@function, @addr = -1) | ||||
|  | ||||
| @ -109,6 +109,10 @@ module Chalk | ||||
|     def initialize(@name, @params, @block) | ||||
|     end | ||||
| 
 | ||||
|     def param_count | ||||
|       return @params.size | ||||
|     end | ||||
| 
 | ||||
|     def accept(v) | ||||
|       v.visit(self) | ||||
|       @block.accept(v) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user