Organize code into modules.
This commit is contained in:
parent
cd0e5c2919
commit
96059d6e04
|
@ -2,9 +2,9 @@ require "./chalk/*"
|
||||||
require "option_parser"
|
require "option_parser"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
config = Config.parse!
|
config = Ui::Config.parse!
|
||||||
exit unless config.validate!
|
exit unless config.validate!
|
||||||
|
|
||||||
compiler = Compiler.new config
|
compiler = Compiler::Compiler.new config
|
||||||
compiler.run
|
compiler.run
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Builtin
|
||||||
class BuiltinFunction
|
class BuiltinFunction
|
||||||
getter param_count : Int32
|
getter param_count : Int32
|
||||||
|
|
||||||
|
@ -18,4 +19,5 @@ module Chalk
|
||||||
def generate!(codegen, params, table, target, free)
|
def generate!(codegen, params, table, target, free)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,17 +2,18 @@ require "./ir.cr"
|
||||||
require "./emitter.cr"
|
require "./emitter.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Compiler
|
||||||
class CodeGenerator
|
class CodeGenerator
|
||||||
include Emitter
|
include Emitter
|
||||||
|
|
||||||
RETURN_REG = 14
|
RETURN_REG = 14
|
||||||
STACK_REG = 13
|
STACK_REG = 13
|
||||||
|
|
||||||
property instructions : Array(Instruction)
|
property instructions : Array(Ir::Instruction)
|
||||||
|
|
||||||
def initialize(table, @function : TreeFunction)
|
def initialize(table, @function : Trees::TreeFunction)
|
||||||
@registers = 0
|
@registers = 0
|
||||||
@instructions = [] of Instruction
|
@instructions = [] of Ir::Instruction
|
||||||
@table = Table.new table
|
@table = Table.new table
|
||||||
|
|
||||||
@function.params.each do |param|
|
@function.params.each do |param|
|
||||||
|
@ -21,11 +22,11 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate!(tree, function : InlineFunction, table, target, free)
|
def generate!(tree, function : Builtin::InlineFunction, table, target, free)
|
||||||
function.generate!(self, tree.params, table, target, free)
|
function.generate!(self, tree.params, table, target, free)
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate!(tree, function : TreeFunction | BuiltinFunction, table, target, free)
|
def generate!(tree, function : Trees::TreeFunction | Builtin::BuiltinFunction, table, target, free)
|
||||||
start_at = free
|
start_at = free
|
||||||
# Move I to stack
|
# Move I to stack
|
||||||
setis
|
setis
|
||||||
|
@ -64,30 +65,30 @@ module Chalk
|
||||||
|
|
||||||
def generate!(tree, table, target, free)
|
def generate!(tree, table, target, free)
|
||||||
case tree
|
case tree
|
||||||
when TreeId
|
when Trees::TreeId
|
||||||
entry = table[tree.id]?
|
entry = table[tree.id]?
|
||||||
raise "Unknown variable" unless entry &&
|
raise "Unknown variable" unless entry &&
|
||||||
entry.is_a?(VarEntry)
|
entry.is_a?(VarEntry)
|
||||||
loadr target, entry.register
|
loadr target, entry.register
|
||||||
when TreeLit
|
when Trees::TreeLit
|
||||||
load target, tree.lit
|
load target, tree.lit
|
||||||
when TreeOp
|
when Trees::TreeOp
|
||||||
generate! tree.left, table, target, free
|
generate! tree.left, table, target, free
|
||||||
generate! tree.right, table, free, free + 1
|
generate! tree.right, table, free, free + 1
|
||||||
opr tree.op, target, free
|
opr tree.op, target, free
|
||||||
when TreeCall
|
when Trees::TreeCall
|
||||||
entry = table[tree.name]?
|
entry = table[tree.name]?
|
||||||
raise "Unknown function" unless entry &&
|
raise "Unknown function" unless entry &&
|
||||||
entry.is_a?(FunctionEntry)
|
entry.is_a?(FunctionEntry)
|
||||||
function = entry.function
|
function = entry.function
|
||||||
raise "Invalid call" if tree.params.size != function.param_count
|
raise "Invalid call" if tree.params.size != function.param_count
|
||||||
generate! tree, function, table, target, free
|
generate! tree, function, table, target, free
|
||||||
when TreeBlock
|
when Trees::TreeBlock
|
||||||
table = Table.new(table)
|
table = Table.new(table)
|
||||||
tree.children.each do |child|
|
tree.children.each do |child|
|
||||||
free += generate! child, table, free, free + 1
|
free += generate! child, table, free, free + 1
|
||||||
end
|
end
|
||||||
when TreeVar
|
when Trees::TreeVar
|
||||||
entry = table[tree.name]?
|
entry = table[tree.name]?
|
||||||
if entry == nil
|
if entry == nil
|
||||||
entry = VarEntry.new free
|
entry = VarEntry.new free
|
||||||
|
@ -97,12 +98,12 @@ module Chalk
|
||||||
raise "Unknown variable" unless entry.is_a?(VarEntry)
|
raise "Unknown variable" unless entry.is_a?(VarEntry)
|
||||||
generate! tree.expr, table, entry.register, free
|
generate! tree.expr, table, entry.register, free
|
||||||
return 1
|
return 1
|
||||||
when TreeAssign
|
when Trees::TreeAssign
|
||||||
entry = table[tree.name]?
|
entry = table[tree.name]?
|
||||||
raise "Unknown variable" unless entry &&
|
raise "Unknown variable" unless entry &&
|
||||||
entry.is_a?(VarEntry)
|
entry.is_a?(VarEntry)
|
||||||
generate! tree.expr, table, entry.register, free
|
generate! tree.expr, table, entry.register, free
|
||||||
when TreeIf
|
when Trees::TreeIf
|
||||||
generate! tree.condition, table, free, free + 1
|
generate! tree.condition, table, free, free + 1
|
||||||
sne free, 0
|
sne free, 0
|
||||||
jump_inst = jr 0
|
jump_inst = jr 0
|
||||||
|
@ -115,7 +116,7 @@ module Chalk
|
||||||
old_size = @instructions.size
|
old_size = @instructions.size
|
||||||
generate! tree.otherwise, table, free, free + 1 if tree.otherwise
|
generate! tree.otherwise, table, free, free + 1 if tree.otherwise
|
||||||
jump_after.offset = @instructions.size - old_size + 1
|
jump_after.offset = @instructions.size - old_size + 1
|
||||||
when TreeWhile
|
when Trees::TreeWhile
|
||||||
before_cond = @instructions.size
|
before_cond = @instructions.size
|
||||||
generate! tree.condition, table, free, free + 1
|
generate! tree.condition, table, free, free + 1
|
||||||
sne free, 0
|
sne free, 0
|
||||||
|
@ -127,7 +128,7 @@ module Chalk
|
||||||
|
|
||||||
cond_jump.offset = @instructions.size - old_size + 1
|
cond_jump.offset = @instructions.size - old_size + 1
|
||||||
after_jump.offset = before_cond - instructions.size + 1
|
after_jump.offset = before_cond - instructions.size + 1
|
||||||
when TreeReturn
|
when Trees::TreeReturn
|
||||||
generate! tree.rvalue, table, RETURN_REG, free
|
generate! tree.rvalue, table, RETURN_REG, free
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
@ -139,4 +140,5 @@ module Chalk
|
||||||
return @instructions
|
return @instructions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,8 +3,9 @@ require "./constant_folder.cr"
|
||||||
require "./table.cr"
|
require "./table.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Compiler
|
||||||
class Compiler
|
class Compiler
|
||||||
def initialize(@config : Config)
|
def initialize(@config : Ui::Config)
|
||||||
@logger = Logger.new STDOUT
|
@logger = Logger.new STDOUT
|
||||||
@logger.debug("Initialized compiler")
|
@logger.debug("Initialized compiler")
|
||||||
@logger.level = Logger::DEBUG
|
@logger.level = Logger::DEBUG
|
||||||
|
@ -20,14 +21,14 @@ module Chalk
|
||||||
end
|
end
|
||||||
@logger.debug("Finished tokenizing")
|
@logger.debug("Finished tokenizing")
|
||||||
@logger.debug("Beginning parsing")
|
@logger.debug("Beginning parsing")
|
||||||
parser = Parser.new
|
parser = ParserCombinators::Parser.new
|
||||||
if trees = parser.parse?(tokens)
|
if trees = parser.parse?(tokens)
|
||||||
@logger.debug("Finished parsing")
|
@logger.debug("Finished parsing")
|
||||||
@logger.debug("Beginning constant folding")
|
@logger.debug("Beginning constant folding")
|
||||||
folder = ConstantFolder.new
|
folder = Trees::ConstantFolder.new
|
||||||
trees.map! do |tree|
|
trees.map! do |tree|
|
||||||
@logger.debug("Constant folding #{tree.name}")
|
@logger.debug("Constant folding #{tree.name}")
|
||||||
tree.apply(folder).as(TreeFunction)
|
tree.apply(folder).as(Trees::TreeFunction)
|
||||||
end
|
end
|
||||||
@logger.debug("Done constant folding")
|
@logger.debug("Done constant folding")
|
||||||
return trees
|
return trees
|
||||||
|
@ -44,15 +45,15 @@ module Chalk
|
||||||
end
|
end
|
||||||
@logger.debug("Done creating symbol table")
|
@logger.debug("Done creating symbol table")
|
||||||
|
|
||||||
table["draw"] = FunctionEntry.new InlineDrawFunction.new
|
table["draw"] = FunctionEntry.new Builtin::InlineDrawFunction.new
|
||||||
table["get_key"] = FunctionEntry.new InlineAwaitKeyFunction.new
|
table["get_key"] = FunctionEntry.new Builtin::InlineAwaitKeyFunction.new
|
||||||
table["get_font"] = FunctionEntry.new InlineGetFontFunction.new
|
table["get_font"] = FunctionEntry.new Builtin::InlineGetFontFunction.new
|
||||||
table["set_delay"] = FunctionEntry.new InlineSetDelayFunction.new
|
table["set_delay"] = FunctionEntry.new Builtin::InlineSetDelayFunction.new
|
||||||
table["get_delay"] = FunctionEntry.new InlineGetDelayFunction.new
|
table["get_delay"] = FunctionEntry.new Builtin::InlineGetDelayFunction.new
|
||||||
return table
|
return table
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_code(tree : TreeFunction, table, instruction = ReturnInstruction.new)
|
private def create_code(tree : Trees::TreeFunction, table, instruction = Ir::ReturnInstruction.new)
|
||||||
optimizer = Optimizer.new
|
optimizer = Optimizer.new
|
||||||
generator = CodeGenerator.new table, tree
|
generator = CodeGenerator.new table, tree
|
||||||
@logger.debug("Generating code for #{tree.name}")
|
@logger.debug("Generating code for #{tree.name}")
|
||||||
|
@ -61,14 +62,14 @@ module Chalk
|
||||||
return optimizer.optimize(code)
|
return optimizer.optimize(code)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_code(tree : BuiltinFunction, table, instruction = nil)
|
private def create_code(tree : Builtin::BuiltinFunction, table, instruction = nil)
|
||||||
instructions = [] of Instruction
|
instructions = [] of Ir::Instruction
|
||||||
tree.generate!(instructions)
|
tree.generate!(instructions)
|
||||||
return instructions
|
return instructions
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_code(trees : Array(TreeFunction), table)
|
private def create_code(trees : Array(Trees::TreeFunction), table)
|
||||||
code = {} of String => Array(Instruction)
|
code = {} of String => Array(Ir::Instruction)
|
||||||
trees.each do |tree|
|
trees.each do |tree|
|
||||||
code[tree.name] = create_code(tree, table)
|
code[tree.name] = create_code(tree, table)
|
||||||
end
|
end
|
||||||
|
@ -94,7 +95,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
private def generate_binary(table, instructions, dest)
|
private def generate_binary(table, instructions, dest)
|
||||||
context = InstructionContext.new table, instructions.size
|
context = Ir::InstructionContext.new table, instructions.size
|
||||||
binary = instructions.map_with_index { |it, i| it.to_bin(context, i).to_u16 }
|
binary = instructions.map_with_index { |it, i| it.to_bin(context, i).to_u16 }
|
||||||
binary.each do |inst|
|
binary.each do |inst|
|
||||||
first = (inst >> 8).to_u8
|
first = (inst >> 8).to_u8
|
||||||
|
@ -116,11 +117,11 @@ module Chalk
|
||||||
entry = table[first]?
|
entry = table[first]?
|
||||||
raise "Unknown function" unless entry && entry.is_a?(FunctionEntry)
|
raise "Unknown function" unless entry && entry.is_a?(FunctionEntry)
|
||||||
function = entry.function
|
function = entry.function
|
||||||
next if function.is_a?(InlineFunction)
|
next if function.is_a?(Builtin::InlineFunction)
|
||||||
done << first
|
done << first
|
||||||
next unless function.is_a?(TreeFunction)
|
next unless function.is_a?(Trees::TreeFunction)
|
||||||
|
|
||||||
visitor = CallVisitor.new
|
visitor = Trees::CallVisitor.new
|
||||||
function.accept(visitor)
|
function.accept(visitor)
|
||||||
open.concat(visitor.calls - done)
|
open.concat(visitor.calls - done)
|
||||||
end
|
end
|
||||||
|
@ -128,24 +129,24 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
private def run_binary
|
private def run_binary
|
||||||
all_instructions = [] of Instruction
|
all_instructions = [] of Ir::Instruction
|
||||||
trees = create_trees(@config.file)
|
trees = create_trees(@config.file)
|
||||||
table = create_table(trees)
|
table = create_table(trees)
|
||||||
names = collect_calls(table)
|
names = collect_calls(table)
|
||||||
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.as(TreeFunction),
|
all_instructions.concat create_code(main_entry.function.as(Trees::TreeFunction),
|
||||||
table, JumpRelativeInstruction.new 0)
|
table, Ir::JumpRelativeInstruction.new 0)
|
||||||
main_entry.addr = 0
|
main_entry.addr = 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
|
||||||
function = entry.function
|
function = entry.function
|
||||||
raise "Trying to compile inlined function" if function.is_a?(InlineFunction)
|
raise "Trying to compile inlined function" if function.is_a?(Builtin::InlineFunction)
|
||||||
all_instructions.concat create_code(function, table)
|
all_instructions.concat create_code(function, table)
|
||||||
all_instructions << ReturnInstruction.new
|
all_instructions << Ir::ReturnInstruction.new
|
||||||
end
|
end
|
||||||
|
|
||||||
file = File.open("out.ch8", "w")
|
file = File.open("out.ch8", "w")
|
||||||
|
@ -155,13 +156,14 @@ module Chalk
|
||||||
|
|
||||||
def run
|
def run
|
||||||
case @config.mode
|
case @config.mode
|
||||||
when OutputMode::Tree
|
when Ui::OutputMode::Tree
|
||||||
run_tree
|
run_tree
|
||||||
when OutputMode::Intermediate
|
when Ui::OutputMode::Intermediate
|
||||||
run_intermediate
|
run_intermediate
|
||||||
when OutputMode::Binary
|
when Ui::OutputMode::Binary
|
||||||
run_binary
|
run_binary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Ui
|
||||||
enum OutputMode
|
enum OutputMode
|
||||||
Tree,
|
Tree,
|
||||||
Intermediate,
|
Intermediate,
|
||||||
|
@ -48,4 +49,5 @@ module Chalk
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,33 +1,35 @@
|
||||||
require "./tree.cr"
|
require "./tree.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Trees
|
||||||
class ConstantFolder < Transformer
|
class ConstantFolder < Transformer
|
||||||
private def perform_op(op, left, right)
|
private def perform_op(op, left, right)
|
||||||
case op
|
case op
|
||||||
when TokenType::OpAdd
|
when Compiler::TokenType::OpAdd
|
||||||
left + right
|
left + right
|
||||||
when TokenType::OpSub
|
when Compiler::TokenType::OpSub
|
||||||
left - right
|
left - right
|
||||||
when TokenType::OpMul
|
when Compiler::TokenType::OpMul
|
||||||
left*right
|
left*right
|
||||||
when TokenType::OpDiv
|
when Compiler::TokenType::OpDiv
|
||||||
left/right
|
left/right
|
||||||
when TokenType::OpAnd
|
when Compiler::TokenType::OpAnd
|
||||||
left & right
|
left & right
|
||||||
when TokenType::OpOr
|
when Compiler::TokenType::OpOr
|
||||||
left | right
|
left | right
|
||||||
else TokenType::OpXor
|
else Compiler::TokenType::OpXor
|
||||||
left ^ right
|
left ^ right
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform(tree : TreeOp)
|
def transform(tree : Trees::TreeOp)
|
||||||
if tree.left.is_a?(TreeLit) && tree.right.is_a?(TreeLit)
|
if tree.left.is_a?(Trees::TreeLit) && tree.right.is_a?(Trees::TreeLit)
|
||||||
return TreeLit.new perform_op(tree.op,
|
return Trees::TreeLit.new perform_op(tree.op,
|
||||||
tree.left.as(TreeLit).lit,
|
tree.left.as(Trees::TreeLit).lit,
|
||||||
tree.right.as(TreeLit).lit)
|
tree.right.as(Trees::TreeLit).lit)
|
||||||
end
|
end
|
||||||
return tree
|
return tree
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,75 +1,77 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Compiler
|
||||||
module Emitter
|
module Emitter
|
||||||
def load(into, value)
|
def load(into, value)
|
||||||
inst = LoadInstruction.new into, value.to_i32
|
inst = Ir::LoadInstruction.new into, value.to_i32
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def loadr(into, from)
|
def loadr(into, from)
|
||||||
inst = LoadRegInstruction.new into, from
|
inst = Ir::LoadRegInstruction.new into, from
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def op(op, into, from)
|
def op(op, into, from)
|
||||||
inst = OpInstruction.new op, into, from
|
inst = Ir::OpInstruction.new op, into, from
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def opr(op, into, from)
|
def opr(op, into, from)
|
||||||
inst = OpRegInstruction.new op, into, from
|
inst = Ir::OpRegInstruction.new op, into, from
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def sne(l, r)
|
def sne(l, r)
|
||||||
inst = SkipNeInstruction.new l, r
|
inst = Ir::SkipNeInstruction.new l, r
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def jr(o)
|
def jr(o)
|
||||||
inst = JumpRelativeInstruction.new o
|
inst = Ir::JumpRelativeInstruction.new o
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def store(up_to)
|
def store(up_to)
|
||||||
inst = StoreInstruction.new up_to
|
inst = Ir::StoreInstruction.new up_to
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def restore(up_to)
|
def restore(up_to)
|
||||||
inst = RestoreInstruction.new up_to
|
inst = Ir::RestoreInstruction.new up_to
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def ret
|
def ret
|
||||||
inst = ReturnInstruction.new
|
inst = Ir::ReturnInstruction.new
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(func)
|
def call(func)
|
||||||
inst = CallInstruction.new func
|
inst = Ir::CallInstruction.new func
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def setis
|
def setis
|
||||||
inst = SetIStackInstruction.new
|
inst = Ir::SetIStackInstruction.new
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
|
|
||||||
def addi(reg)
|
def addi(reg)
|
||||||
inst = AddIRegInstruction.new reg
|
inst = Ir::AddIRegInstruction.new reg
|
||||||
@instructions << inst
|
@instructions << inst
|
||||||
return inst
|
return inst
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Trees
|
||||||
class CallVisitor < Visitor
|
class CallVisitor < Visitor
|
||||||
property calls : Set(String)
|
property calls : Set(String)
|
||||||
|
|
||||||
|
@ -10,4 +11,5 @@ module Chalk
|
||||||
@calls << t.name
|
@calls << t.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Builtin
|
||||||
class InlineDrawFunction < InlineFunction
|
class InlineDrawFunction < InlineFunction
|
||||||
def initialize
|
def initialize
|
||||||
@param_count = 3
|
@param_count = 3
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
if !params[2].is_a?(TreeLit)
|
if !params[2].is_a?(Trees::TreeLit)
|
||||||
raise "Third parameter must be a constant."
|
raise "Third parameter must be a constant."
|
||||||
end
|
end
|
||||||
emitter.generate! params[0], table, free, free + 1
|
emitter.generate! params[0], table, free, free + 1
|
||||||
emitter.generate! params[1], table, free + 1, free + 2
|
emitter.generate! params[1], table, free + 1, free + 2
|
||||||
emitter.instructions << DrawInstruction.new free, free + 1, params[2].as(TreeLit).lit.to_i32
|
emitter.instructions << Ir::DrawInstruction.new free, free + 1, params[2].as(Trees::TreeLit).lit.to_i32
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.instructions << AwaitKeyInstruction.new target
|
emitter.instructions << Ir::AwaitKeyInstruction.new target
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ module Chalk
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.generate! params[0], table, free, free + 1
|
emitter.generate! params[0], table, free, free + 1
|
||||||
emitter.instructions << GetFontInstruction.new free
|
emitter.instructions << Ir::GetFontInstruction.new free
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ module Chalk
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.generate! params[0], table, free, free + 1
|
emitter.generate! params[0], table, free, free + 1
|
||||||
emitter.instructions << SetDelayTimerInstruction.new free
|
emitter.instructions << Ir::SetDelayTimerInstruction.new free
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +53,8 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.instructions << GetDelayTimerInstruction.new target
|
emitter.instructions << Ir::GetDelayTimerInstruction.new target
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require "./lexer.cr"
|
require "./lexer.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Ir
|
||||||
class Instruction
|
class Instruction
|
||||||
def to_bin(i, index)
|
def to_bin(i, index)
|
||||||
return 0
|
return 0
|
||||||
|
@ -8,7 +9,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
class InstructionContext
|
class InstructionContext
|
||||||
property table : Table
|
property table : Compiler::Table
|
||||||
property stack : Int32
|
property stack : Int32
|
||||||
|
|
||||||
def initialize(@table, @stack)
|
def initialize(@table, @stack)
|
||||||
|
@ -53,7 +54,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
class OpInstruction < Instruction
|
class OpInstruction < Instruction
|
||||||
property op : TokenType
|
property op : Compiler::TokenType
|
||||||
property into : Int32
|
property into : Int32
|
||||||
property value : Int32
|
property value : Int32
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ module Chalk
|
||||||
|
|
||||||
def to_bin(i, index)
|
def to_bin(i, index)
|
||||||
case op
|
case op
|
||||||
when TokenType::OpAdd
|
when Compiler::TokenType::OpAdd
|
||||||
return 0x7000 | (@into << 8) | @value
|
return 0x7000 | (@into << 8) | @value
|
||||||
else
|
else
|
||||||
raise "Invalid instruction"
|
raise "Invalid instruction"
|
||||||
|
@ -77,7 +78,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
class OpRegInstruction < Instruction
|
class OpRegInstruction < Instruction
|
||||||
property op : TokenType
|
property op : Compiler::TokenType
|
||||||
property into : Int32
|
property into : Int32
|
||||||
property from : Int32
|
property from : Int32
|
||||||
|
|
||||||
|
@ -94,15 +95,15 @@ module Chalk
|
||||||
def to_bin(i, index)
|
def to_bin(i, index)
|
||||||
code = 0
|
code = 0
|
||||||
case op
|
case op
|
||||||
when TokenType::OpAdd
|
when Compiler::TokenType::OpAdd
|
||||||
code = 4
|
code = 4
|
||||||
when TokenType::OpSub
|
when Compiler::TokenType::OpSub
|
||||||
code = 5
|
code = 5
|
||||||
when TokenType::OpOr
|
when Compiler::TokenType::OpOr
|
||||||
code = 1
|
code = 1
|
||||||
when TokenType::OpAnd
|
when Compiler::TokenType::OpAnd
|
||||||
code = 2
|
code = 2
|
||||||
when TokenType::OpXor
|
when Compiler::TokenType::OpXor
|
||||||
code = 3
|
code = 3
|
||||||
else
|
else
|
||||||
raise "Invalid instruction"
|
raise "Invalid instruction"
|
||||||
|
@ -256,7 +257,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_bin(i, index)
|
def to_bin(i, index)
|
||||||
return 0x2000 | (i.table[name]?.as(FunctionEntry).addr * 2 + 0x200)
|
return 0x2000 | (i.table[name]?.as(Compiler::FunctionEntry).addr * 2 + 0x200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -370,4 +371,5 @@ module Chalk
|
||||||
return 0xf007 | (@into << 8)
|
return 0xf007 | (@into << 8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require "lex"
|
require "lex"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Compiler
|
||||||
enum TokenType
|
enum TokenType
|
||||||
Any,
|
Any,
|
||||||
Str,
|
Str,
|
||||||
|
@ -79,4 +80,5 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Compiler
|
||||||
class Optimizer
|
class Optimizer
|
||||||
private def check_dead(inst)
|
private def check_dead(inst)
|
||||||
if inst.is_a?(LoadRegInstruction)
|
if inst.is_a?(Ir::LoadRegInstruction)
|
||||||
return inst.from == inst.into
|
return inst.from == inst.into
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
|
@ -20,7 +21,7 @@ module Chalk
|
||||||
instructions = instructions.dup
|
instructions = instructions.dup
|
||||||
block_boundaries = [instructions.size]
|
block_boundaries = [instructions.size]
|
||||||
instructions.each_with_index do |inst, i|
|
instructions.each_with_index do |inst, i|
|
||||||
if inst.is_a?(JumpRelativeInstruction)
|
if inst.is_a?(Ir::JumpRelativeInstruction)
|
||||||
block_boundaries << i
|
block_boundaries << i
|
||||||
block_boundaries << (inst.offset + i)
|
block_boundaries << (inst.offset + i)
|
||||||
end
|
end
|
||||||
|
@ -37,7 +38,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
instructions.each_with_index do |inst, i|
|
instructions.each_with_index do |inst, i|
|
||||||
next if !inst.is_a?(JumpRelativeInstruction)
|
next if !inst.is_a?(Ir::JumpRelativeInstruction)
|
||||||
jump_to = inst.offset + i
|
jump_to = inst.offset + i
|
||||||
next unless deletions_at[jump_to]?
|
next unless deletions_at[jump_to]?
|
||||||
deletions_offset = deletions_at[i] - deletions_at[jump_to]
|
deletions_offset = deletions_at[i] - deletions_at[jump_to]
|
||||||
|
@ -52,4 +53,5 @@ module Chalk
|
||||||
return instructions
|
return instructions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
require "./parser_builder.cr"
|
require "./parser_builder.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module ParserCombinators
|
||||||
class Parser
|
class Parser
|
||||||
include ParserBuilder
|
include ParserBuilder
|
||||||
|
|
||||||
private def create_type
|
private def create_type
|
||||||
either(type(TokenType::KwU0), type(TokenType::KwU8), type(TokenType::KwU12))
|
either(type(Compiler::TokenType::KwU0), type(Compiler::TokenType::KwU8), type(Compiler::TokenType::KwU12))
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_lit
|
private def create_lit
|
||||||
dec_parser = type(TokenType::LitDec).transform &.string.to_i64
|
dec_parser = type(Compiler::TokenType::LitDec).transform &.string.to_i64
|
||||||
hex_parser = type(TokenType::LitHex).transform &.string.lchop("0x").to_i64(16)
|
hex_parser = type(Compiler::TokenType::LitHex).transform &.string.lchop("0x").to_i64(16)
|
||||||
bin_parser = type(TokenType::LitBin).transform &.string.lchop("0b").to_i64(2)
|
bin_parser = type(Compiler::TokenType::LitBin).transform &.string.lchop("0b").to_i64(2)
|
||||||
lit_parser = either(dec_parser, hex_parser, bin_parser).transform { |it| TreeLit.new(it).as(Tree) }
|
lit_parser = either(dec_parser, hex_parser, bin_parser).transform { |it| Trees::TreeLit.new(it).as(Trees::Tree) }
|
||||||
return lit_parser
|
return lit_parser
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_op_expr(atom, op)
|
private def create_op_expr(atom, op)
|
||||||
pl = PlaceholderParser(Tree).new
|
pl = PlaceholderParser(Trees::Tree).new
|
||||||
recurse = atom.then(op).then(pl).transform do |arr|
|
recurse = atom.then(op).then(pl).transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
TreeOp.new(
|
Trees::TreeOp.new(
|
||||||
arr[1].as(Token).type,
|
arr[1].as(Compiler::Token).type,
|
||||||
arr[0].as(Tree),
|
arr[0].as(Trees::Tree),
|
||||||
arr[2].as(Tree)).as(Tree)
|
arr[2].as(Trees::Tree)).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
pl.parser = either(recurse, atom)
|
pl.parser = either(recurse, atom)
|
||||||
return pl
|
return pl
|
||||||
|
@ -36,27 +37,27 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_call(expr)
|
private def create_call(expr)
|
||||||
call = type(TokenType::Id).then(char '(').then(delimited(expr, char ',')).then(char ')').transform do |arr|
|
call = type(Compiler::TokenType::Id).then(char '(').then(delimited(expr, char ',')).then(char ')').transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
name = arr[0].as(Token).string
|
name = arr[0].as(Compiler::Token).string
|
||||||
params = arr[2..arr.size - 2].map &.as(Tree)
|
params = arr[2..arr.size - 2].map &.as(Trees::Tree)
|
||||||
TreeCall.new(name, params).as(Tree)
|
Trees::TreeCall.new(name, params).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return call
|
return call
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_expr
|
private def create_expr
|
||||||
expr_place = PlaceholderParser(Tree).new
|
expr_place = PlaceholderParser(Trees::Tree).new
|
||||||
literal = create_lit
|
literal = create_lit
|
||||||
id = type(TokenType::Id).transform { |it| TreeId.new(it.string).as(Tree) }
|
id = type(Compiler::TokenType::Id).transform { |it| Trees::TreeId.new(it.string).as(Trees::Tree) }
|
||||||
call = create_call(expr_place)
|
call = create_call(expr_place)
|
||||||
atom = either(literal, call, id)
|
atom = either(literal, call, id)
|
||||||
|
|
||||||
ops = [either(type(TokenType::OpMul), type(TokenType::OpDiv)),
|
ops = [either(type(Compiler::TokenType::OpMul), type(Compiler::TokenType::OpDiv)),
|
||||||
either(type(TokenType::OpAdd), type(TokenType::OpSub)),
|
either(type(Compiler::TokenType::OpAdd), type(Compiler::TokenType::OpSub)),
|
||||||
type(TokenType::OpXor),
|
type(Compiler::TokenType::OpXor),
|
||||||
type(TokenType::OpAnd),
|
type(Compiler::TokenType::OpAnd),
|
||||||
type(TokenType::OpOr)]
|
type(Compiler::TokenType::OpOr)]
|
||||||
expr = create_op_exprs(atom, ops)
|
expr = create_op_exprs(atom, ops)
|
||||||
expr_place.parser = expr
|
expr_place.parser = expr
|
||||||
|
|
||||||
|
@ -64,60 +65,60 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_var(expr)
|
private def create_var(expr)
|
||||||
var = type(TokenType::KwVar).then(type(TokenType::Id)).then(char '=').then(expr).then(char ';').transform do |arr|
|
var = type(Compiler::TokenType::KwVar).then(type(Compiler::TokenType::Id)).then(char '=').then(expr).then(char ';').transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
name = arr[1].as(Token).string
|
name = arr[1].as(Compiler::Token).string
|
||||||
exp = arr[arr.size - 2].as(Tree)
|
exp = arr[arr.size - 2].as(Trees::Tree)
|
||||||
TreeVar.new(name, exp).as(Tree)
|
Trees::TreeVar.new(name, exp).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return var
|
return var
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_assign(expr)
|
private def create_assign(expr)
|
||||||
assign = type(TokenType::Id).then(char '=').then(expr).then(char ';').transform do |arr|
|
assign = type(Compiler::TokenType::Id).then(char '=').then(expr).then(char ';').transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
name = arr[0].as(Token).string
|
name = arr[0].as(Compiler::Token).string
|
||||||
exp = arr[arr.size - 2].as(Tree)
|
exp = arr[arr.size - 2].as(Trees::Tree)
|
||||||
TreeAssign.new(name, exp).as(Tree)
|
Trees::TreeAssign.new(name, exp).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return assign
|
return assign
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_basic(expr)
|
private def create_basic(expr)
|
||||||
basic = expr.then(char ';').transform do |arr|
|
basic = expr.then(char ';').transform do |arr|
|
||||||
arr.flatten[0].as(Tree)
|
arr.flatten[0].as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return basic
|
return basic
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_if(expr, block)
|
private def create_if(expr, block)
|
||||||
iff = type(TokenType::KwIf).then(char '(').then(expr).then(char ')').then(block)
|
iff = type(Compiler::TokenType::KwIf).then(char '(').then(expr).then(char ')').then(block)
|
||||||
.then(optional(type(TokenType::KwElse).then(block)))
|
.then(optional(type(Compiler::TokenType::KwElse).then(block)))
|
||||||
.transform do |arr|
|
.transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
cond = arr[2].as(Tree)
|
cond = arr[2].as(Trees::Tree)
|
||||||
code = arr[4].as(Tree)
|
code = arr[4].as(Trees::Tree)
|
||||||
otherwise = arr.size == 7 ? arr[6].as(Tree) : nil
|
otherwise = arr.size == 7 ? arr[6].as(Trees::Tree) : nil
|
||||||
TreeIf.new(cond, code, otherwise).as(Tree)
|
Trees::TreeIf.new(cond, code, otherwise).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return iff
|
return iff
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_while(expr, block)
|
private def create_while(expr, block)
|
||||||
whilee = type(TokenType::KwWhile).then(char '(').then(expr).then(char ')').then(block).transform do |arr|
|
whilee = type(Compiler::TokenType::KwWhile).then(char '(').then(expr).then(char ')').then(block).transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
cond = arr[2].as(Tree)
|
cond = arr[2].as(Trees::Tree)
|
||||||
code = arr[4].as(Tree)
|
code = arr[4].as(Trees::Tree)
|
||||||
TreeWhile.new(cond, code).as(Tree)
|
Trees::TreeWhile.new(cond, code).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return whilee
|
return whilee
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_return(expr)
|
private def create_return(expr)
|
||||||
returnn = type(TokenType::KwReturn).then(expr).then(char ';').transform do |arr|
|
returnn = type(Compiler::TokenType::KwReturn).then(expr).then(char ';').transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
value = arr[1].as(Tree)
|
value = arr[1].as(Trees::Tree)
|
||||||
TreeReturn.new(value).as(Tree)
|
Trees::TreeReturn.new(value).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return returnn
|
return returnn
|
||||||
end
|
end
|
||||||
|
@ -125,14 +126,14 @@ module Chalk
|
||||||
private def create_block(statement)
|
private def create_block(statement)
|
||||||
block = char('{').then(many(statement)).then(char '}').transform do |arr|
|
block = char('{').then(many(statement)).then(char '}').transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
params = arr[1..arr.size - 2].map &.as(Tree)
|
params = arr[1..arr.size - 2].map &.as(Trees::Tree)
|
||||||
TreeBlock.new(params).as(Tree)
|
Trees::TreeBlock.new(params).as(Trees::Tree)
|
||||||
end
|
end
|
||||||
return block
|
return block
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_statement_block
|
private def create_statement_block
|
||||||
statement_place = PlaceholderParser(Tree).new
|
statement_place = PlaceholderParser(Trees::Tree).new
|
||||||
expr = create_expr
|
expr = create_expr
|
||||||
block = create_block(statement_place)
|
block = create_block(statement_place)
|
||||||
iff = create_if(expr, block)
|
iff = create_if(expr, block)
|
||||||
|
@ -147,27 +148,28 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
private def create_func(block, type)
|
private def create_func(block, type)
|
||||||
func = type(TokenType::KwFun).then(type(TokenType::Id))
|
func = type(Compiler::TokenType::KwFun).then(type(Compiler::TokenType::Id))
|
||||||
.then(char '(').then(delimited(type(TokenType::Id), char ',')).then(char ')')
|
.then(char '(').then(delimited(type(Compiler::TokenType::Id), char ',')).then(char ')')
|
||||||
.then(char ':').then(type)
|
.then(char ':').then(type)
|
||||||
.then(block).transform do |arr|
|
.then(block).transform do |arr|
|
||||||
arr = arr.flatten
|
arr = arr.flatten
|
||||||
name = arr[1].as(Token).string
|
name = arr[1].as(Compiler::Token).string
|
||||||
params = arr[3..arr.size - 5].map &.as(Token).string
|
params = arr[3..arr.size - 5].map &.as(Compiler::Token).string
|
||||||
code = arr[arr.size - 1].as(Tree)
|
code = arr[arr.size - 1].as(Trees::Tree)
|
||||||
type = arr[arr.size - 2].as(Token).type
|
type = arr[arr.size - 2].as(Compiler::Token).type
|
||||||
TreeFunction.new(name, params, code)
|
Trees::TreeFunction.new(name, params, code)
|
||||||
end
|
end
|
||||||
return func
|
return func
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
_, block = create_statement_block
|
_, block = create_statement_block
|
||||||
@parser = many(create_func(block, create_type)).as(BasicParser(Array(TreeFunction)))
|
@parser = many(create_func(block, create_type)).as(BasicParser(Array(Trees::TreeFunction)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse?(tokens)
|
def parse?(tokens)
|
||||||
return @parser.parse?(tokens, 0).try &.[0]
|
return @parser.parse?(tokens, 0).try &.[0]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,13 +2,14 @@ require "./lexer.cr"
|
||||||
require "./parsers.cr"
|
require "./parsers.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module ParserCombinators
|
||||||
module ParserBuilder
|
module ParserBuilder
|
||||||
def type(type) : BasicParser(Token)
|
def type(type) : BasicParser(Compiler::Token)
|
||||||
return TypeParser.new(type).as(BasicParser(Token))
|
return TypeParser.new(type).as(BasicParser(Compiler::Token))
|
||||||
end
|
end
|
||||||
|
|
||||||
def char(type) : BasicParser(Token)
|
def char(type) : BasicParser(Compiler::Token)
|
||||||
return CharParser.new(type).as(BasicParser(Token))
|
return CharParser.new(type).as(BasicParser(Compiler::Token))
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform(parser : BasicParser(T), &transform : T -> R) forall T, R
|
def transform(parser : BasicParser(T), &transform : T -> R) forall T, R
|
||||||
|
@ -35,4 +36,5 @@ module Chalk
|
||||||
return NextParser.new(first, second).as(BasicParser(Array(T | R)))
|
return NextParser.new(first, second).as(BasicParser(Array(T | R)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module ParserCombinators
|
||||||
abstract class BasicParser(T)
|
abstract class BasicParser(T)
|
||||||
abstract def parse?(tokens : Array(Token),
|
abstract def parse?(tokens : Array(Compiler::Token),
|
||||||
index : Int64) : Tuple(T, Int64)?
|
index : Int64) : Tuple(T, Int64)?
|
||||||
|
|
||||||
def parse(tokens, index)
|
def parse(tokens, index)
|
||||||
|
@ -16,8 +17,8 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class TypeParser < BasicParser(Token)
|
class TypeParser < BasicParser(Compiler::Token)
|
||||||
def initialize(@type : TokenType)
|
def initialize(@type : Compiler::TokenType)
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse?(tokens, index)
|
def parse?(tokens, index)
|
||||||
|
@ -27,13 +28,13 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class CharParser < BasicParser(Token)
|
class CharParser < BasicParser(Compiler::Token)
|
||||||
def initialize(@char : Char)
|
def initialize(@char : Char)
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse?(tokens, index)
|
def parse?(tokens, index)
|
||||||
return nil unless index < tokens.size
|
return nil unless index < tokens.size
|
||||||
return nil unless (tokens[index].type == TokenType::Any) &&
|
return nil unless (tokens[index].type == Compiler::TokenType::Any) &&
|
||||||
tokens[index].string[0] == @char
|
tokens[index].string[0] == @char
|
||||||
return {tokens[index], index + 1}
|
return {tokens[index], index + 1}
|
||||||
end
|
end
|
||||||
|
@ -143,4 +144,5 @@ module Chalk
|
||||||
@parser.try &.parse?(tokens, index)
|
@parser.try &.parse?(tokens, index)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require "./tree.cr"
|
require "./tree.cr"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Trees
|
||||||
class PrintVisitor < Visitor
|
class PrintVisitor < Visitor
|
||||||
def initialize(@stream : IO)
|
def initialize(@stream : IO)
|
||||||
@indent = 0
|
@indent = 0
|
||||||
|
@ -73,4 +74,5 @@ module Chalk
|
||||||
accept(PrintVisitor.new io)
|
accept(PrintVisitor.new io)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Compiler
|
||||||
class Entry
|
class Entry
|
||||||
end
|
end
|
||||||
|
|
||||||
class FunctionEntry < Entry
|
class FunctionEntry < Entry
|
||||||
property function : TreeFunction | BuiltinFunction | InlineFunction
|
property function : Trees::TreeFunction | Builtin::BuiltinFunction | Builtin::InlineFunction
|
||||||
property addr : Int32
|
property addr : Int32
|
||||||
|
|
||||||
def initialize(@function, @addr = -1)
|
def initialize(@function, @addr = -1)
|
||||||
|
@ -48,4 +49,5 @@ module Chalk
|
||||||
io << @data.map { |k, v| k + ": " + v.to_s }.join("\n")
|
io << @data.map { |k, v| k + ": " + v.to_s }.join("\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
|
module Trees
|
||||||
class Visitor
|
class Visitor
|
||||||
def visit(tree)
|
def visit(tree)
|
||||||
end
|
end
|
||||||
|
@ -60,7 +61,7 @@ module Chalk
|
||||||
end
|
end
|
||||||
|
|
||||||
class TreeOp < Tree
|
class TreeOp < Tree
|
||||||
property op : TokenType
|
property op : Compiler::TokenType
|
||||||
property left : Tree
|
property left : Tree
|
||||||
property right : Tree
|
property right : Tree
|
||||||
|
|
||||||
|
@ -225,4 +226,5 @@ module Chalk
|
||||||
return t.transform(self)
|
return t.transform(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user