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