Run the format tool.

This commit is contained in:
Danila Fedorin 2018-07-25 13:53:35 -07:00
parent fa00bda8ab
commit df2a00fd66
7 changed files with 570 additions and 551 deletions

View File

@ -1,12 +1,12 @@
require "./chalk/*" require "./chalk/*"
module Chalk module Chalk
lexer = Lexer.new lexer = Lexer.new
parser = Parser.new parser = Parser.new
tokens = lexer.lex(File.read("test.txt")) tokens = lexer.lex(File.read("test.txt"))
trees = parser.parse?(tokens) trees = parser.parse?(tokens)
trees.try do |trees| trees.try do |trees|
trees.each &.accept(PrintVisitor.new) trees.each &.accept(PrintVisitor.new)
end end
end end

View File

@ -2,37 +2,37 @@ require "./lexer.cr"
require "./parsers.cr" require "./parsers.cr"
module Chalk module Chalk
module Builder module Builder
def type(type): BasicParser(Token) def type(type) : BasicParser(Token)
return TypeParser.new(type).as(BasicParser(Token)) return TypeParser.new(type).as(BasicParser(Token))
end
def char(type): BasicParser(Token)
return CharParser.new(type).as(BasicParser(Token))
end
def transform(parser : BasicParser(T), &transform : T -> R) forall T, R
return TransformParser.new(parser, &transform).as(BasicParser(R))
end
def optional(parser : BasicParser(T)): BasicParser(T?) forall T
return OptionalParser.new(parser).as(BasicParser(T?))
end
def either(*args : BasicParser(T)): BasicParser(T) forall T
return EitherParser.new(args.to_a).as(BasicParser(T))
end
def many(parser : BasicParser(T)): BasicParser(Array(T)) forall T
return ManyParser.new(parser).as(BasicParser(Array(T)))
end
def delimited(parser : BasicParser(T), delimiter : BasicParser(R)): BasicParser(Array(T)) forall T, R
return DelimitedParser.new(parser, delimiter).as(BasicParser(Array(T)))
end
def then(first : BasicParser(T), second : BasicParser(R)) forall T, R
return NextParser.new(first, second).as(BasicParser(Array(T | R)))
end
end end
def char(type) : BasicParser(Token)
return CharParser.new(type).as(BasicParser(Token))
end
def transform(parser : BasicParser(T), &transform : T -> R) forall T, R
return TransformParser.new(parser, &transform).as(BasicParser(R))
end
def optional(parser : BasicParser(T)) : BasicParser(T?) forall T
return OptionalParser.new(parser).as(BasicParser(T?))
end
def either(*args : BasicParser(T)) : BasicParser(T) forall T
return EitherParser.new(args.to_a).as(BasicParser(T))
end
def many(parser : BasicParser(T)) : BasicParser(Array(T)) forall T
return ManyParser.new(parser).as(BasicParser(Array(T)))
end
def delimited(parser : BasicParser(T), delimiter : BasicParser(R)) : BasicParser(Array(T)) forall T, R
return DelimitedParser.new(parser, delimiter).as(BasicParser(Array(T)))
end
def then(first : BasicParser(T), second : BasicParser(R)) forall T, R
return NextParser.new(first, second).as(BasicParser(Array(T | R)))
end
end
end end

View File

@ -1,82 +1,82 @@
require "lex" require "lex"
module Chalk module Chalk
enum TokenType enum TokenType
Any, Any,
Str, Str,
Id, Id,
LitDec, LitDec,
LitBin, LitBin,
LitHex, LitHex,
OpAdd OpAdd
OpSub OpSub
OpMul OpMul
OpDiv OpDiv
OpOr OpOr
OpAnd OpAnd
OpXor OpXor
KwSprite KwSprite
KwInline KwInline
KwFun KwFun
KwU0 KwU0
KwU8 KwU8
KwU12 KwU12
KwVar KwVar
KwIf KwIf
KwElse KwElse
KwWhile KwWhile
KwReturn KwReturn
end
class Token
def initialize(@string : String, @type : TokenType)
end end
class Token getter string : String
def initialize(@string : String, @type : TokenType) getter type : TokenType
end end
getter string : String class Lexer
getter type : TokenType def initialize
@lexer = Lex::Lexer.new
@lexer.add_pattern(".", TokenType::Any.value)
@lexer.add_pattern("\"(\\\\\"|[^\"])*\"",
TokenType::Str.value)
@lexer.add_pattern("[a-zA-Z_][a-zA-Z_0-9]*",
TokenType::Id.value)
@lexer.add_pattern("[0-9]+",
TokenType::LitDec.value)
@lexer.add_pattern("0b[0-1]+",
TokenType::LitBin.value)
@lexer.add_pattern("0x[0-9a-fA-F]+",
TokenType::LitHex.value)
@lexer.add_pattern("\\+", TokenType::OpAdd.value)
@lexer.add_pattern("-", TokenType::OpSub.value)
@lexer.add_pattern("\\*", TokenType::OpMul.value)
@lexer.add_pattern("/", TokenType::OpDiv.value)
@lexer.add_pattern("&", TokenType::OpAdd.value)
@lexer.add_pattern("\\|", TokenType::OpOr.value)
@lexer.add_pattern("^", TokenType::OpXor.value)
@lexer.add_pattern("sprite", TokenType::KwSprite.value)
@lexer.add_pattern("inline", TokenType::KwInline.value)
@lexer.add_pattern("fun", TokenType::KwFun.value)
@lexer.add_pattern("u0", TokenType::KwU0.value)
@lexer.add_pattern("u8", TokenType::KwU8.value)
@lexer.add_pattern("u12", TokenType::KwU12.value)
@lexer.add_pattern("var", TokenType::KwVar.value)
@lexer.add_pattern("if", TokenType::KwIf.value)
@lexer.add_pattern("else", TokenType::KwElse.value)
@lexer.add_pattern("while", TokenType::KwWhile.value)
@lexer.add_pattern("return", TokenType::KwReturn.value)
end end
class Lexer def lex(string)
def initialize return @lexer.lex(string)
@lexer = Lex::Lexer.new .select { |t| !t[0][0].whitespace? }
@lexer.add_pattern(".", TokenType::Any.value) .map do |tuple|
@lexer.add_pattern("\"(\\\\\"|[^\"])*\"", string, id = tuple
TokenType::Str.value) Token.new(string, TokenType.new(id))
@lexer.add_pattern("[a-zA-Z_][a-zA-Z_0-9]*",
TokenType::Id.value)
@lexer.add_pattern("[0-9]+",
TokenType::LitDec.value)
@lexer.add_pattern("0b[0-1]+",
TokenType::LitBin.value)
@lexer.add_pattern("0x[0-9a-fA-F]+",
TokenType::LitHex.value)
@lexer.add_pattern("\\+", TokenType::OpAdd.value)
@lexer.add_pattern("-", TokenType::OpSub.value)
@lexer.add_pattern("\\*", TokenType::OpMul.value)
@lexer.add_pattern("/", TokenType::OpDiv.value)
@lexer.add_pattern("&", TokenType::OpAdd.value)
@lexer.add_pattern("\\|", TokenType::OpOr.value)
@lexer.add_pattern("^", TokenType::OpXor.value)
@lexer.add_pattern("sprite", TokenType::KwSprite.value)
@lexer.add_pattern("inline", TokenType::KwInline.value)
@lexer.add_pattern("fun", TokenType::KwFun.value)
@lexer.add_pattern("u0", TokenType::KwU0.value)
@lexer.add_pattern("u8", TokenType::KwU8.value)
@lexer.add_pattern("u12", TokenType::KwU12.value)
@lexer.add_pattern("var", TokenType::KwVar.value)
@lexer.add_pattern("if", TokenType::KwIf.value)
@lexer.add_pattern("else", TokenType::KwElse.value)
@lexer.add_pattern("while", TokenType::KwWhile.value)
@lexer.add_pattern("return", TokenType::KwReturn.value)
end
def lex(string)
return @lexer.lex(string)
.select { |t| !t[0][0].whitespace? }
.map do |tuple|
string, id = tuple
Token.new(string, TokenType.new(id))
end
end end
end end
end
end end

View File

@ -1,173 +1,173 @@
require "./builder.cr" require "./builder.cr"
module Chalk module Chalk
class Parser class Parser
include Builder include Builder
private def create_type private def create_type
either(type(TokenType::KwU0), type(TokenType::KwU8), type(TokenType::KwU12)) either(type(TokenType::KwU0), type(TokenType::KwU8), type(TokenType::KwU12))
end
private def create_lit
dec_parser = type(TokenType::LitDec).transform &.string.to_i64
hex_parser = type(TokenType::LitHex).transform &.string.lchop("0x").to_i64(16)
bin_parser = type(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) }
return lit_parser
end
private def create_op_expr(atom, op)
pl = PlaceholderParser(Tree).new
recurse = atom.then(op).then(pl).transform do |arr|
arr = arr.flatten
TreeOp.new(
arr[1].as(Token).type,
arr[0].as(Tree),
arr[2].as(Tree)).as(Tree)
end
pl.parser = either(recurse, atom)
return pl
end
private def create_op_exprs(atom, ops)
ops.reduce(atom) do |previous, current|
create_op_expr(previous, current)
end
end
private def create_call(expr)
call = type(TokenType::Id).then(char '(').then(delimited(expr, char ',')).then(char ')').transform do |arr|
arr = arr.flatten
name = arr[0].as(Token).string
params = arr[2..arr.size - 2].map &.as(Tree)
TreeCall.new(name, params).as(Tree)
end
return call
end
private def create_expr
expr_place = PlaceholderParser(Tree).new
literal = create_lit
id = type(TokenType::Id).transform { |it| TreeId.new(it.string).as(Tree) }
call = create_call(expr_place)
atom = either(literal, call, id)
ops = [ either(type(TokenType::OpMul), type(TokenType::OpDiv)),
either(type(TokenType::OpAdd), type(TokenType::OpSub)),
type(TokenType::OpXor),
type(TokenType::OpAnd),
type(TokenType::OpOr) ]
expr = create_op_exprs(atom, ops)
expr_place.parser = expr
return expr
end
private def create_var(expr)
var = type(TokenType::KwVar).then(type(TokenType::Id)).then(char '=').then(expr).then(char ';').transform do |arr|
arr = arr.flatten
name = arr[1].as(Token).string
exp = arr[arr.size - 2].as(Tree)
TreeVar.new(name, exp).as(Tree)
end
return var
end
private def create_assign(expr)
assign = type(TokenType::Id).then(char '=').then(expr).then(char ';').transform do |arr|
arr = arr.flatten
name = arr[0].as(Token).string
exp = arr[arr.size - 2].as(Tree)
TreeAssign.new(name, exp).as(Tree)
end
return assign
end
private def create_basic(expr)
basic = expr.then(char ';').transform do |arr|
arr.flatten[0].as(Tree)
end
return basic
end
private def create_if(expr, block)
iff = type(TokenType::KwIf).then(char '(').then(expr).then(char ')').then(block)
.then(optional(type(TokenType::KwElse).then(block)))
.transform do |arr|
arr = arr.flatten
cond = arr[2].as(Tree)
code = arr[4].as(Tree)
otherwise = arr.size == 7 ? arr[6].as(Tree) : nil
TreeIf.new(cond, code, otherwise).as(Tree)
end
return iff
end
private def create_while(expr, block)
whilee = type(TokenType::KwWhile).then(char '(').then(expr).then(char ')').then(block).transform do |arr|
arr = arr.flatten
cond = arr[2].as(Tree)
code = arr[4].as(Tree)
TreeWhile.new(cond, code).as(Tree)
end
return whilee
end
private def create_return(expr)
returnn = type(TokenType::KwReturn).then(expr).then(char ';').transform do |arr|
arr = arr.flatten
value = arr[1].as(Tree)
TreeReturn.new(value).as(Tree)
end
return returnn
end
private def create_block(statement)
block = char('{').then(many(statement)).then(char '}').transform do |arr|
arr = arr.flatten
params = arr[1..arr.size - 2].map &.as(Tree)
TreeBlock.new(params).as(Tree)
end
return block
end
private def create_statement_block
statement_place = PlaceholderParser(Tree).new
expr = create_expr
block = create_block(statement_place)
iff = create_if(expr, block)
whilee = create_while(expr, block)
returnn = create_return(expr)
var = create_var(expr)
assign = create_assign(expr)
basic = create_basic(expr)
statement = either(basic, var, assign, block, iff, whilee, returnn)
statement_place.parser = statement
return {statement, block}
end
private def create_func(block, type)
func = type(TokenType::KwFun).then(type(TokenType::Id))
.then(char '(').then(delimited(type(TokenType::Id), char ',')).then(char ')')
.then(char ':').then(type)
.then(block).transform do |arr|
arr = arr.flatten
name = arr[1].as(Token).string
params = arr[3..arr.size - 5].map &.as(Token).string
code = arr[arr.size - 1].as(Tree)
type = arr[arr.size - 2].as(Token).type
TreeFunction.new(name, params, code).as(Tree)
end
return func
end
def initialize
_, block = create_statement_block
@parser = many(create_func(block, create_type)).as(BasicParser(Array(Tree)))
end
def parse?(tokens)
return @parser.parse?(tokens, 0).try &.[0]
end
end end
private def create_lit
dec_parser = type(TokenType::LitDec).transform &.string.to_i64
hex_parser = type(TokenType::LitHex).transform &.string.lchop("0x").to_i64(16)
bin_parser = type(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) }
return lit_parser
end
private def create_op_expr(atom, op)
pl = PlaceholderParser(Tree).new
recurse = atom.then(op).then(pl).transform do |arr|
arr = arr.flatten
TreeOp.new(
arr[1].as(Token).type,
arr[0].as(Tree),
arr[2].as(Tree)).as(Tree)
end
pl.parser = either(recurse, atom)
return pl
end
private def create_op_exprs(atom, ops)
ops.reduce(atom) do |previous, current|
create_op_expr(previous, current)
end
end
private def create_call(expr)
call = type(TokenType::Id).then(char '(').then(delimited(expr, char ',')).then(char ')').transform do |arr|
arr = arr.flatten
name = arr[0].as(Token).string
params = arr[2..arr.size - 2].map &.as(Tree)
TreeCall.new(name, params).as(Tree)
end
return call
end
private def create_expr
expr_place = PlaceholderParser(Tree).new
literal = create_lit
id = type(TokenType::Id).transform { |it| TreeId.new(it.string).as(Tree) }
call = create_call(expr_place)
atom = either(literal, call, id)
ops = [either(type(TokenType::OpMul), type(TokenType::OpDiv)),
either(type(TokenType::OpAdd), type(TokenType::OpSub)),
type(TokenType::OpXor),
type(TokenType::OpAnd),
type(TokenType::OpOr)]
expr = create_op_exprs(atom, ops)
expr_place.parser = expr
return expr
end
private def create_var(expr)
var = type(TokenType::KwVar).then(type(TokenType::Id)).then(char '=').then(expr).then(char ';').transform do |arr|
arr = arr.flatten
name = arr[1].as(Token).string
exp = arr[arr.size - 2].as(Tree)
TreeVar.new(name, exp).as(Tree)
end
return var
end
private def create_assign(expr)
assign = type(TokenType::Id).then(char '=').then(expr).then(char ';').transform do |arr|
arr = arr.flatten
name = arr[0].as(Token).string
exp = arr[arr.size - 2].as(Tree)
TreeAssign.new(name, exp).as(Tree)
end
return assign
end
private def create_basic(expr)
basic = expr.then(char ';').transform do |arr|
arr.flatten[0].as(Tree)
end
return basic
end
private def create_if(expr, block)
iff = type(TokenType::KwIf).then(char '(').then(expr).then(char ')').then(block)
.then(optional(type(TokenType::KwElse).then(block)))
.transform do |arr|
arr = arr.flatten
cond = arr[2].as(Tree)
code = arr[4].as(Tree)
otherwise = arr.size == 7 ? arr[6].as(Tree) : nil
TreeIf.new(cond, code, otherwise).as(Tree)
end
return iff
end
private def create_while(expr, block)
whilee = type(TokenType::KwWhile).then(char '(').then(expr).then(char ')').then(block).transform do |arr|
arr = arr.flatten
cond = arr[2].as(Tree)
code = arr[4].as(Tree)
TreeWhile.new(cond, code).as(Tree)
end
return whilee
end
private def create_return(expr)
returnn = type(TokenType::KwReturn).then(expr).then(char ';').transform do |arr|
arr = arr.flatten
value = arr[1].as(Tree)
TreeReturn.new(value).as(Tree)
end
return returnn
end
private def create_block(statement)
block = char('{').then(many(statement)).then(char '}').transform do |arr|
arr = arr.flatten
params = arr[1..arr.size - 2].map &.as(Tree)
TreeBlock.new(params).as(Tree)
end
return block
end
private def create_statement_block
statement_place = PlaceholderParser(Tree).new
expr = create_expr
block = create_block(statement_place)
iff = create_if(expr, block)
whilee = create_while(expr, block)
returnn = create_return(expr)
var = create_var(expr)
assign = create_assign(expr)
basic = create_basic(expr)
statement = either(basic, var, assign, block, iff, whilee, returnn)
statement_place.parser = statement
return {statement, block}
end
private def create_func(block, type)
func = type(TokenType::KwFun).then(type(TokenType::Id))
.then(char '(').then(delimited(type(TokenType::Id), char ',')).then(char ')')
.then(char ':').then(type)
.then(block).transform do |arr|
arr = arr.flatten
name = arr[1].as(Token).string
params = arr[3..arr.size - 5].map &.as(Token).string
code = arr[arr.size - 1].as(Tree)
type = arr[arr.size - 2].as(Token).type
TreeFunction.new(name, params, code).as(Tree)
end
return func
end
def initialize
_, block = create_statement_block
@parser = many(create_func(block, create_type)).as(BasicParser(Array(Tree)))
end
def parse?(tokens)
return @parser.parse?(tokens, 0).try &.[0]
end
end
end end

View File

@ -1,151 +1,149 @@
require "./builder.cr" require "./builder.cr"
module Chalk module Chalk
abstract class BasicParser(T)
abstract def parse?(tokens : Array(Token),
index : Int64) : Tuple(T, Int64)?
abstract class BasicParser(T) def parse(tokens : Array(Token),
abstract def parse?(tokens : Array(Token), index : Int64) : Tuple(T, Int64)
index : Int64): Tuple(T, Int64)? return parse?(tokens, index).not_nil!
def parse(tokens : Array(Token),
index : Int64): Tuple(T, Int64)
return parse?(tokens, index).not_nil!
end
def transform(&transform : T -> R) forall R
return TransformParser.new(self, &transform).as(BasicParser(R))
end
def then(other : BasicParser(R)): BasicParser(Array(T | R)) forall R
return NextParser
.new(self, other)
.as(BasicParser(Array(T | R)))
end
end end
class TypeParser < BasicParser(Token) def transform(&transform : T -> R) forall R
def initialize(@type : TokenType) return TransformParser.new(self, &transform).as(BasicParser(R))
end
def parse?(tokens, index)
return nil unless index < tokens.size
return nil unless tokens[index].type == @type
return { tokens[index], index + 1}
end
end end
class CharParser < BasicParser(Token) def then(other : BasicParser(R)) : BasicParser(Array(T | R)) forall R
def initialize(@char : Char) return NextParser.new(self, other).as(BasicParser(Array(T | R)))
end end
end
def parse?(tokens, index) class TypeParser < BasicParser(Token)
return nil unless index < tokens.size def initialize(@type : TokenType)
return nil unless (tokens[index].type == TokenType::Any) &&
tokens[index].string[0] == @char
return { tokens[index], index + 1}
end
end end
class TransformParser(T, R) < BasicParser(R) def parse?(tokens, index)
def initialize(@parser : BasicParser(T), &@block : T -> R) return nil unless index < tokens.size
end return nil unless tokens[index].type == @type
return {tokens[index], index + 1}
end
end
def parse?(tokens, index) class CharParser < BasicParser(Token)
if parsed = @parser.parse?(tokens, index) def initialize(@char : Char)
return { @block.call(parsed[0]), parsed[1] }
end
return nil
end
end end
class OptionalParser(T) < BasicParser(T?) def parse?(tokens, index)
def initialize(@parser : BasicParser(T)) return nil unless index < tokens.size
end return nil unless (tokens[index].type == TokenType::Any) &&
tokens[index].string[0] == @char
return {tokens[index], index + 1}
end
end
def parse?(tokens, index) class TransformParser(T, R) < BasicParser(R)
if parsed = @parser.parse?(tokens, index) def initialize(@parser : BasicParser(T), &@block : T -> R)
return { parsed[0], parsed[1] }
end
return { nil, index }
end
end end
class EitherParser(T) < BasicParser(T) def parse?(tokens, index)
def initialize(@parsers : Array(BasicParser(T))) if parsed = @parser.parse?(tokens, index)
end return {@block.call(parsed[0]), parsed[1]}
end
return nil
end
end
def parse?(tokens, index) class OptionalParser(T) < BasicParser(T?)
@parsers.each do |parser| def initialize(@parser : BasicParser(T))
if parsed = parser.parse?(tokens, index)
return parsed
end
end
return nil
end
end end
class ManyParser(T) < BasicParser(Array(T)) def parse?(tokens, index)
def initialize(@parser : BasicParser(T)) if parsed = @parser.parse?(tokens, index)
end return {parsed[0], parsed[1]}
end
return {nil, index}
end
end
def parse?(tokens, index) class EitherParser(T) < BasicParser(T)
many = [] of T def initialize(@parsers : Array(BasicParser(T)))
while parsed = @parser.parse?(tokens, index)
item, index = parsed
many << item
end
return { many, index }
end
end end
class DelimitedParser(T, R) < BasicParser(Array(T)) def parse?(tokens, index)
def initialize(@parser : BasicParser(T), @delimiter : BasicParser(R)) @parsers.each do |parser|
if parsed = parser.parse?(tokens, index)
return parsed
end end
end
return nil
end
end
def parse?(tokens, index) class ManyParser(T) < BasicParser(Array(T))
array = [] of T def initialize(@parser : BasicParser(T))
first = @parser.parse?(tokens, index)
return { array, index } unless first
first_value, index = first
array << first_value
while delimiter = @delimiter.parse?(tokens, index)
_, new_index = delimiter
new = @parser.parse?(tokens, new_index)
break unless new
new_value, index = new
array << new_value
end
return { array, index }
end
end end
class NextParser(T, R) < BasicParser(Array(T | R)) def parse?(tokens, index)
def initialize(@first : BasicParser(T), @second : BasicParser(R)) many = [] of T
end while parsed = @parser.parse?(tokens, index)
item, index = parsed
many << item
end
return {many, index}
end
end
def parse?(tokens, index) class DelimitedParser(T, R) < BasicParser(Array(T))
first = @first.parse?(tokens, index) def initialize(@parser : BasicParser(T), @delimiter : BasicParser(R))
return nil unless first
first_value, index = first
second = @second.parse?(tokens, index)
return nil unless second
second_value, index = second
array = Array(T | R).new
array << first_value << second_value
return { array, index }
end
end end
class PlaceholderParser(T) < BasicParser(T) def parse?(tokens, index)
property parser : BasicParser(T)? array = [] of T
first = @parser.parse?(tokens, index)
return {array, index} unless first
first_value, index = first
array << first_value
while delimiter = @delimiter.parse?(tokens, index)
_, new_index = delimiter
new = @parser.parse?(tokens, new_index)
break unless new
new_value, index = new
array << new_value
end
def initialize return {array, index}
@parser = nil
end
def parse?(tokens, index)
@parser.try &.parse?(tokens, index)
end
end end
end
class NextParser(T, R) < BasicParser(Array(T | R))
def initialize(@first : BasicParser(T), @second : BasicParser(R))
end
def parse?(tokens, index)
first = @first.parse?(tokens, index)
return nil unless first
first_value, index = first
second = @second.parse?(tokens, index)
return nil unless second
second_value, index = second
array = Array(T | R).new
array << first_value << second_value
return {array, index}
end
end
class PlaceholderParser(T) < BasicParser(T)
property parser : BasicParser(T)?
def initialize
@parser = nil
end
def parse?(tokens, index)
@parser.try &.parse?(tokens, index)
end
end
end end

View File

@ -1,53 +1,53 @@
require "./tree.cr" require "./tree.cr"
module Chalk module Chalk
class PrintVisitor < Visitor class PrintVisitor < Visitor
def initialize def initialize
@indent = 0 @indent = 0
end end
def print_indent def print_indent
@indent.times do @indent.times do
STDOUT << " " STDOUT << " "
end end
end end
def visit(id : TreeId) def visit(id : TreeId)
print_indent print_indent
puts id.id puts id.id
end end
def visit(lit : TreeLit) def visit(lit : TreeLit)
print_indent print_indent
puts lit.lit puts lit.lit
end end
def visit(op : TreeOp) def visit(op : TreeOp)
print_indent print_indent
STDOUT << "[op] " STDOUT << "[op] "
puts op.op puts op.op
@indent += 1 @indent += 1
end end
def finish(op : TreeOp) def finish(op : TreeOp)
@indent -= 1 @indent -= 1
end end
def visit(function : TreeFunction) def visit(function : TreeFunction)
print_indent print_indent
STDOUT << "[function] " << function.name << "( " STDOUT << "[function] " << function.name << "( "
function.params.each do |param| function.params.each do |param|
STDOUT << param << " " STDOUT << param << " "
end end
puts ")" puts ")"
@indent += 1 @indent += 1
end end
def finish(function : TreeFunction) def finish(function : TreeFunction)
@indent -= 1 @indent -= 1
end end
macro forward(text, type) macro forward(text, type)
def visit(tree : {{type}}) def visit(tree : {{type}})
print_indent print_indent
puts {{text}} puts {{text}}
@ -59,12 +59,12 @@ module Chalk
end end
end end
forward("[call]", TreeCall) forward("[call]", TreeCall)
forward("[block]", TreeBlock) forward("[block]", TreeBlock)
forward("[var]", TreeVar) forward("[var]", TreeVar)
forward("[assign]", TreeAssign) forward("[assign]", TreeAssign)
forward("[if]", TreeIf) forward("[if]", TreeIf)
forward("[while]", TreeWhile) forward("[while]", TreeWhile)
forward("[return]", TreeReturn) forward("[return]", TreeReturn)
end end
end end

View File

@ -1,138 +1,159 @@
module Chalk module Chalk
class Visitor class Visitor
def visit(tree : Tree) def visit(tree : Tree)
end
def finish(tree : Tree)
end
end end
class Tree def finish(tree : Tree)
def accept(v : Visitor) end
v.visit(self) end
v.finish(self)
end class Tree
def accept(v : Visitor)
v.visit(self)
v.finish(self)
end
end
class TreeId < Tree
property id : String
def initialize(@id : String)
end
end
class TreeLit < Tree
property lit : Int64
def initialize(@lit : Int64)
end
end
class TreeCall < Tree
property name : String
property params : Array(Tree)
def initialize(@name : String, @params : Array(Tree))
end end
class TreeId < Tree def accept(v : Visitor)
property id : String v.visit(self)
def initialize(@id : String) end @params.each &.accept(v)
v.finish(self)
end
end
class TreeOp < Tree
property op : TokenType
property left : Tree
property right : Tree
def initialize(@op : TokenType, @left : Tree, @right : Tree)
end end
class TreeLit < Tree def accept(v : Visitor)
property lit : Int64 v.visit(self)
def initialize(@lit : Int64) end @left.accept(v)
@right.accept(v)
v.finish(self)
end
end
class TreeBlock < Tree
def initialize(@children : Array(Tree))
end end
class TreeCall < Tree def accept(v : Visitor)
property name : String v.visit(self)
property params : Array(Tree) @children.each &.accept(v)
v.finish(self)
end
end
def initialize(@name : String, @params : Array(Tree)) end class TreeFunction < Tree
def accept(v : Visitor) property name : String
v.visit(self) property params : Array(String)
@params.each &.accept(v) property block : Tree
v.finish(self)
end def initialize(@name : String, @params : Array(String), @block : Tree)
end end
class TreeOp < Tree def accept(v : Visitor)
property op : TokenType v.visit(self)
property left : Tree @block.accept(v)
property right : Tree v.finish(self)
def initialize(@op : TokenType, @left : Tree, @right : Tree) end end
end
def accept(v : Visitor) class TreeVar < Tree
v.visit(self) property name : String
@left.accept(v) property expr : Tree
@right.accept(v)
v.finish(self) def initialize(@name : String, @expr : Tree)
end
end end
class TreeBlock < Tree def accept(v : Visitor)
def initialize(@children : Array(Tree)) end v.visit(self)
@expr.accept(v)
v.finish(self)
end
end
def accept(v : Visitor) class TreeAssign < Tree
v.visit(self) property name : String
@children.each &.accept(v) property expr : Tree
v.finish(self)
end def initialize(@name : String, @expr : Tree)
end end
class TreeFunction < Tree def accept(v : Visitor)
property name : String v.visit(self)
property params : Array(String) @expr.accept(v)
property block : Tree v.finish(self)
end
end
def initialize(@name : String, @params : Array(String), @block : Tree) end class TreeIf < Tree
def accept(v : Visitor) property condition : Tree
v.visit(self) property block : Tree
@block.accept(v) property otherwise : Tree?
v.finish(self)
end def initialize(@condition : Tree, @block : Tree, @otherwise : Tree? = nil)
end end
class TreeVar < Tree def accept(v : Visitor)
property name : String v.visit(self)
property expr : Tree @condition.accept(v)
@block.accept(v)
@otherwise.try &.accept(v)
v.finish(self)
end
end
def initialize(@name : String, @expr : Tree) end class TreeWhile < Tree
def accept(v : Visitor) property condition : Tree
v.visit(self) property block : Tree
@expr.accept(v)
v.finish(self) def initialize(@condition : Tree, @block : Tree)
end
end end
class TreeAssign < Tree def accept(v : Visitor)
property name : String v.visit(self)
property expr : Tree @condition.accept(v)
@block.accept(v)
v.finish(self)
end
end
def initialize(@name : String, @expr : Tree) end class TreeReturn < Tree
def accept(v : Visitor) property rvalue : Tree
v.visit(self)
@expr.accept(v) def initialize(@rvalue : Tree)
v.finish(self)
end
end end
class TreeIf < Tree def accept(v : Visitor)
property condition : Tree v.visit(self)
property block : Tree @rvalue.accept(v)
property otherwise : Tree? v.finish(self)
def initialize(@condition : Tree, @block : Tree, @otherwise : Tree? = nil) end
def accept(v : Visitor)
v.visit(self)
@condition.accept(v)
@block.accept(v)
@otherwise.try &.accept(v)
v.finish(self)
end
end
class TreeWhile < Tree
property condition : Tree
property block : Tree
def initialize(@condition : Tree, @block : Tree) end
def accept(v : Visitor)
v.visit(self)
@condition.accept(v)
@block.accept(v)
v.finish(self)
end
end
class TreeReturn < Tree
property rvalue : Tree
def initialize(@rvalue : Tree) end
def accept(v : Visitor)
v.visit(self)
@rvalue.accept(v)
v.finish(self)
end
end end
end
end end